From dbf5a9a4006020ddebcce89692ce8826b6b2db46 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 21 Jun 2024 13:43:03 +0000 Subject: [PATCH 001/288] 8334706: [JVMCI] APX registers incorrectly exposed on AMD64 Reviewed-by: yzheng, never --- .../share/classes/jdk/vm/ci/amd64/AMD64.java | 9 ++++----- .../share/classes/jdk/vm/ci/code/Architecture.java | 8 ++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java index 9f3fc0cdbd6a9..83401fed62033 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java @@ -83,11 +83,10 @@ public class AMD64 extends Architecture { public static final Register r30 = new Register(30, 30, "r30", CPU); public static final Register r31 = new Register(31, 31, "r31", CPU); + // The set of common CPU registers available on all x64 platforms. public static final Register[] cpuRegisters = { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, - r8, r9, r10, r11, r12, r13, r14, r15, - r16, r17, r18, r19, r20, r21, r22, r23, - r24, r25, r26, r27, r28, r29, r30, r31 + r8, r9, r10, r11, r12, r13, r14, r15 }; public static final RegisterCategory XMM = new RegisterCategory("XMM"); @@ -162,8 +161,6 @@ public class AMD64 extends Architecture { public static final RegisterArray valueRegistersAVX512 = new RegisterArray( rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, - r16, r17, r18, r19, r20, r21, r22, r23, - r24, r25, r26, r27, r28, r29, r30, r31, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23, @@ -179,6 +176,8 @@ public class AMD64 extends Architecture { public static final RegisterArray allRegisters = new RegisterArray( rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java index 0b00628aceaf3..f14855cd6b995 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java @@ -26,6 +26,7 @@ import java.util.Set; import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.PlatformKind; @@ -81,6 +82,13 @@ public abstract class Architecture { protected Architecture(String name, PlatformKind wordKind, ByteOrder byteOrder, boolean unalignedMemoryAccess, RegisterArray registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, int returnAddressSize) { + // registers is expected to mention all registers in order of their encoding. + for (int i = 0; i < registers.size(); ++i) { + if (registers.get(i).number != i) { + Register reg = registers.get(i); + throw new JVMCIError("%s: %d != %d", reg, reg.number, i); + } + } this.name = name; this.registers = registers; this.wordKind = wordKind; From 9f8de221d7f0186718411ab3f5217e3883237e84 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 21 Jun 2024 13:51:06 +0000 Subject: [PATCH 002/288] 8327793: Deprecate jstatd for removal Reviewed-by: alanb, cjplummer --- src/jdk.jstatd/share/classes/module-info.java | 3 ++- src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java | 4 +++- test/jdk/sun/tools/jstatd/JstatdTest.java | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/jdk.jstatd/share/classes/module-info.java b/src/jdk.jstatd/share/classes/module-info.java index ade59da4248cd..e9a9521ac73fc 100644 --- a/src/jdk.jstatd/share/classes/module-info.java +++ b/src/jdk.jstatd/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ * @moduleGraph * @since 9 */ +@Deprecated(since="24", forRemoval=true) module jdk.jstatd { requires java.rmi; requires jdk.internal.jvmstat; diff --git a/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java b/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java index 5dc7f1fa2fbce..cfd1212a67aba 100644 --- a/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java +++ b/src/jdk.jstatd/share/classes/sun/tools/jstatd/Jstatd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,8 @@ public static void main(String[] args) { int rmiPort = 0; int argc = 0; + System.err.println("WARNING: jstatd is deprecated and will be removed in a future release."); + for ( ; (argc < args.length) && (args[argc].startsWith("-")); argc++) { String arg = args[argc]; diff --git a/test/jdk/sun/tools/jstatd/JstatdTest.java b/test/jdk/sun/tools/jstatd/JstatdTest.java index b2ac3804f6805..5041bc40d7510 100644 --- a/test/jdk/sun/tools/jstatd/JstatdTest.java +++ b/test/jdk/sun/tools/jstatd/JstatdTest.java @@ -356,7 +356,7 @@ private void runTest(boolean useShortSyntax) throws Throwable { OutputAnalyzer output = jstatdThread.getOutput(); List stdout = output.asLinesWithoutVMWarnings(); output.reportDiagnosticSummary(); - assertEquals(stdout.size(), 1, "Output should contain one line"); + assertEquals(stdout.size(), 2, "Output should contain two lines"); // includes deprecation warning assertTrue(stdout.get(0).startsWith("jstatd started"), "List should start with 'jstatd started'"); assertNotEquals(output.getExitValue(), 0, "jstatd process exited with unexpected exit code"); From 75bea280b9adb6dac9fefafbb3f4b212f100fbb5 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Fri, 21 Jun 2024 14:16:23 +0000 Subject: [PATCH 003/288] 8333867: SHA3 performance can be improved Reviewed-by: kvn, valeriep --- src/hotspot/share/opto/library_call.cpp | 4 +- .../sun/security/provider/DigestBase.java | 4 +- .../classes/sun/security/provider/SHA3.java | 105 ++++++++---------- 3 files changed, 51 insertions(+), 62 deletions(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index b3253a817a408..596e637652dfb 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -7681,7 +7681,7 @@ bool LibraryCallKit::inline_digestBase_implCompress(vmIntrinsics::ID id) { break; case vmIntrinsics::_sha3_implCompress: assert(UseSHA3Intrinsics, "need SHA3 instruction support"); - state = get_state_from_digest_object(digestBase_obj, T_BYTE); + state = get_state_from_digest_object(digestBase_obj, T_LONG); stubAddr = StubRoutines::sha3_implCompress(); stubName = "sha3_implCompress"; block_size = get_block_size_from_digest_object(digestBase_obj); @@ -7781,7 +7781,7 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(int predicate) { klass_digestBase_name = "sun/security/provider/SHA3"; stub_name = "sha3_implCompressMB"; stub_addr = StubRoutines::sha3_implCompressMB(); - elem_type = T_BYTE; + elem_type = T_LONG; } break; default: diff --git a/src/java.base/share/classes/sun/security/provider/DigestBase.java b/src/java.base/share/classes/sun/security/provider/DigestBase.java index dbe59396ac0b6..2aaf0a2fac6fd 100644 --- a/src/java.base/share/classes/sun/security/provider/DigestBase.java +++ b/src/java.base/share/classes/sun/security/provider/DigestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable { private final int digestLength; // size of the input to the compression function in bytes - private final int blockSize; + protected final int blockSize; // buffer to store partial blocks, blockSize bytes large // Subclasses should not access this array directly except possibly in their // implDigest() method. See MD5.java as an example. diff --git a/src/java.base/share/classes/sun/security/provider/SHA3.java b/src/java.base/share/classes/sun/security/provider/SHA3.java index 2b8bf8afbedaf..eaccf2a88e922 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA3.java +++ b/src/java.base/share/classes/sun/security/provider/SHA3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,14 @@ package sun.security.provider; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; import java.security.ProviderException; import java.util.Arrays; import java.util.Objects; import jdk.internal.vm.annotation.IntrinsicCandidate; -import static sun.security.provider.ByteArrayAccess.b2lLittle; -import static sun.security.provider.ByteArrayAccess.l2bLittle; /** * This class implements the Secure Hash Algorithm SHA-3 developed by @@ -48,7 +49,7 @@ abstract class SHA3 extends DigestBase { private static final int WIDTH = 200; // in bytes, e.g. 1600 bits - private static final int DM = 5; // dimension of lanes + private static final int DM = 5; // dimension of state matrix private static final int NR = 24; // number of rounds @@ -65,8 +66,11 @@ abstract class SHA3 extends DigestBase { }; private final byte suffix; - private byte[] state = new byte[WIDTH]; - private long[] lanes = new long[DM*DM]; + private long[] state = new long[DM*DM]; + + static final VarHandle asLittleEndian + = MethodHandles.byteArrayViewVarHandle(long[].class, + ByteOrder.LITTLE_ENDIAN).withInvokeExactBehavior(); /** * Creates a new SHA-3 object. @@ -91,10 +95,12 @@ void implCompress(byte[] b, int ofs) { @IntrinsicCandidate private void implCompress0(byte[] b, int ofs) { - for (int i = 0; i < buffer.length; i++) { - state[i] ^= b[ofs++]; - } - keccak(); + for (int i = 0; i < blockSize / 8; i++) { + state[i] ^= (long) asLittleEndian.get(b, ofs); + ofs += 8; + } + + keccak(); } /** @@ -102,29 +108,43 @@ private void implCompress0(byte[] b, int ofs) { * DigestBase calls implReset() when necessary. */ void implDigest(byte[] out, int ofs) { + byte[] byteState = new byte[8]; int numOfPadding = - setPaddingBytes(suffix, buffer, (int)(bytesProcessed % buffer.length)); + setPaddingBytes(suffix, buffer, (int)(bytesProcessed % blockSize)); if (numOfPadding < 1) { throw new ProviderException("Incorrect pad size: " + numOfPadding); } implCompress(buffer, 0); - int availableBytes = buffer.length; + int availableBytes = blockSize; // i.e. buffer.length int numBytes = engineGetDigestLength(); while (numBytes > availableBytes) { - System.arraycopy(state, 0, out, ofs, availableBytes); + for (int i = 0; i < availableBytes / 8 ; i++) { + asLittleEndian.set(out, ofs, state[i]); + ofs += 8; + } numBytes -= availableBytes; - ofs += availableBytes; keccak(); } - System.arraycopy(state, 0, out, ofs, numBytes); + int numLongs = (numBytes + 7) / 8; + + for (int i = 0; i < numLongs - 1; i++) { + asLittleEndian.set(out, ofs, state[i]); + ofs += 8; + } + if (numBytes == numLongs * 8) { + asLittleEndian.set(out, ofs, state[numLongs - 1]); + } else { + asLittleEndian.set(byteState, 0, state[numLongs - 1]); + System.arraycopy(byteState, 0, + out, ofs, numBytes - (numLongs - 1) * 8); + } } /** * Resets the internal state to start a new hash. */ void implReset() { - Arrays.fill(state, (byte)0); - Arrays.fill(lanes, 0L); + Arrays.fill(state, 0L); } /** @@ -144,46 +164,19 @@ private static int setPaddingBytes(byte suffix, byte[] in, int len) { return (in.length - len); } - /** - * Utility function for transforming the specified byte array 's' - * into array of lanes 'm' as defined in section 3.1.2. - */ - private static void bytes2Lanes(byte[] s, long[] m) { - int sOfs = 0; - // Conversion traverses along x-axis before y-axis - for (int y = 0; y < DM; y++, sOfs += 40) { - b2lLittle(s, sOfs, m, DM*y, 40); - } - } - - /** - * Utility function for transforming the specified array of - * lanes 'm' into a byte array 's' as defined in section 3.1.3. - */ - private static void lanes2Bytes(long[] m, byte[] s) { - int sOfs = 0; - // Conversion traverses along x-axis before y-axis - for (int y = 0; y < DM; y++, sOfs += 40) { - l2bLittle(m, DM*y, s, sOfs, 40); - } - } - /** * The function Keccak as defined in section 5.2 with * rate r = 1600 and capacity c. */ private void keccak() { - // convert the 200-byte state into 25 lanes - bytes2Lanes(state, lanes); - long a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; long a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24; // move data into local variables - a0 = lanes[0]; a1 = lanes[1]; a2 = lanes[2]; a3 = lanes[3]; a4 = lanes[4]; - a5 = lanes[5]; a6 = lanes[6]; a7 = lanes[7]; a8 = lanes[8]; a9 = lanes[9]; - a10 = lanes[10]; a11 = lanes[11]; a12 = lanes[12]; a13 = lanes[13]; a14 = lanes[14]; - a15 = lanes[15]; a16 = lanes[16]; a17 = lanes[17]; a18 = lanes[18]; a19 = lanes[19]; - a20 = lanes[20]; a21 = lanes[21]; a22 = lanes[22]; a23 = lanes[23]; a24 = lanes[24]; + a0 = state[0]; a1 = state[1]; a2 = state[2]; a3 = state[3]; a4 = state[4]; + a5 = state[5]; a6 = state[6]; a7 = state[7]; a8 = state[8]; a9 = state[9]; + a10 = state[10]; a11 = state[11]; a12 = state[12]; a13 = state[13]; a14 = state[14]; + a15 = state[15]; a16 = state[16]; a17 = state[17]; a18 = state[18]; a19 = state[19]; + a20 = state[20]; a21 = state[21]; a22 = state[22]; a23 = state[23]; a24 = state[24]; // process the lanes through step mappings for (int ir = 0; ir < NR; ir++) { @@ -287,20 +280,16 @@ private void keccak() { a0 ^= RC_CONSTANTS[ir]; } - lanes[0] = a0; lanes[1] = a1; lanes[2] = a2; lanes[3] = a3; lanes[4] = a4; - lanes[5] = a5; lanes[6] = a6; lanes[7] = a7; lanes[8] = a8; lanes[9] = a9; - lanes[10] = a10; lanes[11] = a11; lanes[12] = a12; lanes[13] = a13; lanes[14] = a14; - lanes[15] = a15; lanes[16] = a16; lanes[17] = a17; lanes[18] = a18; lanes[19] = a19; - lanes[20] = a20; lanes[21] = a21; lanes[22] = a22; lanes[23] = a23; lanes[24] = a24; - - // convert the resulting 25 lanes back into 200-byte state - lanes2Bytes(lanes, state); + state[0] = a0; state[1] = a1; state[2] = a2; state[3] = a3; state[4] = a4; + state[5] = a5; state[6] = a6; state[7] = a7; state[8] = a8; state[9] = a9; + state[10] = a10; state[11] = a11; state[12] = a12; state[13] = a13; state[14] = a14; + state[15] = a15; state[16] = a16; state[17] = a17; state[18] = a18; state[19] = a19; + state[20] = a20; state[21] = a21; state[22] = a22; state[23] = a23; state[24] = a24; } public Object clone() throws CloneNotSupportedException { SHA3 copy = (SHA3) super.clone(); copy.state = copy.state.clone(); - copy.lanes = new long[DM*DM]; return copy; } From c41293a70834a79c79e859ebcdb8869884ac87dc Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Fri, 21 Jun 2024 14:23:38 +0000 Subject: [PATCH 004/288] 8334695: Fix build failure without zgc after JDK-8333300 Reviewed-by: dnsimon, chagedorn --- src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp | 4 +++- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 4 +++- src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp | 4 +++- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 21095692d19dc..8eff2590bfcea 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,6 +220,7 @@ bool CodeInstaller::pd_relocate(address pc, jint mark) { // see comment above for POLL_FAR _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand); return true; +#if INCLUDE_ZGC case Z_BARRIER_RELOCATION_FORMAT_LOAD_GOOD_BEFORE_SHL: _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeShl); return true; @@ -241,6 +242,7 @@ bool CodeInstaller::pd_relocate(address pc, jint mark) { case Z_BARRIER_RELOCATION_FORMAT_STORE_GOOD_AFTER_MOV: _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatStoreGoodAfterMov); return true; +#endif default: return false; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index b7ae365c1936d..2208813f170d6 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,9 @@ class CompilerToVM { static int sizeof_narrowKlass; static int sizeof_arrayOopDesc; static int sizeof_BasicLock; +#if INCLUDE_ZGC static int sizeof_ZStoreBarrierEntry; +#endif static address dsin; static address dcos; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 220667ad2ced0..8595ac193fb8b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,9 @@ int CompilerToVM::Data::sizeof_ConstantPool = sizeof(ConstantPool); int CompilerToVM::Data::sizeof_narrowKlass = sizeof(narrowKlass); int CompilerToVM::Data::sizeof_arrayOopDesc = sizeof(arrayOopDesc); int CompilerToVM::Data::sizeof_BasicLock = sizeof(BasicLock); +#if INCLUDE_ZGC int CompilerToVM::Data::sizeof_ZStoreBarrierEntry = sizeof(ZStoreBarrierEntry); +#endif address CompilerToVM::Data::dsin; address CompilerToVM::Data::dcos; diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 73bac7bd0909c..fea308503cf71 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -121,7 +121,7 @@ static_field(CompilerToVM::Data, sizeof_narrowKlass, int) \ static_field(CompilerToVM::Data, sizeof_arrayOopDesc, int) \ static_field(CompilerToVM::Data, sizeof_BasicLock, int) \ - static_field(CompilerToVM::Data, sizeof_ZStoreBarrierEntry, int) \ + ZGC_ONLY(static_field(CompilerToVM::Data, sizeof_ZStoreBarrierEntry, int)) \ \ static_field(CompilerToVM::Data, dsin, address) \ static_field(CompilerToVM::Data, dcos, address) \ From 93d98027649615afeeeb6a9510230d9655a74a8f Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 21 Jun 2024 15:48:38 +0000 Subject: [PATCH 005/288] 8334715: [riscv] Mixed use of tab and whitespace in riscv.ad Reviewed-by: chagedorn, amitkumar --- src/hotspot/cpu/riscv/riscv.ad | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 533b548c88109..798caee7375d8 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -242,7 +242,7 @@ reg_def V0_H ( SOC, SOC, Op_VecA, 0, v0->as_VMReg()->next() ); reg_def V0_J ( SOC, SOC, Op_VecA, 0, v0->as_VMReg()->next(2) ); reg_def V0_K ( SOC, SOC, Op_VecA, 0, v0->as_VMReg()->next(3) ); -reg_def V1 ( SOC, SOC, Op_VecA, 1, v1->as_VMReg() ); +reg_def V1 ( SOC, SOC, Op_VecA, 1, v1->as_VMReg() ); reg_def V1_H ( SOC, SOC, Op_VecA, 1, v1->as_VMReg()->next() ); reg_def V1_J ( SOC, SOC, Op_VecA, 1, v1->as_VMReg()->next(2) ); reg_def V1_K ( SOC, SOC, Op_VecA, 1, v1->as_VMReg()->next(3) ); @@ -262,7 +262,7 @@ reg_def V4_H ( SOC, SOC, Op_VecA, 4, v4->as_VMReg()->next() ); reg_def V4_J ( SOC, SOC, Op_VecA, 4, v4->as_VMReg()->next(2) ); reg_def V4_K ( SOC, SOC, Op_VecA, 4, v4->as_VMReg()->next(3) ); -reg_def V5 ( SOC, SOC, Op_VecA, 5, v5->as_VMReg() ); +reg_def V5 ( SOC, SOC, Op_VecA, 5, v5->as_VMReg() ); reg_def V5_H ( SOC, SOC, Op_VecA, 5, v5->as_VMReg()->next() ); reg_def V5_J ( SOC, SOC, Op_VecA, 5, v5->as_VMReg()->next(2) ); reg_def V5_K ( SOC, SOC, Op_VecA, 5, v5->as_VMReg()->next(3) ); @@ -272,7 +272,7 @@ reg_def V6_H ( SOC, SOC, Op_VecA, 6, v6->as_VMReg()->next() ); reg_def V6_J ( SOC, SOC, Op_VecA, 6, v6->as_VMReg()->next(2) ); reg_def V6_K ( SOC, SOC, Op_VecA, 6, v6->as_VMReg()->next(3) ); -reg_def V7 ( SOC, SOC, Op_VecA, 7, v7->as_VMReg() ); +reg_def V7 ( SOC, SOC, Op_VecA, 7, v7->as_VMReg() ); reg_def V7_H ( SOC, SOC, Op_VecA, 7, v7->as_VMReg()->next() ); reg_def V7_J ( SOC, SOC, Op_VecA, 7, v7->as_VMReg()->next(2) ); reg_def V7_K ( SOC, SOC, Op_VecA, 7, v7->as_VMReg()->next(3) ); From 8e1d2b091c9a311d98a0b886a803fb18d4405d8a Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Fri, 21 Jun 2024 16:37:57 +0000 Subject: [PATCH 006/288] 8334441: Mark tests in jdk_security_infra group as manual Reviewed-by: clanger, mullan --- test/jdk/ProblemList.txt | 2 - test/jdk/TEST.groups | 5 +- .../certification/CAInterop.java | 268 +++++++++--------- .../certification/CertignaCA.java | 6 +- .../certification/DTrustCA.java | 6 +- .../certification/DigicertCSRootG5.java | 6 +- .../certification/EmSignRootG2CA.java | 6 +- .../certification/HaricaCA.java | 6 +- .../certification/LuxTrustCA.java | 6 +- .../javax/net/ssl/HttpsURLConnectionTest.java | 2 +- 10 files changed, 158 insertions(+), 155 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 4ea08fa2bbc18..546f95b0054b1 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -620,8 +620,6 @@ javax/net/ssl/SSLSession/CertMsgCheck.java 8326705 generic- sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183,8333317 generic-all -security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java#teliasonerarootcav1 8333640 generic-all - ############################################################################ # jdk_sound diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index fa868699aab38..0a8d27484652a 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -251,6 +251,8 @@ jdk_security = \ :jdk_security3 \ :jdk_security4 +# Tests in this group are manual as they depend on external infra +# and may fail with external reasons, for instance - change in CA test portal. jdk_security_infra = \ security/infra @@ -618,6 +620,7 @@ jdk_core_manual_no_input = \ javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataUtil.java jdk_security_manual_no_input = \ + :jdk_security_infra \ com/sun/crypto/provider/Cipher/DES/PerformanceTest.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java \ @@ -661,4 +664,4 @@ jdk_containers_extended = \ jdk_core_no_security = \ :jdk_core \ - -:jdk_security \ No newline at end of file + -:jdk_security diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 9f071bc145087..889926077a9fe 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -27,12 +27,12 @@ * @summary Interoperability tests with Actalis CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp * -Dcom.sun.security.ocsp.useget=false * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca CRL */ @@ -42,9 +42,9 @@ * @summary Interoperability tests with Amazon's CA1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca1 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca1 CRL */ /* @@ -53,9 +53,9 @@ * @summary Interoperability tests with Amazon's CA2 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca2 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca2 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca2 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca2 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca2 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca2 CRL */ /* @@ -64,9 +64,9 @@ * @summary Interoperability tests with Amazon's CA3 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca3 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca3 CRL */ /* @@ -75,9 +75,9 @@ * @summary Interoperability tests with Amazon's CA4 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca4 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca4 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca4 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca4 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop amazonrootca4 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca4 CRL */ /* @@ -86,9 +86,9 @@ * @summary Interoperability tests with Buypass Class 2 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop buypassclass2ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop buypassclass2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca CRL */ /* @@ -97,9 +97,9 @@ * @summary Interoperability tests with Buypass Class 3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop buypassclass3ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop buypassclass3ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca CRL */ /* @@ -108,9 +108,9 @@ * @summary Interoperability tests with Comodo RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop comodorsaca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop comodorsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop comodorsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop comodorsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop comodorsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop comodorsaca CRL */ /* @@ -119,9 +119,9 @@ * @summary Interoperability tests with Comodo ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop comodoeccca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop comodoeccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop comodoeccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop comodoeccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop comodoeccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop comodoeccca CRL */ /* @@ -130,9 +130,9 @@ * @summary Interoperability tests with Comodo userTrust RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop usertrustrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop usertrustrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop usertrustrsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop usertrustrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop usertrustrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop usertrustrsaca CRL */ /* @@ -141,9 +141,9 @@ * @summary Interoperability tests with Comodo userTrust ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop usertrusteccca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop usertrusteccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop usertrusteccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop usertrusteccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop usertrusteccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop usertrusteccca CRL */ /* @@ -152,8 +152,8 @@ * @summary Interoperability tests with Let's Encrypt ISRG Root X1 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx1 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop letsencryptisrgx1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop letsencryptisrgx1 DEFAULT */ /* @@ -162,8 +162,8 @@ * @summary Interoperability tests with Let's Encrypt ISRG Root X2 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx2 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop letsencryptisrgx2 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx2 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop letsencryptisrgx2 DEFAULT */ /* @@ -172,9 +172,9 @@ * @summary Interoperability tests with GlobalSign R6 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop globalsignrootcar6 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsignrootcar6 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop globalsignrootcar6 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsignrootcar6 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsignrootcar6 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsignrootcar6 CRL */ /* @@ -183,9 +183,9 @@ * @summary Interoperability tests with Entrust CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop entrustrootcaec1 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop entrustrootcaec1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop entrustrootcaec1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop entrustrootcaec1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop entrustrootcaec1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop entrustrootcaec1 CRL */ /* @@ -194,9 +194,9 @@ * @summary Interoperability tests with Entrust CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop entrustrootcag4 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop entrustrootcag4 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop entrustrootcag4 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop entrustrootcag4 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop entrustrootcag4 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop entrustrootcag4 CRL */ /* @@ -205,9 +205,9 @@ * @summary Interoperability tests with GoDaddy CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop godaddyrootg2ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop godaddyrootg2ca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop godaddyrootg2ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop godaddyrootg2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop godaddyrootg2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop godaddyrootg2ca CRL */ /* @@ -216,9 +216,9 @@ * @summary Interoperability tests with Starfield CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop starfieldrootg2ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop starfieldrootg2ca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop starfieldrootg2ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop starfieldrootg2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop starfieldrootg2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop starfieldrootg2ca CRL */ /* @@ -227,8 +227,8 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop globalsigneccrootcar4 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsigneccrootcar4 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsigneccrootcar4 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsigneccrootcar4 DEFAULT */ /* @@ -237,8 +237,8 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar1 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootcar1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootcar1 DEFAULT */ /* @@ -247,8 +247,8 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar2 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootcar2 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar2 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootcar2 DEFAULT */ /* @@ -257,8 +257,8 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar3 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootecccar3 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar3 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootecccar3 DEFAULT */ /* @@ -267,8 +267,8 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootecccar4 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar4 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop gtsrootecccar4 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar4 DEFAULT */ /* @@ -277,9 +277,9 @@ * @summary Interoperability tests with Microsoft TLS root CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop microsoftecc2017 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop microsoftecc2017 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop microsoftecc2017 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop microsoftecc2017 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop microsoftecc2017 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop microsoftecc2017 CRL */ /* @@ -288,9 +288,9 @@ * @summary Interoperability tests with Microsoft TLS root CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop microsoftrsa2017 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop microsoftrsa2017 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop microsoftrsa2017 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop microsoftrsa2017 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop microsoftrsa2017 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop microsoftrsa2017 CRL */ /* @@ -299,9 +299,9 @@ * @summary Interoperability tests with QuoVadis Root CA1 G3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca1g3 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop quovadisrootca1g3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop quovadisrootca1g3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca1g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop quovadisrootca1g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop quovadisrootca1g3 CRL */ /* @@ -310,9 +310,9 @@ * @summary Interoperability tests with QuoVadis Root CA2 G3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca2g3 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop quovadisrootca2g3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop quovadisrootca2g3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca2g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop quovadisrootca2g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop quovadisrootca2g3 CRL */ /* @@ -321,9 +321,9 @@ * @summary Interoperability tests with QuoVadis Root CA3 G3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca3g3 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop quovadisrootca3g3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop quovadisrootca3g3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca3g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop quovadisrootca3g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop quovadisrootca3g3 CRL */ /* @@ -332,9 +332,9 @@ * @summary Interoperability tests with DigiCert TLS ECC P384 Root G5 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop digicerttlseccrootg5 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop digicerttlseccrootg5 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop digicerttlseccrootg5 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop digicerttlseccrootg5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop digicerttlseccrootg5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop digicerttlseccrootg5 CRL */ /* @@ -343,9 +343,9 @@ * @summary Interoperability tests with DigiCert TLS RSA4096 Root G5 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop digicerttlsrsarootg5 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop digicerttlsrsarootg5 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop digicerttlsrsarootg5 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop digicerttlsrsarootg5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop digicerttlsrsarootg5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop digicerttlsrsarootg5 CRL */ /* @@ -354,9 +354,9 @@ * @summary Interoperability tests with SSL.com's RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop sslrootrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop sslrootrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop sslrootrsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop sslrootrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop sslrootrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop sslrootrsaca CRL */ /* @@ -365,9 +365,9 @@ * @summary Interoperability tests with SSL.com's EV RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop sslrootevrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop sslrootevrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop sslrootevrsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop sslrootevrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop sslrootevrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop sslrootevrsaca CRL */ /* @@ -376,9 +376,9 @@ * @summary Interoperability tests with SSL.com's ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop sslrooteccca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop sslrooteccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop sslrooteccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop sslrooteccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop sslrooteccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop sslrooteccca CRL */ /* @@ -387,9 +387,9 @@ * @summary Interoperability tests with TeliaSonera Root CA v1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop teliasonerarootcav1 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop teliasonerarootcav1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop teliasonerarootcav1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop teliasonerarootcav1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop teliasonerarootcav1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop teliasonerarootcav1 CRL */ /* @@ -398,9 +398,9 @@ * @summary Interoperability tests with TWCA Global Root CA from TAIWAN-CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop twcaglobalrootca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop twcaglobalrootca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop twcaglobalrootca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop twcaglobalrootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop twcaglobalrootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop twcaglobalrootca CRL */ /* @@ -409,9 +409,9 @@ * @summary Interoperability tests with Certigna Root CAs from Dhimyotis * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certignarootca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop certignarootca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop certignarootca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop certignarootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop certignarootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop certignarootca CRL */ /* @@ -420,9 +420,9 @@ * @summary Interoperability tests with AffirmTrust Commercial CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustcommercialca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustcommercialca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustcommercialca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustcommercialca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustcommercialca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustcommercialca CRL */ /* @@ -431,9 +431,9 @@ * @summary Interoperability tests with AffirmTrust Networking CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustnetworkingca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustnetworkingca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustnetworkingca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustnetworkingca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustnetworkingca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustnetworkingca CRL */ /* @@ -442,9 +442,9 @@ * @summary Interoperability tests with AffirmTrust Premium CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustpremiumca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustpremiumca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustpremiumca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustpremiumca CRL */ /* @@ -453,9 +453,9 @@ * @summary Interoperability tests with AffirmTrust Premium ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumeccca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustpremiumeccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustpremiumeccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumeccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop affirmtrustpremiumeccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustpremiumeccca CRL */ /* @@ -464,9 +464,9 @@ * @summary Interoperability tests with Telia Root CA V2 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop teliarootcav2 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop teliarootcav2 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop teliarootcav2 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop teliarootcav2 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop teliarootcav2 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop teliarootcav2 CRL */ /* @@ -475,9 +475,9 @@ * @summary Interoperability tests with eMudhra Root CA G1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop emsignrootcag1 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop emsignrootcag1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop emsignrootcag1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop emsignrootcag1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop emsignrootcag1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop emsignrootcag1 CRL */ /* @@ -486,9 +486,9 @@ * @summary Interoperability tests with eMudhra ECC Root CA G3 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop emsigneccrootcag3 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop emsigneccrootcag3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop emsigneccrootcag3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop emsigneccrootcag3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop emsigneccrootcag3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop emsigneccrootcag3 CRL */ /* @@ -497,8 +497,8 @@ * @summary Interoperability tests with Certainly Root R1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certainlyrootr1 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop certainlyrootr1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop certainlyrootr1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop certainlyrootr1 DEFAULT */ /* @@ -507,8 +507,8 @@ * @summary Interoperability tests with Certainly Root E1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certainlyroote1 DEFAULT - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop certainlyroote1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop certainlyroote1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop certainlyroote1 DEFAULT */ /* @@ -517,9 +517,9 @@ * @summary Interoperability tests with GlobalSign Root R46 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop globalsignr46 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsignr46 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop globalsignr46 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsignr46 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsignr46 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsignr46 CRL */ /* @@ -528,13 +528,15 @@ * @summary Interoperability tests with GlobalSign Root E46 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop globalsigne46 OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsigne46 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop globalsigne46 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsigne46 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop globalsigne46 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsigne46 CRL */ /** - * Collection of certificate validation tests for interoperability with external CAs + * Collection of certificate validation tests for interoperability with external CAs. + * These tests are marked as manual as they depend on external infrastructure and may fail + * with external reasons, for instance - change in CA test portal. */ public class CAInterop { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java index f1dd2d6229a47..eb09d56a14e56 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,8 @@ * @bug 8245654 8256895 * @summary Interoperability tests with Certigna Root CAs from Dhimyotis * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath CertignaCA OCSP - * @run main/othervm -Djava.security.debug=certpath CertignaCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath CertignaCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CertignaCA CRL */ public class CertignaCA { // Owner: CN=Certigna Services CA, OID.2.5.4.97=NTRFR-48146308100036, diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java index 152e77907bb30..13a2e8044dac7 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +27,8 @@ * @summary Interoperability tests with "D-Trust Root Class 3 CA 2 2009" and * "D-Trust Root Class 3 CA 2 EV 2009" CAs * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath DTrustCA OCSP - * @run main/othervm -Djava.security.debug=certpath DTrustCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath DTrustCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath DTrustCA CRL */ public class DTrustCA { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java index 30ad81b1755c8..4b45bb857ba45 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,8 @@ * @bug 8318759 * @summary Interoperability tests with Digicert CS Root G5 certificates * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=ocsp,certpath DigicertCSRootG5 OCSP - * @run main/othervm -Djava.security.debug=certpath DigicertCSRootG5 CRL + * @run main/othervm/manual -Djava.security.debug=ocsp,certpath DigicertCSRootG5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath DigicertCSRootG5 CRL */ public class DigicertCSRootG5 { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java index 8f5df9cce755b..14e48a6e78fb1 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,8 @@ * @bug 8319187 * @summary Interoperability tests with eMudhra emSign Root CA G2 CS root * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath EmSignRootG2CA OCSP - * @run main/othervm -Djava.security.debug=certpath EmSignRootG2CA CRL + * @run main/othervm/manual -Djava.security.debug=certpath EmSignRootG2CA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath EmSignRootG2CA CRL */ public class EmSignRootG2CA { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java index 247502e6e6cfe..744e9b6bf34ed 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,8 @@ * @bug 8256421 * @summary Interoperability tests with Harica CAs * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath HaricaCA OCSP - * @run main/othervm -Djava.security.debug=certpath HaricaCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath HaricaCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath HaricaCA CRL */ /* diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java index 469501c70c2f6..3e9631848c247 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * 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,8 +26,8 @@ * @bug 8232019 8256895 * @summary Interoperability tests with LuxTrust Global Root 2 CA * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath LuxTrustCA OCSP - * @run main/othervm -Djava.security.debug=certpath LuxTrustCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath LuxTrustCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath LuxTrustCA CRL */ /* diff --git a/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java b/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java index 7aeb67e842d5b..7e08d6cd4fefe 100644 --- a/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java +++ b/test/jdk/security/infra/javax/net/ssl/HttpsURLConnectionTest.java @@ -28,7 +28,7 @@ * KEYCHAINSTORE-ROOT trust store * @library /test/lib * @requires os.family == "mac" - * @run main/othervm HttpsURLConnectionTest https://github.com KeychainStore-Root + * @run main/othervm/manual HttpsURLConnectionTest https://github.com KeychainStore-Root */ import java.io.*; import java.net.*; From 689cee3d0950e15e88a1f6738bfded00655dca9c Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 21 Jun 2024 18:02:57 +0000 Subject: [PATCH 007/288] 8334509: Cancelling PageDialog does not return the same PageFormat object Reviewed-by: aivanov, prr --- .../native/libawt/windows/awt_PrintJob.cpp | 16 ++--- .../PrinterJob/PageDialogCancelTest.java | 58 +++++++++++++++++++ 2 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp index c761533621870..9f126bded9418 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp @@ -522,6 +522,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL; HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL; + jboolean doIt = JNI_FALSE; PAGESETUPDLG setup; memset(&setup, 0, sizeof(setup)); @@ -577,7 +578,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) */ if ((setup.hDevMode == NULL) && (setup.hDevNames == NULL)) { CLEANUP_SHOW; - return JNI_FALSE; + return doIt; } } else { int measure = PSD_INTHOUSANDTHSOFINCHES; @@ -605,7 +606,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) pageFormatToSetup(env, self, page, &setup, AwtPrintControl::getPrintDC(env, self)); if (env->ExceptionCheck()) { CLEANUP_SHOW; - return JNI_FALSE; + return doIt; } setup.lpfnPageSetupHook = reinterpret_cast(pageDlgHook); @@ -619,7 +620,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) jobject paper = getPaper(env, page); if (paper == NULL) { CLEANUP_SHOW; - return JNI_FALSE; + return doIt; } int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ? MM_HIENGLISH : @@ -661,7 +662,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) setPaperValues(env, paper, &paperSize, &margins, units); if (env->ExceptionCheck()) { CLEANUP_SHOW; - return JNI_FALSE; + return doIt; } /* * Put the updated Paper instance and the orientation into @@ -670,7 +671,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) setPaper(env, page, paper); if (env->ExceptionCheck()) { CLEANUP_SHOW; - return JNI_FALSE; + return doIt; } setPageFormatOrientation(env, page, orientation); if (env->ExceptionCheck()) { @@ -684,12 +685,13 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) jboolean err = setPrintPaperSize(env, self, devmode->dmPaperSize); if (err) { CLEANUP_SHOW; - return JNI_FALSE; + return doIt; } } } ::GlobalUnlock(setup.hDevMode); } + doIt = JNI_TRUE; } AwtDialog::CheckUninstallModalHook(); @@ -708,7 +710,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) CLEANUP_SHOW; - return JNI_TRUE; + return doIt; CATCH_BAD_ALLOC_RET(0); } diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java b/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java new file mode 100644 index 0000000000000..f9ce1b7c196a0 --- /dev/null +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8334366 + * @key headful printer + * @summary Verifies original pageobject is returned unmodified + * on cancelling pagedialog + * @requires (os.family == "windows") + * @run main PageDialogCancelTest + */ + +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; + +public class PageDialogCancelTest { + + public static void main(String[] args) throws Exception { + PrinterJob pj = PrinterJob.getPrinterJob(); + PageFormat oldFormat = new PageFormat(); + Robot robot = new Robot(); + Thread t1 = new Thread(() -> { + robot.delay(2000); + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + }); + t1.start(); + PageFormat newFormat = pj.pageDialog(oldFormat); + if (!newFormat.equals(oldFormat)) { + throw new RuntimeException("Original PageFormat not returned on cancelling PageDialog"); + } + } +} + From 1ff5acdafff1ccd3e64c70eebbfbff75e0d783eb Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Fri, 21 Jun 2024 20:13:26 +0000 Subject: [PATCH 008/288] 8332099: since-checker - Add @ since to package-info in jdk.jsobject Reviewed-by: prr --- .../share/classes/netscape/javascript/package-info.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java b/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java index d3770732bc001..fcc97132a5074 100644 --- a/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java +++ b/src/jdk.jsobject/share/classes/netscape/javascript/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ * The classes in this package were initially specified by Netscape, and are the * de facto standard mechanism for calling JavaScript from the Java runtime. *

+ * + * @since 1.5 */ package netscape.javascript; From 7e55ed3b106ed08956d2d38b7c99fb81704667c9 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 21 Jun 2024 22:38:38 +0000 Subject: [PATCH 009/288] 8333748: javap crash - Fatal error: Unmatched bit position 0x2 for location CLASS Reviewed-by: asotona --- .../com/sun/tools/javap/AttributeWriter.java | 4 +- .../com/sun/tools/javap/BasicWriter.java | 42 +++++- .../com/sun/tools/javap/ClassWriter.java | 70 ++-------- .../tools/javap/UndefinedAccessFlagTest.java | 128 ++++++++++++++++++ 4 files changed, 184 insertions(+), 60 deletions(-) create mode 100644 test/langtools/tools/javap/UndefinedAccessFlagTest.java diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java index 839ac2fd041b7..3b9336c499d9c 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ public void write(Attribute a, CodeAttribute lr) { indent(+1); first = false; } - for (var flag : info.flags()) { + for (var flag : maskToAccessFlagsReportUnknown(access_flags, AccessFlag.Location.INNER_CLASS)) { if (flag.sourceModifier() && (flag != AccessFlag.ABSTRACT || !info.has(AccessFlag.INTERFACE))) { print(Modifier.toString(flag.mask()) + " "); diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/BasicWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/BasicWriter.java index 8629957f907fd..64eecf920829a 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/BasicWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/BasicWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,12 @@ package com.sun.tools.javap; import java.io.PrintWriter; +import java.lang.classfile.AccessFlags; +import java.lang.reflect.AccessFlag; +import java.lang.reflect.Modifier; +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; import java.util.function.Supplier; /* @@ -38,6 +44,26 @@ * deletion without notice. */ public class BasicWriter { + private static final Map LOCATION_MASKS; + + static { + var map = new EnumMap(AccessFlag.Location.class); + for (var loc : AccessFlag.Location.values()) { + map.put(loc, 0); + } + + for (var flag : AccessFlag.values()) { + for (var loc : flag.locations()) { + map.compute(loc, (_, v) -> v | flag.mask()); + } + } + + // Peculiarities from AccessFlag.maskToAccessFlag + map.compute(AccessFlag.Location.METHOD, (_, v) -> v | Modifier.STRICT); + + LOCATION_MASKS = map; + } + protected BasicWriter(Context context) { lineWriter = LineWriter.instance(context); out = context.get(PrintWriter.class); @@ -46,6 +72,20 @@ protected BasicWriter(Context context) { throw new AssertionError(); } + protected Set flagsReportUnknown(AccessFlags flags) { + return maskToAccessFlagsReportUnknown(flags.flagsMask(), flags.location()); + } + + protected Set maskToAccessFlagsReportUnknown(int mask, AccessFlag.Location location) { + try { + return AccessFlag.maskToAccessFlags(mask, location); + } catch (IllegalArgumentException ex) { + mask &= LOCATION_MASKS.get(location); + report("Access Flags: " + ex.getMessage()); + return AccessFlag.maskToAccessFlags(mask, location); + } + } + protected void print(String s) { lineWriter.print(s); } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index edf3d803af321..2483e99e49ad9 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -417,7 +417,7 @@ protected void writeField(FieldModel f) { return; var flags = AccessFlags.ofField(f.flags().flagsMask()); - writeModifiers(flags.flags().stream().filter(fl -> fl.sourceModifier()) + writeModifiers(flagsReportUnknown(flags).stream().filter(fl -> fl.sourceModifier()) .map(fl -> Modifier.toString(fl.mask())).toList()); print(() -> sigPrinter.print( f.findAttribute(Attributes.signature()) @@ -446,7 +446,7 @@ protected void writeField(FieldModel f) { if (options.verbose) writeList(String.format("flags: (0x%04x) ", flags.flagsMask()), - flags.flags().stream().map(fl -> "ACC_" + fl.name()).toList(), + flagsReportUnknown(flags).stream().map(fl -> "ACC_" + fl.name()).toList(), "\n"); if (options.showAllAttrs) { @@ -478,7 +478,7 @@ protected void writeMethod(MethodModel m) { int flags = m.flags().flagsMask(); var modifiers = new ArrayList(); - for (var f : AccessFlags.ofMethod(flags).flags()) + for (var f : flagsReportUnknown(m.flags())) if (f.sourceModifier()) modifiers.add(Modifier.toString(f.mask())); String name = "???"; @@ -561,7 +561,7 @@ protected void writeMethod(MethodModel m) { StringBuilder sb = new StringBuilder(); String sep = ""; sb.append(String.format("flags: (0x%04x) ", flags)); - for (var f : AccessFlags.ofMethod(flags).flags()) { + for (var f : flagsReportUnknown(m.flags())) { sb.append(sep).append("ACC_").append(f.name()); sep = ", "; } @@ -794,17 +794,9 @@ else switch (c) { } } - private static Set getClassModifiers(int mask) { - return getModifiers(AccessFlags.ofClass((mask & ACC_INTERFACE) != 0 - ? mask & ~ACC_ABSTRACT : mask).flags()); - } - - private static Set getMethodModifiers(int mask) { - return getModifiers(AccessFlags.ofMethod(mask).flags()); - } - - private static Set getFieldModifiers(int mask) { - return getModifiers(AccessFlags.ofField(mask).flags()); + private Set getClassModifiers(int mask) { + return getModifiers(flagsReportUnknown(AccessFlags.ofClass((mask & ACC_INTERFACE) != 0 + ? mask & ~ACC_ABSTRACT : mask))); } private static Set getModifiers(Set flags) { @@ -814,16 +806,16 @@ private static Set getModifiers(Set flags) return s; } - private static Set getClassFlags(int mask) { - return getFlags(mask, AccessFlags.ofClass(mask).flags()); + private Set getClassFlags(int mask) { + return getFlags(mask, flagsReportUnknown(AccessFlags.ofClass(mask))); } - private static Set getMethodFlags(int mask) { - return getFlags(mask, AccessFlags.ofMethod(mask).flags()); + private Set getMethodFlags(int mask) { + return getFlags(mask, flagsReportUnknown(AccessFlags.ofMethod(mask))); } - private static Set getFieldFlags(int mask) { - return getFlags(mask, AccessFlags.ofField(mask).flags()); + private Set getFieldFlags(int mask) { + return getFlags(mask, flagsReportUnknown(AccessFlags.ofField(mask))); } private static Set getFlags(int mask, Set flags) { @@ -840,42 +832,6 @@ private static Set getFlags(int mask, Set return s; } - public static enum AccessFlag { - ACC_PUBLIC (ClassFile.ACC_PUBLIC, "public", true, true, true, true ), - ACC_PRIVATE (ClassFile.ACC_PRIVATE, "private", false, true, true, true ), - ACC_PROTECTED (ClassFile.ACC_PROTECTED, "protected", false, true, true, true ), - ACC_STATIC (ClassFile.ACC_STATIC, "static", false, true, true, true ), - ACC_FINAL (ClassFile.ACC_FINAL, "final", true, true, true, true ), - ACC_SUPER (ClassFile.ACC_SUPER, null, true, false, false, false), - ACC_SYNCHRONIZED(ClassFile.ACC_SYNCHRONIZED, "synchronized", false, false, false, true ), - ACC_VOLATILE (ClassFile.ACC_VOLATILE, "volatile", false, false, true, false), - ACC_BRIDGE (ClassFile.ACC_BRIDGE, null, false, false, false, true ), - ACC_TRANSIENT (ClassFile.ACC_TRANSIENT, "transient", false, false, true, false), - ACC_VARARGS (ClassFile.ACC_VARARGS, null, false, false, false, true ), - ACC_NATIVE (ClassFile.ACC_NATIVE, "native", false, false, false, true ), - ACC_INTERFACE (ClassFile.ACC_INTERFACE, null, true, true, false, false), - ACC_ABSTRACT (ClassFile.ACC_ABSTRACT, "abstract", true, true, false, true ), - ACC_STRICT (ClassFile.ACC_STRICT, "strictfp", false, false, false, true ), - ACC_SYNTHETIC (ClassFile.ACC_SYNTHETIC, null, true, true, true, true ), - ACC_ANNOTATION (ClassFile.ACC_ANNOTATION, null, true, true, false, false), - ACC_ENUM (ClassFile.ACC_ENUM, null, true, true, true, false), - ACC_MODULE (ClassFile.ACC_MODULE, null, true, false, false, false); - - public final int flag; - public final String modifier; - public final boolean isClass, isInnerClass, isField, isMethod; - - AccessFlag(int flag, String modifier, boolean isClass, - boolean isInnerClass, boolean isField, boolean isMethod) { - this.flag = flag; - this.modifier = modifier; - this.isClass = isClass; - this.isInnerClass = isInnerClass; - this.isField = isField; - this.isMethod = isMethod; - } - } - private final Options options; private final AttributeWriter attrWriter; private final CodeWriter codeWriter; diff --git a/test/langtools/tools/javap/UndefinedAccessFlagTest.java b/test/langtools/tools/javap/UndefinedAccessFlagTest.java new file mode 100644 index 0000000000000..bb531fa369c16 --- /dev/null +++ b/test/langtools/tools/javap/UndefinedAccessFlagTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333748 + * @summary javap should not fail if reserved access flag bits are set to 1 + * @library /tools/lib + * @modules jdk.jdeps/com.sun.tools.javap + * @enablePreview + * @run junit UndefinedAccessFlagTest + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import toolbox.JavapTask; +import toolbox.Task; +import toolbox.ToolBox; + +import java.lang.classfile.AccessFlags; +import java.lang.classfile.ClassModel; +import java.lang.classfile.FieldModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.nio.file.Files; +import java.nio.file.Path; + +import static java.lang.classfile.ClassFile.*; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class UndefinedAccessFlagTest { + + final ToolBox toolBox = new ToolBox(); + + enum TestLocation { + NONE(false), CLASS, FIELD, METHOD, INNER_CLASS(false); + + final boolean fails; + TestLocation() { this(true); } + TestLocation(boolean fails) { this.fails = fails; } + } + + @ParameterizedTest + @EnumSource(TestLocation.class) + void test(TestLocation location) throws Throwable { + var cf = of(); + ClassModel cm; + try (var is = UndefinedAccessFlagTest.class.getResourceAsStream( + "/UndefinedAccessFlagTest$SampleInnerClass.class" + )) { + cm = cf.parse(is.readAllBytes()); + } + var bytes = cf.transform(cm, (cb, ce) -> { + switch (ce) { + case AccessFlags flags when location == TestLocation.CLASS -> cb + .withFlags(flags.flagsMask() | ACC_PRIVATE); + case FieldModel f when location == TestLocation.FIELD -> cb + .transformField(f, (fb, fe) -> { + if (fe instanceof AccessFlags flags) { + fb.withFlags(flags.flagsMask() | ACC_SYNCHRONIZED); + } else { + fb.with(fe); + } + }); + case MethodModel m when location == TestLocation.METHOD -> cb + .transformMethod(m, (mb, me) -> { + if (me instanceof AccessFlags flags) { + mb.withFlags(flags.flagsMask() | ACC_INTERFACE); + } else { + mb.with(me); + } + }); + case InnerClassesAttribute attr when location == TestLocation.INNER_CLASS -> cb + .with(InnerClassesAttribute.of(attr.classes().stream() + .map(ic -> InnerClassInfo.of(ic.innerClass(), ic.outerClass(), ic.innerName(), ic.flagsMask() | 0x0020)) + .toList())); + default -> cb.with(ce); + } + }); + + Files.write(Path.of("transformed.class"), bytes); + + var lines = new JavapTask(toolBox) + .classes("transformed.class") + .options("-c", "-p", "-v") + .run(location.fails ? Task.Expect.FAIL : Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + // No termination when access flag error happens + assertTrue(lines.stream().anyMatch(l -> l.contains("java.lang.String field;"))); + assertTrue(lines.stream().anyMatch(l -> l.contains("UndefinedAccessFlagTest$SampleInnerClass();"))); + assertTrue(lines.stream().anyMatch(l -> l.contains("void method();"))); + assertTrue(lines.stream().anyMatch(l -> l.contains("SampleInnerClass=class UndefinedAccessFlagTest$SampleInnerClass of class UndefinedAccessFlagTest"))); + + // Remove non-error lines + assertTrue(lines.removeIf(st -> !st.startsWith("Error:"))); + // Desired locations has errors + assertTrue(location == TestLocation.NONE || !lines.isEmpty()); + // Access Flag errors only + assertTrue(lines.stream().allMatch(l -> l.contains("Access Flags:")), () -> String.join("\n", lines)); + } + + static class SampleInnerClass { + String field; + void method() {} + } +} From 72ca7bafcd49a98c1fe09da72e4e47683f052e9d Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 22 Jun 2024 12:16:50 +0000 Subject: [PATCH 010/288] 8334708: FFM: two javadoc problems Reviewed-by: mcimadamore --- src/java.base/share/classes/java/lang/foreign/Linker.java | 2 +- src/java.base/share/classes/java/lang/foreign/MemoryLayout.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 545a83984f867..fd6e820d01662 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -222,7 +222,7 @@ *
  * MemoryLayout.structLayout(
  *     ValueLayout.JAVA_INT.withName("x"),
- *     MemoryLayout.paddingLayout(32),
+ *     MemoryLayout.paddingLayout(4),
  *     ValueLayout.JAVA_LONG.withName("y")
  * );
  * 
diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 372b10aab1389..989fc134a2628 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -369,7 +369,7 @@ * int size = ... * MemorySegment points = ... * for (int i = 0 ; i < size ; i++) { - * ... POINT_ARR_X.get(segment, 0L, (long)i) ... + * ... POINT_ARR_X.get(points, 0L, (long)i) ... * } * } * From 652784c803863f40ee3d81695a19e705365cb800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Sun, 23 Jun 2024 08:19:28 +0000 Subject: [PATCH 011/288] 8334392: Switch RNG in NMT's treap Reviewed-by: stuefe, azafari, gziemski --- src/hotspot/share/nmt/nmtTreap.hpp | 24 +++++++++++------------ test/hotspot/gtest/nmt/test_nmt_treap.cpp | 12 ++++++++---- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/nmt/nmtTreap.hpp b/src/hotspot/share/nmt/nmtTreap.hpp index 97a5cddcb81ed..99c8655525c95 100644 --- a/src/hotspot/share/nmt/nmtTreap.hpp +++ b/src/hotspot/share/nmt/nmtTreap.hpp @@ -25,13 +25,12 @@ #ifndef SHARE_NMT_NMTTREAP_HPP #define SHARE_NMT_NMTTREAP_HPP -#include "memory/allocation.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" -#include +#include "utilities/powerOfTwo.hpp" // A Treap is a self-balanced binary tree where each node is equipped with a // priority. It adds the invariant that the priority of a parent P is strictly larger @@ -84,16 +83,16 @@ class Treap { private: ALLOCATOR _allocator; TreapNode* _root; + + // A random number + static constexpr const uint64_t _initial_seed = 0xC8DD2114AE0543A3; uint64_t _prng_seed; int _node_count; uint64_t prng_next() { - // Taken directly off of JFRPrng - static const constexpr uint64_t PrngMult = 0x5DEECE66DLL; - static const constexpr uint64_t PrngAdd = 0xB; - static const constexpr uint64_t PrngModPower = 48; - static const constexpr uint64_t PrngModMask = (static_cast(1) << PrngModPower) - 1; - _prng_seed = (PrngMult * _prng_seed + PrngAdd) & PrngModMask; + uint64_t first_half = os::next_random(_prng_seed); + uint64_t second_half = os::next_random(_prng_seed >> 32); + _prng_seed = first_half | (second_half << 32); return _prng_seed; } @@ -173,9 +172,9 @@ class Treap { #ifdef ASSERT void verify_self() { // A balanced binary search tree should have a depth on the order of log(N). - // We take the ceiling of log_2(N + 1) * 2.5 as our maximum bound. + // We take the ceiling of log_2(N + 1) * 3 as our maximum bound. // For comparison, a RB-tree has a proven max depth of log_2(N + 1) * 2. - const int expected_maximum_depth = ceil((log(this->_node_count+1) / log(2)) * 2.5); + const int expected_maximum_depth = ceil(log2i(this->_node_count+1) * 3); // Find the maximum depth through DFS and ensure that the priority invariant holds. int maximum_depth_found = 0; @@ -225,11 +224,10 @@ class Treap { public: NONCOPYABLE(Treap); - Treap(uint64_t seed = static_cast(os::random()) - | (static_cast(os::random()) << 32)) + Treap() : _allocator(), _root(nullptr), - _prng_seed(seed), + _prng_seed(_initial_seed), _node_count(0) {} ~Treap() { diff --git a/test/hotspot/gtest/nmt/test_nmt_treap.cpp b/test/hotspot/gtest/nmt/test_nmt_treap.cpp index 9cd7f36aad6a7..3c98029d28f58 100644 --- a/test/hotspot/gtest/nmt/test_nmt_treap.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_treap.cpp @@ -300,7 +300,9 @@ TEST_VM_F(TreapTest, VerifyItThroughStressTest) { } else { treap.remove(i); } - verify_it(treap); + if (i % 100 == 0) { + verify_it(treap); + } } for (int i = 0; i < ten_thousand; i++) { int r = os::random(); @@ -309,14 +311,16 @@ TEST_VM_F(TreapTest, VerifyItThroughStressTest) { } else { treap.remove(i); } - verify_it(treap); + if (i % 100 == 0) { + verify_it(treap); + } } } { // Make a very large treap and verify at the end struct Nothing {}; TreapCHeap treap; - constexpr const int five_million = 5000000; - for (int i = 0; i < five_million; i++) { + constexpr const int one_hundred_thousand = 100000; + for (int i = 0; i < one_hundred_thousand; i++) { treap.upsert(i, Nothing()); } verify_it(treap); From eb110bdc6e8bcb87b9b8b24ac66eb9b4c57106fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Sun, 23 Jun 2024 12:33:38 +0000 Subject: [PATCH 012/288] 8334180: NMT gtests introduced with 8312132 should be labeled as NMT Reviewed-by: gziemski, stuefe --- src/hotspot/share/nmt/memoryFileTracker.hpp | 4 ++-- src/hotspot/share/nmt/nmtTreap.hpp | 4 ++-- src/hotspot/share/nmt/vmatree.hpp | 2 +- .../gtest/nmt/test_nmt_memoryfiletracker.cpp | 4 ++-- .../gtest/nmt/test_nmt_nativecallstackstorage.cpp | 6 +++--- test/hotspot/gtest/nmt/test_nmt_treap.cpp | 14 +++++++------- test/hotspot/gtest/nmt/test_vmatree.cpp | 12 ++++++------ 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/nmt/memoryFileTracker.hpp b/src/hotspot/share/nmt/memoryFileTracker.hpp index f662893af0a6b..432b6f9d99e1e 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.hpp +++ b/src/hotspot/share/nmt/memoryFileTracker.hpp @@ -40,7 +40,7 @@ // storage with its own memory space separate from the process. // A typical example of such a file is a memory mapped file. class MemoryFileTracker { - friend class MemoryFileTrackerTest; + friend class NMTMemoryFileTrackerTest; // Provide caching of stacks. NativeCallStackStorage _stack_storage; @@ -48,7 +48,7 @@ class MemoryFileTracker { public: class MemoryFile : public CHeapObj { friend MemoryFileTracker; - friend class MemoryFileTrackerTest; + friend class NMTMemoryFileTrackerTest; const char* _descriptive_name; VirtualMemorySnapshot _summary; VMATree _tree; diff --git a/src/hotspot/share/nmt/nmtTreap.hpp b/src/hotspot/share/nmt/nmtTreap.hpp index 99c8655525c95..700634974393a 100644 --- a/src/hotspot/share/nmt/nmtTreap.hpp +++ b/src/hotspot/share/nmt/nmtTreap.hpp @@ -52,8 +52,8 @@ template class Treap { - friend class VMATreeTest; - friend class TreapTest; + friend class NMTVMATreeTest; + friend class NMTTreapTest; public: class TreapNode { friend Treap; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index b8946b3b8c155..a93c282f4d272 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -38,7 +38,7 @@ // or from committed memory of a certain MEMFLAGS to committed memory of a different MEMFLAGS. // The set of points is stored in a balanced binary tree for efficient querying and updating. class VMATree { - friend class VMATreeTest; + friend class NMTVMATreeTest; // A position in memory. public: using position = size_t; diff --git a/test/hotspot/gtest/nmt/test_nmt_memoryfiletracker.cpp b/test/hotspot/gtest/nmt/test_nmt_memoryfiletracker.cpp index 018b9c49d544e..d32c8192f2cd0 100644 --- a/test/hotspot/gtest/nmt/test_nmt_memoryfiletracker.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_memoryfiletracker.cpp @@ -27,7 +27,7 @@ #include "nmt/memTracker.hpp" #include "unittest.hpp" -class MemoryFileTrackerTest : public testing::Test { +class NMTMemoryFileTrackerTest : public testing::Test { public: size_t sz(int x) { return (size_t) x; } void basics() { @@ -48,6 +48,6 @@ class MemoryFileTrackerTest : public testing::Test { }; }; -TEST_VM_F(MemoryFileTrackerTest, Basics) { +TEST_VM_F(NMTMemoryFileTrackerTest, Basics) { this->basics(); } diff --git a/test/hotspot/gtest/nmt/test_nmt_nativecallstackstorage.cpp b/test/hotspot/gtest/nmt/test_nmt_nativecallstackstorage.cpp index 92c2dde210415..71e924b7b9dc7 100644 --- a/test/hotspot/gtest/nmt/test_nmt_nativecallstackstorage.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_nativecallstackstorage.cpp @@ -29,9 +29,9 @@ using NCSS = NativeCallStackStorage; -class NativeCallStackStorageTest : public testing::Test {}; +class NMTNativeCallStackStorageTest : public testing::Test {}; -TEST_VM_F(NativeCallStackStorageTest, DoNotStoreStackIfNotDetailed) { +TEST_VM_F(NMTNativeCallStackStorageTest, DoNotStoreStackIfNotDetailed) { NativeCallStack ncs{}; NCSS ncss(false); NCSS::StackIndex si = ncss.push(ncs); @@ -40,7 +40,7 @@ TEST_VM_F(NativeCallStackStorageTest, DoNotStoreStackIfNotDetailed) { EXPECT_TRUE(ncs_received.is_empty()); } -TEST_VM_F(NativeCallStackStorageTest, CollisionsReceiveDifferentIndexes) { +TEST_VM_F(NMTNativeCallStackStorageTest, CollisionsReceiveDifferentIndexes) { constexpr const int nr_of_stacks = 10; NativeCallStack ncs_arr[nr_of_stacks]; for (int i = 0; i < nr_of_stacks; i++) { diff --git a/test/hotspot/gtest/nmt/test_nmt_treap.cpp b/test/hotspot/gtest/nmt/test_nmt_treap.cpp index 3c98029d28f58..6e04cfce1a82d 100644 --- a/test/hotspot/gtest/nmt/test_nmt_treap.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_treap.cpp @@ -28,7 +28,7 @@ #include "runtime/os.hpp" #include "unittest.hpp" -class TreapTest : public testing::Test { +class NMTTreapTest : public testing::Test { public: struct Cmp { static int cmp(int a, int b) { @@ -147,15 +147,15 @@ class TreapTest : public testing::Test { } }; -TEST_VM_F(TreapTest, InsertingDuplicatesResultsInOneValue) { +TEST_VM_F(NMTTreapTest, InsertingDuplicatesResultsInOneValue) { this->inserting_duplicates_results_in_one_value(); } -TEST_VM_F(TreapTest, TreapOughtNotLeak) { +TEST_VM_F(NMTTreapTest, TreapOughtNotLeak) { this->treap_ought_not_leak(); } -TEST_VM_F(TreapTest, TestVisitors) { +TEST_VM_F(NMTTreapTest, TestVisitors) { { // Tests with 'default' ordering (ascending) TreapCHeap treap; using Node = TreapCHeap::TreapNode; @@ -259,11 +259,11 @@ TEST_VM_F(TreapTest, TestVisitors) { } } -TEST_VM_F(TreapTest, TestFind) { +TEST_VM_F(NMTTreapTest, TestFind) { test_find(); } -TEST_VM_F(TreapTest, TestClosestLeq) { +TEST_VM_F(NMTTreapTest, TestClosestLeq) { using Node = TreapCHeap::TreapNode; { TreapCHeap treap; @@ -289,7 +289,7 @@ TEST_VM_F(TreapTest, TestClosestLeq) { #ifdef ASSERT -TEST_VM_F(TreapTest, VerifyItThroughStressTest) { +TEST_VM_F(NMTTreapTest, VerifyItThroughStressTest) { { // Repeatedly verify a treap of moderate size TreapCHeap treap; constexpr const int ten_thousand = 10000; diff --git a/test/hotspot/gtest/nmt/test_vmatree.cpp b/test/hotspot/gtest/nmt/test_vmatree.cpp index 17eb61352cd0f..1c1bc31b5b498 100644 --- a/test/hotspot/gtest/nmt/test_vmatree.cpp +++ b/test/hotspot/gtest/nmt/test_vmatree.cpp @@ -34,14 +34,14 @@ using Tree = VMATree; using Node = Tree::TreapNode; using NCS = NativeCallStackStorage; -class VMATreeTest : public testing::Test { +class NMTVMATreeTest : public testing::Test { public: NCS ncs; constexpr static const int si_len = 2; NCS::StackIndex si[si_len]; NativeCallStack stacks[si_len]; - VMATreeTest() : ncs(true) { + NMTVMATreeTest() : ncs(true) { stacks[0] = make_stack(0xA); stacks[1] = make_stack(0xB); si[0] = ncs.push(stacks[0]); @@ -172,7 +172,7 @@ class VMATreeTest : public testing::Test { -TEST_VM_F(VMATreeTest, OverlappingReservationsResultInTwoNodes) { +TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { VMATree::RegionData rd{si[0], mtTest}; Tree tree; for (int i = 99; i >= 0; i--) { @@ -182,7 +182,7 @@ TEST_VM_F(VMATreeTest, OverlappingReservationsResultInTwoNodes) { } // Low-level tests inspecting the state of the tree. -TEST_VM_F(VMATreeTest, LowLevel) { +TEST_VM_F(NMTVMATreeTest, LowLevel) { adjacent_2_nodes(VMATree::empty_regiondata); remove_all_leaves_empty_tree(VMATree::empty_regiondata); commit_middle(VMATree::empty_regiondata); @@ -268,7 +268,7 @@ TEST_VM_F(VMATreeTest, LowLevel) { } // Tests for summary accounting -TEST_VM_F(VMATreeTest, SummaryAccounting) { +TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Fully enclosed re-reserving works correctly. Tree::RegionData rd(NCS::StackIndex(), mtTest); Tree::RegionData rd2(NCS::StackIndex(), mtNMT); @@ -416,7 +416,7 @@ struct SimpleVMATracker : public CHeapObj { constexpr const size_t SimpleVMATracker::num_pages; -TEST_VM_F(VMATreeTest, TestConsistencyWithSimpleTracker) { +TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { // In this test we use ASSERT macros from gtest instead of EXPECT // as any error will propagate and become larger as the test progresses. SimpleVMATracker* tr = new SimpleVMATracker(); From 7baddc202a9ab2b85401aa05f827678b514ebf55 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sun, 23 Jun 2024 18:00:28 +0000 Subject: [PATCH 013/288] 8334339: Test java/nio/file/attribute/BasicFileAttributeView/CreationTime.java fails on alinux3 Reviewed-by: alanb --- .../BasicFileAttributeView/CreationTime.java | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index 1898f584bcd63..ad85da7ae63b1 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,24 @@ * questions. */ -/* @test - * @bug 8011536 8151430 8316304 +/* @test id=tmp + * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems - * that support it. + * that support it, tests using /tmp directory. * @library ../.. /test/lib * @build jdk.test.lib.Platform * @run main CreationTime */ +/* @test id=cwd + * @summary Basic test for creationTime attribute on platforms/file systems + * that support it, tests using the test scratch directory, the test + * scratch directory maybe at diff disk partition to /tmp on linux. + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * @run main CreationTime . + */ + import java.lang.foreign.Linker; import java.nio.file.Path; import java.nio.file.Files; @@ -38,6 +47,7 @@ import java.io.IOException; import jdk.test.lib.Platform; +import jtreg.SkippedException; public class CreationTime { @@ -68,8 +78,14 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); + System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); + // If the file system doesn't support birth time, then skip this test + if (creationTime.toMillis() == 0) { + throw new SkippedException("birth time not support for: " + file); + } else { + err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); + } } /** @@ -95,7 +111,7 @@ static void test(Path top) throws IOException { // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } - System.out.println("supportsCreationTimeRead == " + supportsCreationTimeRead); + System.out.println(top + " supportsCreationTimeRead == " + supportsCreationTimeRead); /** * If the creation-time attribute is supported then change the file's @@ -127,7 +143,12 @@ static void test(Path top) throws IOException { public static void main(String[] args) throws IOException { // create temporary directory to run tests - Path dir = TestUtil.createTemporaryDirectory(); + Path dir; + if (args.length == 0) { + dir = TestUtil.createTemporaryDirectory(); + } else { + dir = TestUtil.createTemporaryDirectory(args[0]); + } try { test(dir); } finally { From a4582a8957d604b50249e1f59679393966456a14 Mon Sep 17 00:00:00 2001 From: Zhao Song Date: Mon, 24 Jun 2024 05:15:32 +0000 Subject: [PATCH 014/288] 8334166: Enable binary check Reviewed-by: kcr, ihse, prr, erikj --- .jcheck/conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jcheck/conf b/.jcheck/conf index ecc41e341d926..f666ff69d5ee3 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -5,7 +5,7 @@ version=24 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists -warning=issuestitle +warning=issuestitle,binary [repository] tags=(?:jdk-(?:[1-9]([0-9]*)(?:\.(?:0|[1-9][0-9]*)){0,4})(?:\+(?:(?:[0-9]+))|(?:-ga)))|(?:jdk[4-9](?:u\d{1,3})?-(?:(?:b\d{2,3})|(?:ga)))|(?:hs\d\d(?:\.\d{1,2})?-b\d\d) From 863b2a991df9204560c4680fc10dd0f68b260217 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 24 Jun 2024 06:06:45 +0000 Subject: [PATCH 015/288] 8329994: Zap alignment padding bits for ArrayOops in non-release builds Reviewed-by: ayang, sjohanss --- src/hotspot/share/gc/shared/memAllocator.cpp | 15 +++++++++++++++ src/hotspot/share/gc/shared/memAllocator.hpp | 1 + src/hotspot/share/gc/z/zObjArrayAllocator.cpp | 2 ++ 3 files changed, 18 insertions(+) diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index 156b55c104621..318ab00188b3d 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -388,6 +388,7 @@ oop ObjArrayAllocator::initialize(HeapWord* mem) const { assert(_length >= 0, "length should be non-negative"); if (_do_zero) { mem_clear(mem); + mem_zap_start_padding(mem); mem_zap_end_padding(mem); } arrayOopDesc::set_length(mem, _length); @@ -395,6 +396,20 @@ oop ObjArrayAllocator::initialize(HeapWord* mem) const { } #ifndef PRODUCT +void ObjArrayAllocator::mem_zap_start_padding(HeapWord* mem) const { + const BasicType element_type = ArrayKlass::cast(_klass)->element_type(); + const size_t base_offset_in_bytes = arrayOopDesc::base_offset_in_bytes(element_type); + const size_t header_size_in_bytes = arrayOopDesc::header_size_in_bytes(); + + const address base = reinterpret_cast
(mem) + base_offset_in_bytes; + const address header_end = reinterpret_cast
(mem) + header_size_in_bytes; + + if (header_end < base) { + const size_t padding_in_bytes = base - header_end; + Copy::fill_to_bytes(header_end, padding_in_bytes, heapPaddingByteVal); + } +} + void ObjArrayAllocator::mem_zap_end_padding(HeapWord* mem) const { const size_t length_in_bytes = static_cast(_length) << ArrayKlass::cast(_klass)->log2_element_size(); const BasicType element_type = ArrayKlass::cast(_klass)->element_type(); diff --git a/src/hotspot/share/gc/shared/memAllocator.hpp b/src/hotspot/share/gc/shared/memAllocator.hpp index a0450af4450ec..ec67616adbaaf 100644 --- a/src/hotspot/share/gc/shared/memAllocator.hpp +++ b/src/hotspot/share/gc/shared/memAllocator.hpp @@ -94,6 +94,7 @@ class ObjArrayAllocator: public MemAllocator { const int _length; const bool _do_zero; + void mem_zap_start_padding(HeapWord* mem) const PRODUCT_RETURN; void mem_zap_end_padding(HeapWord* mem) const PRODUCT_RETURN; public: diff --git a/src/hotspot/share/gc/z/zObjArrayAllocator.cpp b/src/hotspot/share/gc/z/zObjArrayAllocator.cpp index 1b2f3804e3d24..ad19f273dcf0f 100644 --- a/src/hotspot/share/gc/z/zObjArrayAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjArrayAllocator.cpp @@ -139,6 +139,8 @@ oop ZObjArrayAllocator::initialize(HeapWord* mem) const { return true; }; + mem_zap_start_padding(mem); + if (!initialize_memory()) { // Re-color with 11 remset bits if we got intercepted by a GC safepoint const bool result = initialize_memory(); From 13dce296fc3924b269757ce1279c57afe18faeeb Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Mon, 24 Jun 2024 06:33:39 +0000 Subject: [PATCH 016/288] 8334560: [PPC64]: postalloc_expand_java_dynamic_call_sched does not copy all fields Reviewed-by: mbaesken, mdoerr --- src/hotspot/cpu/ppc/ppc.ad | 1 + test/jdk/com/sun/jdi/EATests.java | 91 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 8917b344e54cb..38485da958132 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -3429,6 +3429,7 @@ encode %{ call->_oop_map = _oop_map; call->_jvms = _jvms; call->_jvmadj = _jvmadj; + call->_has_ea_local_in_scope = _has_ea_local_in_scope; call->_in_rms = _in_rms; call->_nesting = _nesting; call->_override_symbolic_info = _override_symbolic_info; diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index cd80d01a07f11..7285948165989 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -289,6 +289,7 @@ public static void main(String[] args) { // Relocking test cases new EARelockingSimpleTarget() .run(); new EARelockingSimpleWithAccessInOtherThreadTarget() .run(); + new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target() .run(); new EARelockingRecursiveTarget() .run(); new EARelockingNestedInflatedTarget() .run(); new EARelockingNestedInflated_02Target() .run(); @@ -413,6 +414,7 @@ protected void runTests() throws Exception { // Relocking test cases new EARelockingSimple() .run(this); new EARelockingSimpleWithAccessInOtherThread() .run(this); + new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall() .run(this); new EARelockingRecursive() .run(this); new EARelockingNestedInflated() .run(this); new EARelockingNestedInflated_02() .run(this); @@ -1851,6 +1853,95 @@ public int getExpectedIResult() { ///////////////////////////////////////////////////////////////////////////// +// The debugger reads and publishes an object with eliminated locking to an instance field. +// A 2nd thread in the debuggee finds it there and changes its state using a synchronized method. +// Without eager relocking the accesses are unsynchronized which can be observed. +// This is a variant of EARelockingSimpleWithAccessInOtherThread with a dynamic call (not devirtualized). +class EARelockingSimpleWithAccessInOtherThread_02_DynamicCall extends EATestCaseBaseDebugger { + + public void runTestCase() throws Exception { + BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); + printStack(bpe.thread()); + String l1ClassName = EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target.SyncCounter.class.getName(); + ObjectReference ctr = getLocalRef(bpe.thread().frame(2), l1ClassName, "l1"); + setField(testCase, "sharedCounter", ctr); + terminateEndlessLoop(); + } +} + +class EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target extends EATestCaseBaseTarget { + + public static final BrkPtDispatchA[] disp = + {new BrkPtDispatchA(), new BrkPtDispatchB(), new BrkPtDispatchC(), new BrkPtDispatchD()}; + + public static class BrkPtDispatchA { + public EATestCaseBaseTarget testCase; + public void dontinline_brkpt() { testCase.dontinline_brkpt(); } + } + + public static class BrkPtDispatchB extends BrkPtDispatchA { + @Override + public void dontinline_brkpt() { testCase.dontinline_brkpt(); } + } + + public static class BrkPtDispatchC extends BrkPtDispatchA { + @Override + public void dontinline_brkpt() { testCase.dontinline_brkpt(); } + } + + public static class BrkPtDispatchD extends BrkPtDispatchA { + @Override + public void dontinline_brkpt() { + testCase.dontinline_brkpt(); + } + } + + public static class SyncCounter { + private int val; + public synchronized int inc() { return val++; } + } + + public volatile SyncCounter sharedCounter; + + @Override + public void setUp() { + super.setUp(); + testMethodDepth = 2; + for (BrkPtDispatchA d : disp) { + d.testCase = this; + } + doLoop = true; + new Thread(() -> { + while (doLoop) { + SyncCounter ctr = sharedCounter; + if (ctr != null) { + ctr.inc(); + } + } + }).start(); + } + + public int dispCount; + public void dontinline_testMethod() { + SyncCounter l1 = new SyncCounter(); + synchronized (l1) { // Eliminated locking + l1.inc(); + // Use different types for the subsequent call to prevent devirtualization. + BrkPtDispatchA d = disp[(dispCount++) & 3]; + d.dontinline_brkpt(); // Dynamic call. Debugger publishes l1 to sharedCounter. + iResult = l1.inc(); // Changes by the 2nd thread will be observed if l1 + // was not relocked before passing it to the debugger. + } + } + + @Override + public int getExpectedIResult() { + return 1; + } +} + +///////////////////////////////////////////////////////////////////////////// + // Test recursive locking class EARelockingRecursiveTarget extends EATestCaseBaseTarget { From edf7f055ee010a2c19bce26c15726d5b58e2e832 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 24 Jun 2024 07:14:57 +0000 Subject: [PATCH 017/288] 8334083: C2 SuperWord: TestCompatibleUseDefTypeSize.java fails with -XX:+AlignVector after JDK-8325155 Reviewed-by: chagedorn, kvn --- .../loopopts/superword/TestCompatibleUseDefTypeSize.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java index e1aa91369d473..43580f4dee246 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java @@ -359,6 +359,7 @@ static Object[] test2(byte[] src, char[] dst) { IRNode.ADD_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, // a[i] and a[i+1] cannot both be aligned. applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Used to not vectorize because of "alignment boundaries". // Assume 64 byte vector width: @@ -376,6 +377,7 @@ static Object[] test3(int[] a, int[] b) { IRNode.ADD_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, // a[i] and a[i+1] cannot both be aligned. applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // same as test3, but hand-unrolled static Object[] test4(int[] a, int[] b) { From 05a63d80b9c1e312512c707ccf6b255c16a9edf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 24 Jun 2024 07:51:01 +0000 Subject: [PATCH 018/288] 8334489: Add function os::used_memory Reviewed-by: eosterlund, dholmes, stuefe --- src/hotspot/share/runtime/os.cpp | 17 +++++++++++++++++ src/hotspot/share/runtime/os.hpp | 1 + 2 files changed, 18 insertions(+) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index bdf93e1d3b403..9860251fc3308 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -78,6 +78,10 @@ #include "utilities/macros.hpp" #include "utilities/powerOfTwo.hpp" +#ifdef LINUX +#include "osContainer_linux.hpp" +#endif + #ifndef _WINDOWS # include #endif @@ -2064,6 +2068,19 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { p2i(addr), p2i(addr) + bytes); } +julong os::used_memory() { +#ifdef LINUX + if (OSContainer::is_containerized()) { + jlong mem_usage = OSContainer::memory_usage_in_bytes(); + if (mem_usage > 0) { + return mem_usage; + } + } +#endif + return os::physical_memory() - os::available_memory(); +} + + bool os::commit_memory(char* addr, size_t bytes, bool executable) { assert_nonempty_range(addr, bytes); bool res = pd_commit_memory(addr, bytes, executable); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index ce7a07d4c43a0..f3f44ddb2e659 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -336,6 +336,7 @@ class os: AllStatic { // than "free" memory (`MemFree` in `/proc/meminfo`) because Linux can free memory // aggressively (e.g. clear caches) so that it becomes available. static julong available_memory(); + static julong used_memory(); static julong free_memory(); static jlong total_swap_space(); From 05ff3185edd25b381a97f6879f496e97b62dddc2 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 24 Jun 2024 08:46:10 +0000 Subject: [PATCH 019/288] 8334594: Generational ZGC: Deadlock after OopMap rewrites in 8331572 Reviewed-by: stefank, eosterlund, coleenp, zgu --- src/hotspot/share/gc/shared/gcVMOperations.cpp | 2 +- .../share/gc/shenandoah/shenandoahVMOperations.cpp | 2 +- src/hotspot/share/gc/x/xDriver.cpp | 2 +- src/hotspot/share/gc/z/zGeneration.cpp | 2 +- src/hotspot/share/interpreter/oopMapCache.cpp | 9 ++++++--- src/hotspot/share/interpreter/oopMapCache.hpp | 4 ++-- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index 4cf1a4ccbafd0..4cc75f4745991 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -132,7 +132,7 @@ bool VM_GC_Operation::doit_prologue() { void VM_GC_Operation::doit_epilogue() { // GC thread root traversal likely used OopMapCache a lot, which // might have created lots of old entries. Trigger the cleanup now. - OopMapCache::trigger_cleanup(); + OopMapCache::try_trigger_cleanup(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index af221550c69ab..9d2782502fefc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -44,7 +44,7 @@ void VM_ShenandoahOperation::doit_epilogue() { assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State was not synchronized to java threads."); // GC thread root traversal likely used OopMapCache a lot, which // might have created lots of old entries. Trigger the cleanup now. - OopMapCache::trigger_cleanup(); + OopMapCache::try_trigger_cleanup(); } bool VM_ShenandoahReferenceOperation::doit_prologue() { diff --git a/src/hotspot/share/gc/x/xDriver.cpp b/src/hotspot/share/gc/x/xDriver.cpp index c477f4a135c32..3e6fd03134e12 100644 --- a/src/hotspot/share/gc/x/xDriver.cpp +++ b/src/hotspot/share/gc/x/xDriver.cpp @@ -134,7 +134,7 @@ class VM_XOperation : public VM_Operation { // GC thread root traversal likely used OopMapCache a lot, which // might have created lots of old entries. Trigger the cleanup now. - OopMapCache::trigger_cleanup(); + OopMapCache::try_trigger_cleanup(); } bool gc_locked() const { diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 5c3afa9db8cc6..be86550d32171 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -456,7 +456,7 @@ class VM_ZOperation : public VM_Operation { // GC thread root traversal likely used OopMapCache a lot, which // might have created lots of old entries. Trigger the cleanup now. - OopMapCache::trigger_cleanup(); + OopMapCache::try_trigger_cleanup(); } bool success() const { diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index cae0efae9b26d..7b60e4869e368 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -592,10 +592,13 @@ bool OopMapCache::has_cleanup_work() { return Atomic::load(&_old_entries) != nullptr; } -void OopMapCache::trigger_cleanup() { - if (has_cleanup_work()) { - MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); +void OopMapCache::try_trigger_cleanup() { + // See we can take the lock for the notification without blocking. + // This allows triggering the cleanup from GC paths, that can hold + // the service lock for e.g. oop iteration in service thread. + if (has_cleanup_work() && Service_lock->try_lock_without_rank_check()) { Service_lock->notify_all(); + Service_lock->unlock(); } } diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 3c124631377ef..46c85f6e87985 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -183,8 +183,8 @@ class OopMapCache : public CHeapObj { // Check if we need to clean up old entries static bool has_cleanup_work(); - // Request cleanup if work is needed - static void trigger_cleanup(); + // Request cleanup if work is needed and notification is currently possible + static void try_trigger_cleanup(); // Clean up the old entries static void cleanup(); From ca5a438e5a4612c66f70c70a9d425eca0e49e84d Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 24 Jun 2024 08:58:02 +0000 Subject: [PATCH 020/288] 8334571: Extract control dependency rewiring out of PhaseIdealLoop::dominated_by() into separate method Reviewed-by: roland, kvn --- src/hotspot/share/opto/loopPredicate.cpp | 52 ++++++++++++++---------- src/hotspot/share/opto/loopnode.hpp | 4 +- src/hotspot/share/opto/loopopts.cpp | 39 ++++++++++-------- 3 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index bccc01a86ddb0..998d3a27178e1 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -1152,7 +1152,6 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl, ConNode* zero, Invariance& invar, Deoptimization::DeoptReason reason) { // Following are changed to nonnull when a predicate can be hoisted - IfProjNode* new_predicate_proj = nullptr; IfNode* iff = if_success_proj->in(0)->as_If(); Node* test = iff->in(1); if (!test->is_Bool()) { //Conv2B, ... @@ -1163,10 +1162,9 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod if (invar.is_invariant(bol)) { C->print_method(PHASE_BEFORE_LOOP_PREDICATION_IC, 4, iff); // Invariant test - new_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, - reason, - iff->Opcode()); - Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); + IfProjNode* hoisted_check_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, + iff->Opcode()); + Node* ctrl = hoisted_check_predicate_proj->in(0)->as_If()->in(0); BoolNode* hoisted_check_predicate_bool = invar.clone(bol, ctrl)->as_Bool(); // Negate test if necessary (Parse Predicates always have IfTrue as success projection and IfFalse as uncommon trap) @@ -1177,11 +1175,16 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod register_new_node(hoisted_check_predicate_bool, ctrl); negated = true; } - IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); + IfNode* new_predicate_iff = hoisted_check_predicate_proj->in(0)->as_If(); _igvn.hash_delete(new_predicate_iff); new_predicate_iff->set_req(1, hoisted_check_predicate_bool); - C->print_method(PHASE_AFTER_LOOP_PREDICATION_IC, 4, new_predicate_proj->in(0)); + invar.map_ctrl(if_success_proj, hoisted_check_predicate_proj); // Mark hoisted check as invariant + + // Eliminate the old If in the loop body. + dominated_by(hoisted_check_predicate_proj, iff, negated); + + C->print_method(PHASE_AFTER_LOOP_PREDICATION_IC, 4, hoisted_check_predicate_proj->in(0)); #ifndef PRODUCT if (TraceLoopPredicate) { @@ -1193,10 +1196,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod } #endif } else if (cl != nullptr && loop->is_range_check_if(if_success_proj, this, invar DEBUG_ONLY(COMMA parse_predicate_proj))) { - range_check_predicate = true; C->print_method(PHASE_BEFORE_LOOP_PREDICATION_RC, 4, iff); // Range check for counted loops assert(if_success_proj->is_IfTrue(), "trap must be on false projection for a range check"); + IfTrueNode* hoisted_check_proj = if_success_proj->as_IfTrue(); const Node* cmp = bol->in(1)->as_Cmp(); Node* idx = cmp->in(1); assert(!invar.is_invariant(idx), "index is variant"); @@ -1265,10 +1268,18 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod // Fall through into rest of the cleanup code which will move any dependent nodes to the skeleton predicates of the // upper bound test. We always need to create skeleton predicates in order to properly remove dead loops when later // splitting the predicated loop into (unreachable) sub-loops (i.e. done by unrolling, peeling, pre/main/post etc.). - new_predicate_proj = add_template_assertion_predicate(iff, loop, if_success_proj, parse_predicate_proj, upper_bound_proj, scale, - offset, init, limit, stride, rng, overflow, reason); + IfTrueNode* template_assertion_predicate_proj = + add_template_assertion_predicate(iff, loop, hoisted_check_proj, parse_predicate_proj, upper_bound_proj, scale, + offset, init, limit, stride, rng, overflow, reason); + + // Eliminate the old range check in the loop body. + // When a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2 + // Hoisted Check Predicates (one for the start of the loop, one for the end) but we can only keep track of one control + // dependency: pin the data dependent nodes. + eliminate_hoisted_range_check(hoisted_check_proj, template_assertion_predicate_proj); + invar.map_ctrl(hoisted_check_proj, template_assertion_predicate_proj); // Mark hoisted check as invariant - C->print_method(PHASE_AFTER_LOOP_PREDICATION_RC, 4, new_predicate_proj->in(0)); + C->print_method(PHASE_AFTER_LOOP_PREDICATION_RC, 4, template_assertion_predicate_proj->in(0)); #ifndef PRODUCT if (TraceLoopOpts && !TraceLoopPredicate) { @@ -1281,24 +1292,21 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod // with uncommon trap. return false; } - assert(new_predicate_proj != nullptr, "sanity"); - // Success - attach condition (new_predicate_bol) to predicate if - invar.map_ctrl(if_success_proj, new_predicate_proj); // so that invariance test can be appropriate - - // Eliminate the old If in the loop body - // If a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2 - // Hoisted Check Predicates (one for the start of the loop, one for the end) but we can only keep track of one control - // dependency: pin the data dependent nodes. - dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con, range_check_predicate); C->set_major_progress(); return true; } +void PhaseIdealLoop::eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, + IfTrueNode* template_assertion_predicate_proj) { + _igvn.replace_input_of(hoisted_check_proj->in(0), 1, _igvn.intcon(1)); + rewire_safe_outputs_to_dominator(hoisted_check_proj, template_assertion_predicate_proj, true); +} + // Each newly created Hoisted Check Predicate is accompanied by two Template Assertion Predicates. Later, we initialize // them by making a copy of them when splitting a loop into sub loops. The Assertion Predicates ensure that dead sub // loops are removed properly. -IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, +IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, ParsePredicateSuccessProj* parse_predicate_proj, IfProjNode* upper_bound_proj, const int scale, Node* offset, Node* init, Node* limit, const jint stride, @@ -1312,7 +1320,7 @@ IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, upper_bound_proj); - IfProjNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); + IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(opaque_init->outcnt() > 0, "should be used"); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 8d9d4b3e0e543..17145c825a420 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1377,10 +1377,11 @@ class PhaseIdealLoop : public PhaseTransform { void loop_predication_follow_branches(Node *c, IdealLoopTree *loop, float loop_trip_cnt, PathFrequency& pf, Node_Stack& stack, VectorSet& seen, Node_List& if_proj_list); - IfProjNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, + IfTrueNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, ParsePredicateSuccessProj* parse_predicate_proj, IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit, jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason); + void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj); Node* add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* predicate_proj, int scale_con, Node* offset, Node* limit, int stride_con, Node* value, bool is_template); @@ -1535,6 +1536,7 @@ class PhaseIdealLoop : public PhaseTransform { // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). void dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip = false, bool pin_array_access_nodes = false); + void rewire_safe_outputs_to_dominator(Node* source, Node* dominator, bool pin_array_access_nodes); // Split Node 'n' through merge point RegionNode* split_thru_region(Node* n, RegionNode* region); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 23b2edce6549a..182947e552e88 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -340,24 +340,31 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b // I can assume this path reaches an infinite loop. In this case it's not // important to optimize the data Nodes - either the whole compilation will // be tossed or this path (and all data Nodes) will go dead. - if (iff->outcnt() != 2) return; + if (iff->outcnt() != 2) { + return; + } // Make control-dependent data Nodes on the live path (path that will remain // once the dominated IF is removed) become control-dependent on the // dominating projection. Node* dp = iff->proj_out_or_null(pop == Op_IfTrue); - if (dp == nullptr) + if (dp == nullptr) { return; + } + + rewire_safe_outputs_to_dominator(dp, prevdom, pin_array_access_nodes); +} - IdealLoopTree* old_loop = get_loop(dp); +void PhaseIdealLoop::rewire_safe_outputs_to_dominator(Node* source, Node* dominator, const bool pin_array_access_nodes) { + IdealLoopTree* old_loop = get_loop(source); - for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { - Node* cd = dp->fast_out(i); // Control-dependent node + for (DUIterator_Fast imax, i = source->fast_outs(imax); i < imax; i++) { + Node* out = source->fast_out(i); // Control-dependent node // Do not rewire Div and Mod nodes which could have a zero divisor to avoid skipping their zero check. - if (cd->depends_only_on_test() && _igvn.no_dependent_zero_check(cd)) { - assert(cd->in(0) == dp, ""); - _igvn.replace_input_of(cd, 0, prevdom); + if (out->depends_only_on_test() && _igvn.no_dependent_zero_check(out)) { + assert(out->in(0) == source, "must be control dependent on source"); + _igvn.replace_input_of(out, 0, dominator); if (pin_array_access_nodes) { // Because of Loop Predication, Loads and range check Cast nodes that are control dependent on this range // check (that is about to be removed) now depend on multiple dominating Hoisted Check Predicates. After the @@ -365,21 +372,21 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b // in the graph. To ensure that these Loads/Casts do not float above any of the dominating checks (even when the // lowest dominating check is later replaced by yet another dominating check), we need to pin them at the lowest // dominating check. - Node* clone = cd->pin_array_access_node(); + Node* clone = out->pin_array_access_node(); if (clone != nullptr) { - clone = _igvn.register_new_node_with_optimizer(clone, cd); - _igvn.replace_node(cd, clone); - cd = clone; + clone = _igvn.register_new_node_with_optimizer(clone, out); + _igvn.replace_node(out, clone); + out = clone; } } - set_early_ctrl(cd, false); - IdealLoopTree* new_loop = get_loop(get_ctrl(cd)); + set_early_ctrl(out, false); + IdealLoopTree* new_loop = get_loop(get_ctrl(out)); if (old_loop != new_loop) { if (!old_loop->_child) { - old_loop->_body.yank(cd); + old_loop->_body.yank(out); } if (!new_loop->_child) { - new_loop->_body.push(cd); + new_loop->_body.push(out); } } --i; From 9d4a4bd2c2a4bd16bbc80b602b15b448c52220f6 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Mon, 24 Jun 2024 11:15:33 +0000 Subject: [PATCH 021/288] 8324841: PKCS11 tests still skip execution Reviewed-by: valeriep --- test/jdk/sun/security/pkcs11/PKCS11Test.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index ffd1c42fd88f4..2810040e376a6 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -791,8 +791,8 @@ private static Path findNSSLibrary(Path path, Path libraryName) throws IOExcepti (tp, attr) -> tp.getFileName().equals(libraryName))) { return files.findAny() - .orElseThrow(() -> new SkippedException( - "NSS library \"" + libraryName + "\" was not found in " + path)); + .orElseThrow(() -> + new RuntimeException("NSS library \"" + libraryName + "\" was not found in " + path)); } } From 2e64d15144be03388104c762816c1ba629da9639 Mon Sep 17 00:00:00 2001 From: Lutz Schmidt Date: Mon, 24 Jun 2024 11:27:18 +0000 Subject: [PATCH 022/288] 8334564: VM startup: fatal error: FLAG_SET_ERGO cannot be used to set an invalid value for NonNMethodCodeHeapSize Reviewed-by: mdoerr, kvn, stuefe --- src/hotspot/share/code/codeCache.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 20583ce492ddd..36656515942c3 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -227,6 +227,11 @@ void CodeCache::initialize_heaps() { if (!non_nmethod.set) { non_nmethod.size += compiler_buffer_size; + // Further down, just before FLAG_SET_ERGO(), all segment sizes are + // aligned down to the next lower multiple of min_size. For large page + // sizes, this may result in (non_nmethod.size == 0) which is not acceptable. + // Therefore, force non_nmethod.size to at least min_size. + non_nmethod.size = MAX2(non_nmethod.size, min_size); } if (!profiled.set && !non_profiled.set) { From 5ac2149b7bde947886533bf5996d977bb8ec66f1 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 24 Jun 2024 12:37:53 +0000 Subject: [PATCH 023/288] 8334299: Deprecate LockingMode option, along with LM_LEGACY and LM_MONITOR Reviewed-by: stuefe, dholmes --- src/hotspot/share/runtime/arguments.cpp | 1 + src/hotspot/share/runtime/globals.hpp | 6 +++--- .../jtreg/runtime/CommandLine/VMDeprecatedOptions.java | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0949e9e2aacac..f428403fa3002 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -505,6 +505,7 @@ static SpecialFlag const special_jvm_flags[] = { { "DontYieldALot", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "PreserveAllAnnotations", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "UseNotificationThread", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, + { "LockingMode", JDK_Version::jdk(24), JDK_Version::jdk(26), JDK_Version::jdk(27) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() }, diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index b8b9c846bb4d1..e4eb8d3e9e90c 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1957,9 +1957,9 @@ const int ObjectAlignmentInBytes = 8; "fence. Add cleanliness checks.") \ \ product(int, LockingMode, LM_LIGHTWEIGHT, \ - "Select locking mode: " \ - "0: monitors only (LM_MONITOR), " \ - "1: monitors & legacy stack-locking (LM_LEGACY), " \ + "(Deprecated) Select locking mode: " \ + "0: (Deprecated) monitors only (LM_MONITOR), " \ + "1: (Deprecated) monitors & legacy stack-locking (LM_LEGACY), " \ "2: monitors & new lightweight locking (LM_LIGHTWEIGHT, default)") \ range(0, 2) \ \ diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index 7904b01495fc7..4e6252ae20510 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -58,6 +58,7 @@ public class VMDeprecatedOptions { // deprecated non-alias flags: {"AllowRedefinitionToAddDeleteMethods", "true"}, {"ZGenerational", "false"}, + {"LockingMode", "1"}, // deprecated alias flags (see also aliased_jvm_flags): {"CreateMinidumpOnCrash", "false"} From e825ccfe6652577e4e828e8e4dfe19be0ea77813 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Mon, 24 Jun 2024 13:33:20 +0000 Subject: [PATCH 024/288] 8332362: Implement os::committed_in_range for MacOS and AIX Reviewed-by: stuefe --- src/hotspot/os/linux/os_linux.cpp | 75 --------------- src/hotspot/os/posix/os_posix.cpp | 91 +++++++++++++++++++ src/hotspot/share/runtime/os.cpp | 7 -- .../runtime/test_committed_virtualmemory.cpp | 43 +++++++++ .../Thread/TestAlwaysPreTouchStacks.java | 39 ++++++-- 5 files changed, 166 insertions(+), 89 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 52866a44b26c6..87150365ed576 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -3525,81 +3525,6 @@ static address get_stack_commited_bottom(address bottom, size_t size) { return nbot; } -bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { - int mincore_return_value; - const size_t stripe = 1024; // query this many pages each time - unsigned char vec[stripe + 1]; - // set a guard - vec[stripe] = 'X'; - - const size_t page_sz = os::vm_page_size(); - uintx pages = size / page_sz; - - assert(is_aligned(start, page_sz), "Start address must be page aligned"); - assert(is_aligned(size, page_sz), "Size must be page aligned"); - - committed_start = nullptr; - - int loops = checked_cast((pages + stripe - 1) / stripe); - int committed_pages = 0; - address loop_base = start; - bool found_range = false; - - for (int index = 0; index < loops && !found_range; index ++) { - assert(pages > 0, "Nothing to do"); - uintx pages_to_query = (pages >= stripe) ? stripe : pages; - pages -= pages_to_query; - - // Get stable read - while ((mincore_return_value = mincore(loop_base, pages_to_query * page_sz, vec)) == -1 && errno == EAGAIN); - - // During shutdown, some memory goes away without properly notifying NMT, - // E.g. ConcurrentGCThread/WatcherThread can exit without deleting thread object. - // Bailout and return as not committed for now. - if (mincore_return_value == -1 && errno == ENOMEM) { - return false; - } - - // If mincore is not supported. - if (mincore_return_value == -1 && errno == ENOSYS) { - return false; - } - - assert(vec[stripe] == 'X', "overflow guard"); - assert(mincore_return_value == 0, "Range must be valid"); - // Process this stripe - for (uintx vecIdx = 0; vecIdx < pages_to_query; vecIdx ++) { - if ((vec[vecIdx] & 0x01) == 0) { // not committed - // End of current contiguous region - if (committed_start != nullptr) { - found_range = true; - break; - } - } else { // committed - // Start of region - if (committed_start == nullptr) { - committed_start = loop_base + page_sz * vecIdx; - } - committed_pages ++; - } - } - - loop_base += pages_to_query * page_sz; - } - - if (committed_start != nullptr) { - assert(committed_pages > 0, "Must have committed region"); - assert(committed_pages <= int(size / page_sz), "Can not commit more than it has"); - assert(committed_start >= start && committed_start < start + size, "Out of range"); - committed_size = page_sz * committed_pages; - return true; - } else { - assert(committed_pages == 0, "Should not have committed region"); - return false; - } -} - - // Linux uses a growable mapping for the stack, and if the mapping for // the stack guard pages is not removed when we detach a thread the // stack cannot grow beyond the pages where the stack guard was diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1e7473eea1dc1..26bff6c8bd4e6 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -93,6 +93,9 @@ #define MAP_ANONYMOUS MAP_ANON #endif +/* Input/Output types for mincore(2) */ +typedef LINUX_ONLY(unsigned) char mincore_vec_t; + static jlong initial_time_count = 0; static int clock_tics_per_sec = 100; @@ -146,6 +149,94 @@ void os::check_dump_limit(char* buffer, size_t bufferSize) { VMError::record_coredump_status(buffer, success); } +bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { + +#ifdef _AIX + committed_start = start; + committed_size = size; + return true; +#else + + int mincore_return_value; + constexpr size_t stripe = 1024; // query this many pages each time + mincore_vec_t vec [stripe + 1]; + + // set a guard + DEBUG_ONLY(vec[stripe] = 'X'); + + size_t page_sz = os::vm_page_size(); + uintx pages = size / page_sz; + + assert(is_aligned(start, page_sz), "Start address must be page aligned"); + assert(is_aligned(size, page_sz), "Size must be page aligned"); + + committed_start = nullptr; + + int loops = checked_cast((pages + stripe - 1) / stripe); + int committed_pages = 0; + address loop_base = start; + bool found_range = false; + + for (int index = 0; index < loops && !found_range; index ++) { + assert(pages > 0, "Nothing to do"); + uintx pages_to_query = (pages >= stripe) ? stripe : pages; + pages -= pages_to_query; + + // Get stable read + int fail_count = 0; + while ((mincore_return_value = mincore(loop_base, pages_to_query * page_sz, vec)) == -1 && errno == EAGAIN){ + if (++fail_count == 1000){ + return false; + } + } + + // During shutdown, some memory goes away without properly notifying NMT, + // E.g. ConcurrentGCThread/WatcherThread can exit without deleting thread object. + // Bailout and return as not committed for now. + if (mincore_return_value == -1 && errno == ENOMEM) { + return false; + } + + // If mincore is not supported. + if (mincore_return_value == -1 && errno == ENOSYS) { + return false; + } + + assert(vec[stripe] == 'X', "overflow guard"); + assert(mincore_return_value == 0, "Range must be valid"); + // Process this stripe + for (uintx vecIdx = 0; vecIdx < pages_to_query; vecIdx ++) { + if ((vec[vecIdx] & 0x01) == 0) { // not committed + // End of current contiguous region + if (committed_start != nullptr) { + found_range = true; + break; + } + } else { // committed + // Start of region + if (committed_start == nullptr) { + committed_start = loop_base + page_sz * vecIdx; + } + committed_pages ++; + } + } + + loop_base += pages_to_query * page_sz; + } + + if (committed_start != nullptr) { + assert(committed_pages > 0, "Must have committed region"); + assert(committed_pages <= int(size / page_sz), "Can not commit more than it has"); + assert(committed_start >= start && committed_start < start + size, "Out of range"); + committed_size = page_sz * committed_pages; + return true; + } else { + assert(committed_pages == 0, "Should not have committed region"); + return false; + } +#endif +} + int os::get_native_stack(address* stack, int frames, int toSkip) { int frame_idx = 0; int num_of_frames; // number of frames captured diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 9860251fc3308..97bf33fbaaa7c 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -276,13 +276,6 @@ bool os::dll_build_name(char* buffer, size_t size, const char* fname) { return (n != -1); } -#if !defined(LINUX) && !defined(_WINDOWS) -bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) { - committed_start = start; - committed_size = size; - return true; -} -#endif // Helper for dll_locate_lib. // Pass buffer and printbuffer as we already printed the path to buffer diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index d4959cfa00854..2ffef1e211fdd 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -196,6 +196,42 @@ class CommittedVirtualMemoryTest { os::release_memory(base, size); } + + static void test_committed_in_range(size_t num_pages, size_t pages_to_touch) { + bool result; + size_t committed_size; + address committed_start; + size_t index; + + const size_t page_sz = os::vm_page_size(); + const size_t size = num_pages * page_sz; + + char* base = os::reserve_memory(size, !ExecMem, mtTest); + ASSERT_NE(base, (char*)nullptr); + + result = os::commit_memory(base, size, !ExecMem); + ASSERT_TRUE(result); + + result = os::committed_in_range((address)base, size, committed_start, committed_size); + ASSERT_FALSE(result); + + // Touch pages + for (index = 0; index < pages_to_touch; index ++) { + base[index * page_sz] = 'a'; + } + + result = os::committed_in_range((address)base, size, committed_start, committed_size); + ASSERT_TRUE(result); + ASSERT_EQ(pages_to_touch * page_sz, committed_size); + ASSERT_EQ(committed_start, (address)base); + + os::uncommit_memory(base, size, false); + + result = os::committed_in_range((address)base, size, committed_start, committed_size); + ASSERT_FALSE(result); + + os::release_memory(base, size); + } }; TEST_VM(CommittedVirtualMemoryTracker, test_committed_virtualmemory_region) { @@ -214,3 +250,10 @@ TEST_VM(CommittedVirtualMemoryTracker, test_committed_virtualmemory_region) { } } + +#if !defined(_WINDOWS) && !defined(_AIX) +TEST_VM(CommittedVirtualMemory, test_committed_in_range){ + CommittedVirtualMemoryTest::test_committed_in_range(1024, 1024); + CommittedVirtualMemoryTest::test_committed_in_range(2, 1); +} +#endif diff --git a/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java b/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java index b12eff0cf8454..f16e0ff9da4fd 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java +++ b/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022 SAP SE. All rights reserved. - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,14 +32,27 @@ import java.util.regex.Pattern; import java.util.concurrent.CyclicBarrier; +import static jdk.test.lib.Platform.isLinux; +import static jdk.test.lib.Platform.isWindows; + /* - * @test + * @test id=preTouch * @summary Test AlwaysPreTouchThreadStacks * @requires os.family != "aix" * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run driver TestAlwaysPreTouchStacks + * @run driver TestAlwaysPreTouchStacks preTouch + */ + +/* + * @test id=noPreTouch + * @summary Test that only touched committed memory is reported as thread stack usage. + * @requires os.family != "aix" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver TestAlwaysPreTouchStacks noPreTouch */ public class TestAlwaysPreTouchStacks { @@ -90,12 +103,22 @@ public static void main(String[] args) throws Exception { // should show up with fully - or almost fully - committed thread stacks. } else { + boolean preTouch; + if (args.length == 1 && args[0].equals("noPreTouch")){ + preTouch = false; + } else if (args.length == 1 && args[0].equals("preTouch")){ + preTouch = true; + } else { + throw new RuntimeException("Invalid test input. Must be 'preTouch' or 'noPreTouch'."); + } ArrayList vmArgs = new ArrayList<>(); Collections.addAll(vmArgs, "-XX:+UnlockDiagnosticVMOptions", "-Xmx100M", - "-XX:+AlwaysPreTouchStacks", "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics"); + if (preTouch){ + vmArgs.add("-XX:+AlwaysPreTouchStacks"); + } if (System.getProperty("os.name").contains("Linux")) { vmArgs.add("-XX:-UseMadvPopulateWrite"); } @@ -110,8 +133,8 @@ public static void main(String[] args) throws Exception { output.shouldContain("Alive: " + i); } - // We want to see, in the final NMT printout, a committed thread stack size very close to reserved - // stack size. Like this: + // If using -XX:+AlwaysPreTouchStacks, we want to see, in the final NMT printout, + // a committed thread stack size very close to reserved stack size. Like this: // - Thread (reserved=10332400KB, committed=10284360KB) // (thread #10021) // (stack: reserved=10301560KB, committed=10253520KB) <<<< @@ -135,8 +158,10 @@ public static void main(String[] args) throws Exception { // as thread stack. But without pre-touching, the thread stacks would be committed to about 1/5th // of their reserved size. Requiring them to be committed for over 3/4th shows that pretouch is // really working. - if ((double)committed < ((double)reserved * 0.75)) { + if (preTouch && (double)committed < ((double)reserved * 0.75)) { throw new RuntimeException("Expected a higher ratio between stack committed and reserved."); + } else if (!preTouch && (double)committed > ((double)reserved * 0.50)){ + throw new RuntimeException("Expected a lower ratio between stack committed and reserved."); } // Added sanity tests: we expect our test threads to be still alive when NMT prints its final // report, so their stacks should dominate the NMT-reported total stack size. From b2930c5aeedf911ec893734181c1af0573e222f4 Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Mon, 24 Jun 2024 13:34:29 +0000 Subject: [PATCH 025/288] 8334040: jdk/classfile/CorpusTest.java timed out Reviewed-by: alanb --- test/jdk/jdk/classfile/CorpusTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index 21e275a837d84..64db67e6d8eb0 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -117,7 +117,7 @@ public void writeBody(BufWriter b) { static Path[] corpus() throws IOException, URISyntaxException { splitTableAttributes("testdata/Pattern2.class", "testdata/Pattern2-split.class"); return Stream.of( - Files.walk(JRT.getPath("modules/java.base/java")), + Files.walk(JRT.getPath("modules/java.base/java/util")), Files.walk(JRT.getPath("modules"), 2).filter(p -> p.endsWith("module-info.class")), Files.walk(Paths.get(URI.create(CorpusTest.class.getResource("CorpusTest.class").toString())).getParent())) .flatMap(p -> p) @@ -140,6 +140,7 @@ void testNullAdaptations(Path path) throws Exception { for (Transforms.NoOpTransform m : Transforms.NoOpTransform.values()) { if (m == Transforms.NoOpTransform.ARRAYCOPY || m == Transforms.NoOpTransform.SHARED_3_NO_STACKMAP + || m == Transforms.NoOpTransform.CLASS_REMAPPER || m.name().startsWith("ASM")) continue; @@ -190,12 +191,8 @@ void testNullAdaptations(Path path) throws Exception { .collect(joining("\n")); fail(String.format("Errors in testNullAdapt: %s", msg)); } - } - @ParameterizedTest - @MethodSource("corpus") - void testReadAndTransform(Path path) throws IOException { - byte[] bytes = Files.readAllBytes(path); + // test read and transform var cc = ClassFile.of(); var classModel = cc.parse(bytes); assertEqualsDeep(ClassRecord.ofClassModel(classModel), ClassRecord.ofStreamingElements(classModel), From 55c796946158aab1d019a57b77a33441d7b13065 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 24 Jun 2024 14:36:50 +0000 Subject: [PATCH 026/288] 8334765: JFR: Log chunk waste Reviewed-by: mgronlun --- .../internal/consumer/filter/ChunkWriter.java | 29 ++++++++++++++++++- test/jdk/jdk/jfr/jvm/TestWaste.java | 4 +-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java index 8c22432512a1a..d38a5872adedb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ import java.nio.file.Path; import java.util.ArrayDeque; import java.util.Deque; +import java.util.Map; +import java.util.HashMap; import java.util.function.Predicate; import jdk.jfr.consumer.RecordedEvent; @@ -56,6 +58,7 @@ public final class ChunkWriter implements Closeable { private final RecordingInput input; private final RecordingOutput output; private final Predicate filter; + private final Map waste = new HashMap<>(); private long chunkStartPosition; private boolean chunkComplete; @@ -178,6 +181,16 @@ public void endChunk(ChunkHeader header) throws IOException { pools = new LongMap<>(); chunkComplete = true; lastCheckpoint = 0; + if (Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.DEBUG)) { + // Log largest waste first + waste.entrySet().stream() + .sorted((a, b) -> b.getValue().compareTo(a.getValue())) + .forEach(entry -> { + String msg = "Total chunk waste by " + entry.getKey() + ": " + entry.getValue() + " bytes."; + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.DEBUG, msg); + }); + } + waste.clear(); } private void writeMetadataEvent(ChunkHeader header) throws IOException { @@ -216,6 +229,20 @@ private void write(CheckpointEvent event, long delta) throws IOException { } } } + if (Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.DEBUG)) { + for (CheckpointPool pool : event.getPools()) { + for (PoolEntry pe : pool.getEntries()) { + if (!pe.isTouched()) { + String name = pe.getType().getName(); + long amount = pe.getEndPosition() - pe.getStartPosition(); + waste.merge(pe.getType().getName(), amount, Long::sum); + String msg = "Unreferenced constant ID " + pe.getId() + + " of type "+ name + " using " + amount + " bytes."; + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, msg); + } + } + } + } long endPosition = output.position(); long size = endPosition - startPosition; output.position(startPosition); diff --git a/test/jdk/jdk/jfr/jvm/TestWaste.java b/test/jdk/jdk/jfr/jvm/TestWaste.java index 0cc1010765eb6..afa2dda4ee12c 100644 --- a/test/jdk/jdk/jfr/jvm/TestWaste.java +++ b/test/jdk/jdk/jfr/jvm/TestWaste.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal.test - * @run main/othervm -XX:TLABSize=2k jdk.jfr.jvm.TestWaste + * @run main/othervm -Xlog:jfr+system+parser=debug -XX:TLABSize=2k jdk.jfr.jvm.TestWaste */ public class TestWaste { static List list = new LinkedList<>(); From 71a692ab435fdeea4ce8f8db7a55dd735c7c5016 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 24 Jun 2024 18:05:50 +0000 Subject: [PATCH 027/288] 8321033: Avoid casting Array to GrowableArray Reviewed-by: kbarrett, iklam, ccheung --- src/hotspot/share/classfile/moduleEntry.cpp | 33 +++++++++++---------- src/hotspot/share/classfile/moduleEntry.hpp | 23 +++++++++++++- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 78478d282c57d..e7f05bedb292a 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -149,7 +149,7 @@ bool ModuleEntry::can_read(ModuleEntry* m) const { if (!has_reads_list()) { return false; } else { - return _reads->contains(m); + return reads()->contains(m); } } @@ -164,9 +164,10 @@ void ModuleEntry::add_read(ModuleEntry* m) { if (m == nullptr) { set_can_read_all_unnamed(); } else { - if (_reads == nullptr) { + if (reads() == nullptr) { // Lazily create a module's reads list - _reads = new (mtModule) GrowableArray(MODULE_READS_SIZE, mtModule); + GrowableArray* new_reads = new (mtModule) GrowableArray(MODULE_READS_SIZE, mtModule); + set_reads(new_reads); } // Determine, based on this newly established read edge to module m, @@ -174,7 +175,7 @@ void ModuleEntry::add_read(ModuleEntry* m) { set_read_walk_required(m->loader_data()); // Establish readability to module m - _reads->append_if_missing(m); + reads()->append_if_missing(m); } } @@ -208,7 +209,7 @@ void ModuleEntry::set_is_open(bool is_open) { // module will return false. bool ModuleEntry::has_reads_list() const { assert_locked_or_safepoint(Module_lock); - return ((_reads != nullptr) && !_reads->is_empty()); + return ((reads() != nullptr) && !reads()->is_empty()); } // Purge dead module entries out of reads list. @@ -227,12 +228,12 @@ void ModuleEntry::purge_reads() { } // Go backwards because this removes entries that are dead. - int len = _reads->length(); + int len = reads()->length(); for (int idx = len - 1; idx >= 0; idx--) { - ModuleEntry* module_idx = _reads->at(idx); + ModuleEntry* module_idx = reads()->at(idx); ClassLoaderData* cld_idx = module_idx->loader_data(); if (cld_idx->is_unloading()) { - _reads->delete_at(idx); + reads()->delete_at(idx); } else { // Update the need to walk this module's reads based on live modules set_read_walk_required(cld_idx); @@ -246,15 +247,15 @@ void ModuleEntry::module_reads_do(ModuleClosure* f) { assert(f != nullptr, "invariant"); if (has_reads_list()) { - int reads_len = _reads->length(); - for (int i = 0; i < reads_len; ++i) { - f->do_module(_reads->at(i)); + int reads_len = reads()->length(); + for (ModuleEntry* m : *reads()) { + f->do_module(m); } } } void ModuleEntry::delete_reads() { - delete _reads; + delete reads(); _reads = nullptr; } @@ -272,7 +273,8 @@ ModuleEntry::ModuleEntry(Handle module_handle, _has_default_read_edges(false), _must_walk_reads(false), _is_open(is_open), - _is_patched(false) { + _is_patched(false) + DEBUG_ONLY(COMMA _reads_is_archived(false)) { // Initialize fields specific to a ModuleEntry if (_name == nullptr) { @@ -466,7 +468,7 @@ void ModuleEntry::iterate_symbols(MetaspaceClosure* closure) { } void ModuleEntry::init_as_archived_entry() { - Array* archived_reads = write_growable_array(_reads); + set_archived_reads(write_growable_array(reads())); _loader_data = nullptr; // re-init at runtime _shared_path_index = FileMapInfo::get_module_shared_path_index(_location); @@ -474,7 +476,6 @@ void ModuleEntry::init_as_archived_entry() { _name = ArchiveBuilder::get_buffered_symbol(_name); ArchivePtrMarker::mark_pointer((address*)&_name); } - _reads = (GrowableArray*)archived_reads; if (_version != nullptr) { _version = ArchiveBuilder::get_buffered_symbol(_version); } @@ -515,7 +516,7 @@ void ModuleEntry::verify_archived_module_entries() { void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) { assert(CDSConfig::is_using_archive(), "runtime only"); set_loader_data(loader_data); - _reads = restore_growable_array((Array*)_reads); + set_reads(restore_growable_array(archived_reads())); JFR_ONLY(INIT_ID(this);) } diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp index 62a0ba2a0b739..48adc41eddc71 100644 --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.hpp @@ -68,7 +68,11 @@ class ModuleEntry : public CHeapObj { // for shared classes from this module Symbol* _name; // name of this module ClassLoaderData* _loader_data; - GrowableArray* _reads; // list of modules that are readable by this module + + union { + GrowableArray* _reads; // list of modules that are readable by this module + Array* _archived_reads; // List of readable modules stored in the CDS archive + }; Symbol* _version; // module version number Symbol* _location; // module location CDS_ONLY(int _shared_path_index;) // >=0 if classes in this module are in CDS archive @@ -77,6 +81,7 @@ class ModuleEntry : public CHeapObj { bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules bool _is_open; // whether the packages in the module are all unqualifiedly exported bool _is_patched; // whether the module is patched via --patch-module + DEBUG_ONLY(bool _reads_is_archived); CDS_JAVA_HEAP_ONLY(int _archived_module_index;) JFR_ONLY(DEFINE_TRACE_ID_FIELD;) @@ -115,6 +120,22 @@ class ModuleEntry : public CHeapObj { bool can_read(ModuleEntry* m) const; bool has_reads_list() const; + GrowableArray* reads() const { + assert(!_reads_is_archived, "sanity"); + return _reads; + } + void set_reads(GrowableArray* r) { + _reads = r; + DEBUG_ONLY(_reads_is_archived = false); + } + Array* archived_reads() const { + assert(_reads_is_archived, "sanity"); + return _archived_reads; + } + void set_archived_reads(Array* r) { + _archived_reads = r; + DEBUG_ONLY(_reads_is_archived = true); + } void add_read(ModuleEntry* m); void set_read_walk_required(ClassLoaderData* m_loader_data); From 4b153e5e051c01ad8d0c3ff335352918c2970fe6 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 24 Jun 2024 18:19:03 +0000 Subject: [PATCH 028/288] 8306580: Propagate CDS dumping errors instead of directly exiting the VM Reviewed-by: iklam, ccheung --- src/hotspot/share/cds/archiveBuilder.cpp | 7 -- src/hotspot/share/cds/archiveBuilder.hpp | 3 - src/hotspot/share/cds/filemap.cpp | 5 +- src/hotspot/share/cds/metaspaceShared.cpp | 97 +++++++++++-------- src/hotspot/share/cds/metaspaceShared.hpp | 9 +- src/hotspot/share/runtime/threads.cpp | 2 +- .../jtreg/runtime/cds/StaticWritingError.java | 52 ++++++++++ 7 files changed, 119 insertions(+), 56 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/StaticWritingError.java diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 72e45a7998ce9..a87a3ff042dec 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1412,10 +1412,3 @@ void ArchiveBuilder::report_out_of_space(const char* name, size_t needed_bytes) log_error(cds)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name); MetaspaceShared::unrecoverable_writing_error(); } - - -#ifndef PRODUCT -void ArchiveBuilder::assert_is_vm_thread() { - assert(Thread::current()->is_VM_thread(), "ArchiveBuilder should be used only inside the VMThread"); -} -#endif diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index ad0302137f55e..c17090ee53d8f 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -343,8 +343,6 @@ class ArchiveBuilder : public StackObj { return to_offset_u4(offset); } - static void assert_is_vm_thread() PRODUCT_RETURN; - public: ArchiveBuilder(); ~ArchiveBuilder(); @@ -432,7 +430,6 @@ class ArchiveBuilder : public StackObj { } static ArchiveBuilder* current() { - assert_is_vm_thread(); assert(_current != nullptr, "ArchiveBuilder must be active"); return _current; } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 5b352b54e4b50..96c826fb67e82 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1406,7 +1406,8 @@ void FileMapInfo::open_for_write() { if (fd < 0) { log_error(cds)("Unable to create shared archive file %s: (%s).", _full_path, os::strerror(errno)); - MetaspaceShared::unrecoverable_writing_error(); + MetaspaceShared::writing_error(); + return; } _fd = fd; _file_open = true; @@ -1659,7 +1660,7 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { // If the shared archive is corrupted, close it and remove it. close(); remove(_full_path); - MetaspaceShared::unrecoverable_writing_error("Unable to write to shared archive file."); + MetaspaceShared::writing_error("Unable to write to shared archive file."); } _file_offset += nbytes; } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 30b240b27ca81..a5061fef567e3 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -444,6 +444,8 @@ void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread class VM_PopulateDumpSharedSpace : public VM_Operation { private: ArchiveHeapInfo _heap_info; + FileMapInfo* _map_info; + StaticArchiveBuilder& _builder; void dump_java_heap_objects(GrowableArray* klasses) NOT_CDS_JAVA_HEAP_RETURN; void dump_shared_symbol_table(GrowableArray* symbols) { @@ -454,11 +456,14 @@ class VM_PopulateDumpSharedSpace : public VM_Operation { public: - VM_PopulateDumpSharedSpace() : VM_Operation(), _heap_info() {} + VM_PopulateDumpSharedSpace(StaticArchiveBuilder& b) : + VM_Operation(), _heap_info(), _map_info(nullptr), _builder(b) {} bool skip_operation() const { return false; } VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } + ArchiveHeapInfo* heap_info() { return &_heap_info; } + FileMapInfo* map_info() const { return _map_info; } void doit(); // outline because gdb sucks bool allow_nested_vm_operations() const { return true; } }; // class VM_PopulateDumpSharedSpace @@ -515,22 +520,21 @@ void VM_PopulateDumpSharedSpace::doit() { MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); SystemDictionaryShared::check_excluded_classes(); - StaticArchiveBuilder builder; - builder.gather_source_objs(); - builder.reserve_buffer(); + _builder.gather_source_objs(); + _builder.reserve_buffer(); - CppVtables::dumptime_init(&builder); + CppVtables::dumptime_init(&_builder); - builder.sort_metadata_objs(); - builder.dump_rw_metadata(); - builder.dump_ro_metadata(); - builder.relocate_metaspaceobj_embedded_pointers(); + _builder.sort_metadata_objs(); + _builder.dump_rw_metadata(); + _builder.dump_ro_metadata(); + _builder.relocate_metaspaceobj_embedded_pointers(); - dump_java_heap_objects(builder.klasses()); - dump_shared_symbol_table(builder.symbols()); + dump_java_heap_objects(_builder.klasses()); + dump_shared_symbol_table(_builder.symbols()); log_info(cds)("Make classes shareable"); - builder.make_klasses_shareable(); + _builder.make_klasses_shareable(); char* serialized_data = dump_read_only_tables(); @@ -540,28 +544,13 @@ void VM_PopulateDumpSharedSpace::doit() { // We don't want to write these addresses into the archive. CppVtables::zero_archived_vtables(); - // relocate the data so that it can be mapped to MetaspaceShared::requested_base_address() - // without runtime relocation. - builder.relocate_to_requested(); - // Write the archive file const char* static_archive = CDSConfig::static_archive_path(); assert(static_archive != nullptr, "SharedArchiveFile not set?"); - FileMapInfo* mapinfo = new FileMapInfo(static_archive, true); - mapinfo->populate_header(MetaspaceShared::core_region_alignment()); - mapinfo->set_serialized_data(serialized_data); - mapinfo->set_cloned_vtables(CppVtables::vtables_serialized_base()); - mapinfo->open_for_write(); - builder.write_archive(mapinfo, &_heap_info); - - if (PrintSystemDictionaryAtExit) { - SystemDictionary::print(); - } - - if (AllowArchivingWithJavaAgent) { - log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " - "for testing purposes only and should not be used in a production environment"); - } + _map_info = new FileMapInfo(static_archive, true); + _map_info->populate_header(MetaspaceShared::core_region_alignment()); + _map_info->set_serialized_data(serialized_data); + _map_info->set_cloned_vtables(CppVtables::vtables_serialized_base()); } class CollectCLDClosure : public CLDClosure { @@ -663,21 +652,19 @@ void MetaspaceShared::prepare_for_dumping() { // Preload classes from a list, populate the shared spaces and dump to a // file. -void MetaspaceShared::preload_and_dump() { - EXCEPTION_MARK; +void MetaspaceShared::preload_and_dump(TRAPS) { ResourceMark rm(THREAD); - preload_and_dump_impl(THREAD); + StaticArchiveBuilder builder; + preload_and_dump_impl(builder, THREAD); if (HAS_PENDING_EXCEPTION) { if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " SIZE_FORMAT "M", MaxHeapSize/M); - CLEAR_PENDING_EXCEPTION; - MetaspaceShared::unrecoverable_writing_error(); + MetaspaceShared::writing_error(); } else { log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); - CLEAR_PENDING_EXCEPTION; - MetaspaceShared::unrecoverable_writing_error("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); + MetaspaceShared::writing_error("Unexpected exception, use -Xlog:cds,exceptions=trace for detail"); } } } @@ -768,7 +755,7 @@ void MetaspaceShared::preload_classes(TRAPS) { log_info(cds)("Loading classes to share: done."); } -void MetaspaceShared::preload_and_dump_impl(TRAPS) { +void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { preload_classes(CHECK); if (SharedArchiveConfigFile) { @@ -805,8 +792,30 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) { } #endif - VM_PopulateDumpSharedSpace op; + VM_PopulateDumpSharedSpace op(builder); VMThread::execute(&op); + + if (!write_static_archive(&builder, op.map_info(), op.heap_info())) { + THROW_MSG(vmSymbols::java_io_IOException(), "Encountered error while dumping"); + } +} + +bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info) { + // relocate the data so that it can be mapped to MetaspaceShared::requested_base_address() + // without runtime relocation. + builder->relocate_to_requested(); + + map_info->open_for_write(); + if (!map_info->is_open()) { + return false; + } + builder->write_archive(map_info, heap_info); + + if (AllowArchivingWithJavaAgent) { + log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " + "for testing purposes only and should not be used in a production environment"); + } + return true; } // Returns true if the class's status has changed. @@ -916,11 +925,17 @@ void MetaspaceShared::unrecoverable_loading_error(const char* message) { // This function is called when the JVM is unable to write the specified CDS archive due to an // unrecoverable error. void MetaspaceShared::unrecoverable_writing_error(const char* message) { + writing_error(message); + vm_direct_exit(1); +} + +// This function is called when the JVM is unable to write the specified CDS archive due to a +// an error. The error will be propagated +void MetaspaceShared::writing_error(const char* message) { log_error(cds)("An error has occurred while writing the shared archive file."); if (message != nullptr) { log_error(cds)("%s", message); } - vm_direct_exit(1); } void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 1fb6ae8814210..f26af21676a83 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -31,9 +31,12 @@ #include "oops/oop.hpp" #include "utilities/macros.hpp" +class ArchiveBuilder; +class ArchiveHeapInfo; class FileMapInfo; class outputStream; class SerializeClosure; +class StaticArchiveBuilder; template class GrowableArray; @@ -66,13 +69,13 @@ class MetaspaceShared : AllStatic { }; static void prepare_for_dumping() NOT_CDS_RETURN; - static void preload_and_dump() NOT_CDS_RETURN; + static void preload_and_dump(TRAPS) NOT_CDS_RETURN; #ifdef _LP64 static void adjust_heap_sizes_for_dumping() NOT_CDS_JAVA_HEAP_RETURN; #endif private: - static void preload_and_dump_impl(TRAPS) NOT_CDS_RETURN; + static void preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) NOT_CDS_RETURN; static void preload_classes(TRAPS) NOT_CDS_RETURN; public: @@ -105,6 +108,7 @@ class MetaspaceShared : AllStatic { static void unrecoverable_loading_error(const char* message = nullptr); static void unrecoverable_writing_error(const char* message = nullptr); + static void writing_error(const char* message = nullptr); static void serialize(SerializeClosure* sc) NOT_CDS_RETURN; @@ -166,6 +170,7 @@ class MetaspaceShared : AllStatic { private: static void read_extra_data(JavaThread* current, const char* filename) NOT_CDS_RETURN; + static bool write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info); static FileMapInfo* open_static_archive(); static FileMapInfo* open_dynamic_archive(); // use_requested_addr: If true (default), attempt to map at the address the diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 9800f85dfe44a..ea18ff3a00686 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -818,7 +818,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { #endif if (CDSConfig::is_dumping_static_archive()) { - MetaspaceShared::preload_and_dump(); + MetaspaceShared::preload_and_dump(CHECK_JNI_ERR); } if (log_is_enabled(Info, perf, class, link)) { diff --git a/test/hotspot/jtreg/runtime/cds/StaticWritingError.java b/test/hotspot/jtreg/runtime/cds/StaticWritingError.java new file mode 100644 index 0000000000000..1bb3e7e721d94 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/StaticWritingError.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8306580 + * @summary Test the writing error when archive file cannot be created + * @requires vm.cds + * @library /test/lib + * @run driver StaticWritingError + */ + +import java.io.File; +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; + +public class StaticWritingError { + public static void main(String[] args) throws Exception { + String directoryName = "nosuchdir"; + String archiveName = "staticWritingError.jsa"; + + // Perform static dump and attempt to write archive in unwritable directory + CDSOptions opts = (new CDSOptions()) + .addPrefix("-Xlog:cds") + .setArchiveName(directoryName + File.separator + archiveName); + OutputAnalyzer out = CDSTestUtils.createArchive(opts); + out.shouldHaveExitValue(1); + out.shouldContain("Unable to create shared archive file"); + out.shouldContain("Encountered error while dumping"); + } +} From 3a26bbcebc2f7d11b172f2b16192a3adefeb8111 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 25 Jun 2024 02:19:57 +0000 Subject: [PATCH 029/288] 8185429: [macos] After a modal dialog is closed, no window becomes active Reviewed-by: tr, dnguyen, serb --- .../macosx/classes/sun/lwawt/macosx/CPlatformWindow.java | 8 +++++++- test/jdk/ProblemList.txt | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 1be76db3acdf2..1bf77f5ee69b1 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.AWTAccessor.WindowAccessor; import sun.java2d.SurfaceData; +import sun.lwawt.LWKeyboardFocusManagerPeer; import sun.lwawt.LWLightweightFramePeer; import sun.lwawt.LWToolkit; import sun.lwawt.LWWindowPeer; @@ -1056,6 +1057,11 @@ public void setModalBlocked(boolean blocked) { } execute(ptr -> nativeSetEnabled(ptr, !blocked)); + + Window currFocus = LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow(); + if (!blocked && (target == currFocus)) { + requestWindowFocus(); + } checkBlockingAndOrder(); } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 546f95b0054b1..b3fb31dc789da 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -781,7 +781,6 @@ java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java 8068378 generic-all java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java 8162380 generic-all java/awt/image/VolatileImage/VolatileImageConfigurationTest.java 8171069 macosx-all,linux-all java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all -java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java 8185429 macosx-all java/awt/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all java/awt/print/PrinterJob/ScaledText/ScaledText.java 8231226 macosx-all java/awt/font/TextLayout/TestJustification.java 8250791 macosx-all From e527e1c32fcc7b2560cec540bcde930075ac284a Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 25 Jun 2024 03:26:18 +0000 Subject: [PATCH 030/288] 8334580: Deprecate no-arg constructor BasicSliderUI() for removal Reviewed-by: kcr, aivanov, iris, prr --- .../share/classes/javax/swing/plaf/basic/BasicSliderUI.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java index 7b94bedea0dcd..ad5cb9c9ab9d8 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java @@ -150,7 +150,10 @@ public class BasicSliderUI extends SliderUI{ /** * Constructs a {@code BasicSliderUI}. + * @deprecated This constructor was exposed erroneously and will be removed in a future release. + * Use {@link #BasicSliderUI(JSlider)} instead. */ + @Deprecated(since = "23", forRemoval = true) public BasicSliderUI() {} /** From 974dca80df71c5cbe492d1e8ca5cee76bcc79358 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 25 Jun 2024 05:06:33 +0000 Subject: [PATCH 031/288] 8334223: Make Arena MEMFLAGs immutable Reviewed-by: jsjolen, azafari, gziemski --- src/hotspot/share/compiler/compilerThread.cpp | 7 ++----- src/hotspot/share/memory/arena.cpp | 16 ++++++---------- src/hotspot/share/memory/arena.hpp | 13 +++++++------ src/hotspot/share/memory/resourceArea.cpp | 13 +------------ src/hotspot/share/memory/resourceArea.hpp | 8 ++------ src/hotspot/share/prims/jni.cpp | 6 +++--- src/hotspot/share/runtime/handles.hpp | 4 ++-- src/hotspot/share/runtime/javaThread.cpp | 16 +++++++--------- src/hotspot/share/runtime/javaThread.hpp | 8 +++++--- src/hotspot/share/runtime/javaThread.inline.hpp | 2 +- src/hotspot/share/runtime/thread.cpp | 6 +++--- src/hotspot/share/runtime/thread.hpp | 4 ++-- 12 files changed, 41 insertions(+), 62 deletions(-) diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index 47e3f5a6f499b..e212200a47c65 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +32,7 @@ // Create a CompilerThread CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) - : JavaThread(&CompilerThread::thread_entry) { + : JavaThread(&CompilerThread::thread_entry, 0, mtCompiler) { _env = nullptr; _log = nullptr; _task = nullptr; @@ -43,9 +43,6 @@ CompilerThread::CompilerThread(CompileQueue* queue, _compiler = nullptr; _arena_stat = CompilationMemoryStatistic::enabled() ? new ArenaStatCounter : nullptr; - // Compiler uses resource area for compilation, let's bias it to mtCompiler - resource_area()->bias_to(mtCompiler); - #ifndef PRODUCT _ideal_graph_printer = nullptr; #endif diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index 6faffe0d20b9c..0399c6922e38d 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -209,7 +209,12 @@ void Chunk::next_chop(Chunk* k) { k->_next = nullptr; } -Arena::Arena(MEMFLAGS flag, Tag tag, size_t init_size) : _flags(flag), _tag(tag), _size_in_bytes(0) { +Arena::Arena(MEMFLAGS flag, Tag tag, size_t init_size) : + _flags(flag), _tag(tag), + _size_in_bytes(0), + _first(nullptr), _chunk(nullptr), + _hwm(nullptr), _max(nullptr) +{ init_size = ARENA_ALIGN(init_size); _chunk = ChunkPool::allocate_chunk(init_size, AllocFailStrategy::EXIT_OOM); _first = _chunk; @@ -219,15 +224,6 @@ Arena::Arena(MEMFLAGS flag, Tag tag, size_t init_size) : _flags(flag), _tag(tag) set_size_in_bytes(init_size); } -Arena::Arena(MEMFLAGS flag, Tag tag) : _flags(flag), _tag(tag), _size_in_bytes(0) { - _chunk = ChunkPool::allocate_chunk(Chunk::init_size, AllocFailStrategy::EXIT_OOM); - _first = _chunk; - _hwm = _chunk->bottom(); // Save the cached hwm, max - _max = _chunk->top(); - MemTracker::record_new_arena(flag); - set_size_in_bytes(Chunk::init_size); -} - Arena::~Arena() { destruct_contents(); MemTracker::record_arena_free(_flags); diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index ed441eca85182..1ca8a78782541 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -94,21 +94,23 @@ class Arena : public CHeapObjBase { tag_node // C2 Node arena }; +private: + const MEMFLAGS _flags; // Memory tracking flags + const Tag _tag; + size_t _size_in_bytes; // Size of arena (used for native memory tracking) + protected: friend class HandleMark; friend class NoHandleMark; friend class VMStructs; - MEMFLAGS _flags; // Memory tracking flags - const Tag _tag; - uint32_t _init_size; Chunk* _first; // First chunk Chunk* _chunk; // current chunk char* _hwm; // High water mark char* _max; // and max in current chunk + // Get a new Chunk of at least size x void* grow(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); - size_t _size_in_bytes; // Size of arena (used for native memory tracking) void* internal_amalloc(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { assert(is_aligned(x, BytesPerWord), "misaligned size"); @@ -124,8 +126,7 @@ class Arena : public CHeapObjBase { public: // Start the chunk_pool cleaner task static void start_chunk_pool_cleaner_task(); - Arena(MEMFLAGS memflag, Tag tag = Tag::tag_other); - Arena(MEMFLAGS memflag, Tag tag, size_t init_size); + Arena(MEMFLAGS memflag, Tag tag = Tag::tag_other, size_t init_size = Chunk::init_size); ~Arena(); void destruct_contents(); char* hwm() const { return _hwm; } diff --git a/src/hotspot/share/memory/resourceArea.cpp b/src/hotspot/share/memory/resourceArea.cpp index 409460709e464..d5a7513ba19d2 100644 --- a/src/hotspot/share/memory/resourceArea.cpp +++ b/src/hotspot/share/memory/resourceArea.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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,17 +30,6 @@ #include "runtime/javaThread.hpp" #include "utilities/vmError.hpp" -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; - } -} - #ifdef ASSERT ResourceMark::ResourceMark(ResourceArea* area, Thread* thread) : diff --git a/src/hotspot/share/memory/resourceArea.hpp b/src/hotspot/share/memory/resourceArea.hpp index ba294e33effbb..5fd376068c5b3 100644 --- a/src/hotspot/share/memory/resourceArea.hpp +++ b/src/hotspot/share/memory/resourceArea.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,10 +60,6 @@ class ResourceArea: public Arena { char* allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); - // Bias this resource area to specific memory type - // (by default, ResourceArea is tagged as mtThread, per-thread general purpose storage) - void bias_to(MEMFLAGS flags); - DEBUG_ONLY(int nesting() const { return _nesting; }) // Capture the state of a ResourceArea needed by a ResourceMark for @@ -81,7 +77,7 @@ class ResourceArea: public Arena { _chunk(area->_chunk), _hwm(area->_hwm), _max(area->_max), - _size_in_bytes(area->_size_in_bytes) + _size_in_bytes(area->size_in_bytes()) DEBUG_ONLY(COMMA _nesting(area->_nesting)) {} }; diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index b6a4443a8c763..ae040d661380e 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 Red Hat, Inc. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 Red Hat, Inc. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -3775,7 +3775,7 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae // Create a thread and mark it as attaching so it will be skipped by the // ThreadsListEnumerator - see CR 6404306 - JavaThread* thread = new JavaThread(true); + JavaThread* thread = JavaThread::create_attaching_thread(); // Set correct safepoint info. The thread is going to call into Java when // initializing the Java level thread object. Hence, the correct state must diff --git a/src/hotspot/share/runtime/handles.hpp b/src/hotspot/share/runtime/handles.hpp index 7865d32bef20d..39e59cc1ef0ef 100644 --- a/src/hotspot/share/runtime/handles.hpp +++ b/src/hotspot/share/runtime/handles.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,7 +187,7 @@ class HandleArea: public Arena { HandleArea* _prev; // link to outer (older) area public: // Constructor - HandleArea(HandleArea* prev) : Arena(mtThread, Tag::tag_ha, Chunk::tiny_size) { + HandleArea(MEMFLAGS flags, HandleArea* prev) : Arena(flags, Tag::tag_ha, Chunk::tiny_size) { debug_only(_handle_mark_nesting = 0); debug_only(_no_handle_mark_nesting = 0); _prev = prev; diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 70bb47c213ca5..a3eef07ba0ac9 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -409,9 +409,9 @@ void JavaThread::check_for_valid_safepoint_state() { // A JavaThread is a normal Java thread -JavaThread::JavaThread() : +JavaThread::JavaThread(MEMFLAGS flags) : + Thread(flags), // Initialize fields - _on_thread_list(false), DEBUG_ONLY(_java_call_counter(0) COMMA) _entry_point(nullptr), @@ -525,13 +525,12 @@ JavaThread::JavaThread() : assert(deferred_card_mark().is_empty(), "Default MemRegion ctor"); } -JavaThread::JavaThread(bool is_attaching_via_jni) : JavaThread() { - if (is_attaching_via_jni) { - _jni_attach_state = _attaching_via_jni; - } +JavaThread* JavaThread::create_attaching_thread() { + JavaThread* jt = new JavaThread(); + jt->_jni_attach_state = _attaching_via_jni; + return jt; } - // interrupt support void JavaThread::interrupt() { @@ -634,8 +633,7 @@ void JavaThread::block_if_vm_exited() { } } -JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread() { - _jni_attach_state = _not_attaching_via_jni; +JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz, MEMFLAGS flags) : JavaThread(flags) { set_entry_point(entry_point); // Create the native thread itself. // %note runtime_23 diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 2541aaded00a3..755a8268864dd 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -478,11 +478,13 @@ class JavaThread: public Thread { public: // Constructor - JavaThread(); // delegating constructor - JavaThread(bool is_attaching_via_jni); // for main thread and JNI attached threads - JavaThread(ThreadFunction entry_point, size_t stack_size = 0); + JavaThread(MEMFLAGS flags = mtThread); // delegating constructor + JavaThread(ThreadFunction entry_point, size_t stack_size = 0, MEMFLAGS flags = mtThread); ~JavaThread(); + // Factory method to create a new JavaThread whose attach state is "is attaching" + static JavaThread* create_attaching_thread(); + #ifdef ASSERT // verify this JavaThread hasn't be published in the Threads::list yet void verify_not_published(); diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp index 7b1ad7e17e1cd..a51a30ae577c1 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index d98fcf6f664a2..e72077adabf3b 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -64,7 +64,7 @@ THREAD_LOCAL Thread* Thread::_thr_current = nullptr; DEBUG_ONLY(Thread* Thread::_starting_thread = nullptr;) -Thread::Thread() { +Thread::Thread(MEMFLAGS flags) { DEBUG_ONLY(_run_state = PRE_CALL_RUN;) @@ -78,9 +78,9 @@ Thread::Thread() { // allocated data structures set_osthread(nullptr); - set_resource_area(new (mtThread)ResourceArea()); + set_resource_area(new (flags) ResourceArea(flags)); DEBUG_ONLY(_current_resource_mark = nullptr;) - set_handle_area(new (mtThread) HandleArea(nullptr)); + set_handle_area(new (flags) HandleArea(flags, nullptr)); set_metadata_handles(new (mtClass) GrowableArray(30, mtClass)); set_last_handle_mark(nullptr); DEBUG_ONLY(_missed_ic_stub_refill_verifier = nullptr); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 44c845986f375..e9fee4d113aaa 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -277,7 +277,7 @@ class Thread: public ThreadShadow { // is waiting to lock public: // Constructor - Thread(); + Thread(MEMFLAGS flag = mtThread); virtual ~Thread() = 0; // Thread is abstract. // Manage Thread::current() From c30e040342c69a213bdff321fdcb0d27ff740489 Mon Sep 17 00:00:00 2001 From: Neethu Prasad Date: Tue, 25 Jun 2024 07:08:07 +0000 Subject: [PATCH 032/288] 8331911: Reconsider locking for recently disarmed nmethods Reviewed-by: shade, eosterlund --- src/hotspot/share/code/nmethod.cpp | 6 ++---- src/hotspot/share/gc/shared/barrierSetNMethod.cpp | 9 +++++++++ src/hotspot/share/gc/x/xBarrierSetNMethod.cpp | 10 ++++++++-- src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 11 +++++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2f4999dc4e366..ea56ee6129812 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -844,10 +844,8 @@ void nmethod::run_nmethod_entry_barrier() { // By calling this nmethod entry barrier, it plays along and acts // like any other nmethod found on the stack of a thread (fewer surprises). nmethod* nm = this; - if (bs_nm->is_armed(nm)) { - bool alive = bs_nm->nmethod_entry_barrier(nm); - assert(alive, "should be alive"); - } + bool alive = bs_nm->nmethod_entry_barrier(nm); + assert(alive, "should be alive"); } } diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 548e6b671eff0..79e3f47ed57bd 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -100,6 +100,12 @@ bool BarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } }; + if (!is_armed(nm)) { + // Some other thread got here first and healed the oops + // and disarmed the nmethod. No need to continue. + return true; + } + // If the nmethod is the only thing pointing to the oops, and we are using a // SATB GC, then it is important that this code marks them live. // Also, with concurrent GC, it is possible that frames in continuation stack @@ -172,6 +178,9 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { nmethod* nm = cb->as_nmethod(); BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + // Check for disarmed method here to avoid going into DeoptimizeNMethodBarriersALot code + // too often. nmethod_entry_barrier checks for disarmed status itself, + // but we have no visibility into whether the barrier acted or not. if (!bs_nm->is_armed(nm)) { return 0; } diff --git a/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp b/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp index 002d6bc00c5d7..3dc76463028b8 100644 --- a/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/x/xBarrierSetNMethod.cpp @@ -32,12 +32,18 @@ #include "runtime/threadWXSetters.inline.hpp" bool XBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { + if (!is_armed(nm)) { + // Some other thread got here first and healed the oops + // and disarmed the nmethod. No need to continue. + return true; + } + XLocker locker(XNMethod::lock_for_nmethod(nm)); log_trace(nmethod, barrier)("Entered critical zone for %p", nm); if (!is_armed(nm)) { - // Some other thread got here first and healed the oops - // and disarmed the nmethod. + // Some other thread managed to complete while we were + // waiting for lock. No need to continue. return true; } diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index 2c58b0155648a..b8ecc3eddd3cd 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -37,6 +37,13 @@ #include "runtime/threadWXSetters.inline.hpp" bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { + if (!is_armed(nm)) { + log_develop_trace(gc, nmethod)("nmethod: " PTR_FORMAT " visited by entry (disarmed before lock)", p2i(nm)); + // Some other thread got here first and healed the oops + // and disarmed the nmethod. No need to continue. + return true; + } + ZLocker locker(ZNMethod::lock_for_nmethod(nm)); log_trace(nmethod, barrier)("Entered critical zone for %p", nm); @@ -44,8 +51,8 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { if (!is_armed(nm)) { log_develop_trace(gc, nmethod)("nmethod: " PTR_FORMAT " visited by entry (disarmed)", p2i(nm)); - // Some other thread got here first and healed the oops - // and disarmed the nmethod. + // Some other thread managed to complete while we were + // waiting for lock. No need to continue. return true; } From baafa662a2f0706e4275a4fe0459ee6759369858 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 25 Jun 2024 09:12:09 +0000 Subject: [PATCH 033/288] 8334287: Man page update for jstatd deprecation Reviewed-by: alanb --- src/jdk.jstatd/share/man/jstatd.1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jdk.jstatd/share/man/jstatd.1 b/src/jdk.jstatd/share/man/jstatd.1 index 4bd90104624b1..f5d2f347b4530 100644 --- a/src/jdk.jstatd/share/man/jstatd.1 +++ b/src/jdk.jstatd/share/man/jstatd.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. .\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. .\" .\" This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,9 @@ jstatd - monitor the creation and termination of instrumented Java HotSpot VMs .SH SYNOPSIS .PP -\f[B]Note:\f[R] This command is experimental and unsupported. +\f[B]WARNING:\f[R] This command is experimental, unsupported, and +deprecated. +It will be removed in a future release. .PP \f[V]jstatd\f[R] [\f[I]options\f[R]] .TP From 75a2afacc8f5fdec53350b1cb66076cdfeae12f0 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Tue, 25 Jun 2024 12:21:46 +0000 Subject: [PATCH 034/288] 8248981: Specify list of standard message digest and mgf algorithms for RSASSA-PSS signature Reviewed-by: valeriep --- .../java/security/spec/ECGenParameterSpec.java | 6 +++--- .../java/security/spec/NamedParameterSpec.java | 14 +++++++------- .../java/security/spec/PSSParameterSpec.java | 17 ++++++++++++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/java/security/spec/ECGenParameterSpec.java b/src/java.base/share/classes/java/security/spec/ECGenParameterSpec.java index 522c7ff73310e..4d506726c9f66 100644 --- a/src/java.base/share/classes/java/security/spec/ECGenParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/ECGenParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,9 +45,9 @@ public class ECGenParameterSpec extends NamedParameterSpec { * of the provider whose implementation will be used. * * @param stdName the standard name of the to-be-generated EC - * domain parameters. See the ParameterSpec Names section in the + * domain parameters. See the ECGenParameterSpec section in the * + * "{@docRoot}/../specs/security/standard-names.html#ecgenparameterspec"> * Java Security Standard Algorithm Names Specification for * information about standard names. * @throws NullPointerException if {@code stdName} is null. diff --git a/src/java.base/share/classes/java/security/spec/NamedParameterSpec.java b/src/java.base/share/classes/java/security/spec/NamedParameterSpec.java index ab716d54c3017..296d353449bbc 100644 --- a/src/java.base/share/classes/java/security/spec/NamedParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/NamedParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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,10 +30,10 @@ * This class is used to specify any algorithm parameters that are determined * by a standard name. This class also holds constants for standard parameter * set names. The names of these constants exactly match the corresponding - * parameter set name. For example, NamedParameterSpec.X25519 represents the - * parameter set identified by the string "X25519". These strings are defined - * in the + * parameter set name. For example, {@code NamedParameterSpec.X25519} + * represents the parameter set identified by the string "X25519". These + * strings are defined in the * Java Security Standard Algorithm Names Specification. * * @since 11 @@ -77,9 +77,9 @@ public class NamedParameterSpec implements AlgorithmParameterSpec { * of the provider whose implementation will be used. * * @param stdName the standard name of the algorithm parameters. See the - * ParameterSpec Names section in the + * NamedParameterSpec section in the * + * "{@docRoot}/../specs/security/standard-names.html#namedparameterspec"> * Java Security Standard Algorithm Names Specification for * information about standard names. * diff --git a/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java b/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java index d6f051995998f..5c77089f1ca23 100644 --- a/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java +++ b/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,8 +118,19 @@ public class PSSParameterSpec implements AlgorithmParameterSpec { * mask generation function, parameters for mask generation * function, salt length, and trailer field values. * - * @param mdName the algorithm name of the hash function - * @param mgfName the algorithm name of the mask generation function + * @param mdName the algorithm name of the hash function. See the + * PSSParameterSpec section of the + * + * Java Security Standard Algorithm Names Specification + * for information about standard names for the hash function. + * @param mgfName the algorithm name of the mask generation function. + * See the PSSParameterSpec section of the + * + * Java Security Standard Algorithm Names Specification + * for information about standard names for the mask generation + * function. * @param mgfSpec the parameters for the mask generation function. * If null is specified, null will be returned by * getMGFParameters(). From cae94b268d633b0557a54e3b21eff60d7f0edc2d Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 25 Jun 2024 14:06:03 +0000 Subject: [PATCH 035/288] 8334397: RISC-V: verify perf of ReverseBytesS/US Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/riscv.ad | 31 +------- src/hotspot/cpu/riscv/riscv_b.ad | 4 +- .../openjdk/bench/java/lang/Characters.java | 24 +++++++ .../org/openjdk/bench/java/lang/Shorts.java | 70 +++++++++++++++++++ 4 files changed, 98 insertions(+), 31 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/Shorts.java diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 798caee7375d8..4ed449032d6e9 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1916,6 +1916,8 @@ bool Matcher::match_rule_supported(int opcode) { case Op_ReverseBytesI: case Op_ReverseBytesL: + case Op_ReverseBytesS: + case Op_ReverseBytesUS: case Op_RotateRight: case Op_RotateLeft: case Op_CountLeadingZerosI: @@ -7866,35 +7868,6 @@ instruct xorL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ ins_pipe(ialu_reg_imm); %} -// ============================================================================ -// BSWAP Instructions - -instruct bytes_reverse_unsigned_short(iRegINoSp dst, iRegIorL2I src) %{ - match(Set dst (ReverseBytesUS src)); - - ins_cost(ALU_COST * 5); - format %{ "revb_h_h_u $dst, $src\t#@bytes_reverse_unsigned_short" %} - - ins_encode %{ - __ revb_h_h_u(as_Register($dst$$reg), as_Register($src$$reg)); - %} - - ins_pipe(pipe_class_default); -%} - -instruct bytes_reverse_short(iRegINoSp dst, iRegIorL2I src) %{ - match(Set dst (ReverseBytesS src)); - - ins_cost(ALU_COST * 5); - format %{ "revb_h_h $dst, $src\t#@bytes_reverse_short" %} - - ins_encode %{ - __ revb_h_h(as_Register($dst$$reg), as_Register($src$$reg)); - %} - - ins_pipe(pipe_class_default); -%} - // ============================================================================ // MemBar Instruction diff --git a/src/hotspot/cpu/riscv/riscv_b.ad b/src/hotspot/cpu/riscv/riscv_b.ad index 9e78159d24fce..92e616a3063e1 100644 --- a/src/hotspot/cpu/riscv/riscv_b.ad +++ b/src/hotspot/cpu/riscv/riscv_b.ad @@ -206,13 +206,13 @@ instruct bytes_reverse_long_b(iRegLNoSp dst, iRegL src) %{ %} instruct bytes_reverse_unsigned_short_b(iRegINoSp dst, iRegIorL2I src) %{ - predicate(UseZbb); match(Set dst (ReverseBytesUS src)); ins_cost(ALU_COST * 2); format %{ "revb_h_h_u $dst, $src\t#@bytes_reverse_unsigned_short_b" %} ins_encode %{ + assert(UseZbb, "must be"); __ revb_h_h_u(as_Register($dst$$reg), as_Register($src$$reg)); %} @@ -220,13 +220,13 @@ instruct bytes_reverse_unsigned_short_b(iRegINoSp dst, iRegIorL2I src) %{ %} instruct bytes_reverse_short_b(iRegINoSp dst, iRegIorL2I src) %{ - predicate(UseZbb); match(Set dst (ReverseBytesS src)); ins_cost(ALU_COST * 2); format %{ "revb_h_h $dst, $src\t#@bytes_reverse_short_b" %} ins_encode %{ + assert(UseZbb, "must be"); __ revb_h_h(as_Register($dst$$reg), as_Register($src$$reg)); %} diff --git a/test/micro/org/openjdk/bench/java/lang/Characters.java b/test/micro/org/openjdk/bench/java/lang/Characters.java index 246b4f5ccc88e..eb12ad744573a 100644 --- a/test/micro/org/openjdk/bench/java/lang/Characters.java +++ b/test/micro/org/openjdk/bench/java/lang/Characters.java @@ -35,6 +35,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; +import java.util.Random; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @@ -48,6 +49,29 @@ public class Characters { @Param({"9", "65", "97", "223", "430"}) private int codePoint; + @Param("500") + private int size; + + private char[] chars; + private char[] res; + + @Setup + public void setup() { + Random r = new Random(0); + chars = new char[size]; + res = new char[size]; + for (int i = 0; i < size; i++) { + chars[i] = (char)r.nextInt(Character.MAX_VALUE + 1); + } + } + + @Benchmark + public void reverseBytes() { + for (int i = 0; i < size; i++) { + res[i] = Character.reverseBytes(chars[i]); + } + } + @Benchmark public boolean isDigit() { return Character.isDigit(codePoint); diff --git a/test/micro/org/openjdk/bench/java/lang/Shorts.java b/test/micro/org/openjdk/bench/java/lang/Shorts.java new file mode 100644 index 0000000000000..b11d07db8e0de --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/Shorts.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class Shorts { + + @Param("500") + private int size; + + private short[] shorts; + private short[] res; + + @Setup + public void setup() { + Random r = new Random(0); + shorts = new short[size]; + res = new short[size]; + for (int i = 0; i < size; i++) { + shorts[i] = (short)(r.nextInt(Character.MAX_VALUE + 1) + Short.MIN_VALUE); + } + } + + @Benchmark + public void reverseBytes() { + for (int i = 0; i < size; i++) { + res[i] = Short.reverseBytes(shorts[i]); + } + } +} From 6c6793307d4734409016943ae584726ac30d667e Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Tue, 25 Jun 2024 14:07:32 +0000 Subject: [PATCH 036/288] 8334899: Test runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java failed after JDK-8306580 Reviewed-by: iklam, dholmes --- .../appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java index 9238a832addcf..3bc7a4427f4c5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java @@ -69,7 +69,7 @@ public static void main(String[] args) throws Throwable { "-Dtest.with.exception=true", gcLog).shouldNotHaveExitValue(0) .shouldContain("Preload Warning: Cannot find jdk/internal/math/FDBigInteger") - .shouldContain("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); + .shouldContain("Unexpected exception, use -Xlog:cds,exceptions=trace for detail"); // 2. Test with OOM System.out.println("2. OOM during dump"); From 57f8b91e558e5b9ff9c2000b8f74e3a1988ead2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 25 Jun 2024 14:37:38 +0000 Subject: [PATCH 037/288] 8333658: NMT: Use an allocator with 4-byte pointers to save memory in NativeCallStackStorage Reviewed-by: stuefe, azafari --- src/hotspot/share/nmt/arrayWithFreeList.hpp | 106 ++++++++++++ .../share/nmt/nmtNativeCallStackStorage.cpp | 60 +++++++ .../share/nmt/nmtNativeCallStackStorage.hpp | 71 +++----- .../gtest/nmt/test_arrayWithFreeList.cpp | 153 ++++++++++++++++++ 4 files changed, 339 insertions(+), 51 deletions(-) create mode 100644 src/hotspot/share/nmt/arrayWithFreeList.hpp create mode 100644 src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp create mode 100644 test/hotspot/gtest/nmt/test_arrayWithFreeList.cpp diff --git a/src/hotspot/share/nmt/arrayWithFreeList.hpp b/src/hotspot/share/nmt/arrayWithFreeList.hpp new file mode 100644 index 0000000000000..90c348bbf7ccc --- /dev/null +++ b/src/hotspot/share/nmt/arrayWithFreeList.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + + */ + +#ifndef SHARE_NMT_ARRAYWITHFREELIST_HPP +#define SHARE_NMT_ARRAYWITHFREELIST_HPP + +#include "utilities/growableArray.hpp" +#include + +// A flat array of elements E, backed by C-heap, growing on-demand. It allows for +// returning arbitrary elements and keeps them in a freelist. Elements can be uniquely +// identified via array index. +template +class ArrayWithFreeList { + + // An E must be trivially copyable and destructible, but it may be constructed + // however it likes. + constexpr void static_assert_E_satisfies_type_requirements() const { + static_assert(std::is_trivially_copyable::value && std::is_trivially_destructible::value, "must be"); + } + +public: + using I = int32_t; + static constexpr const I nil = -1; + +private: + // A free list allocator element is either a link to the next free space + // or an actual element. + union BackingElement { + I link; + E e; + }; + + GrowableArrayCHeap _backing_storage; + I _free_start; + + bool is_in_bounds(I i) { + return i >= 0 && i < _backing_storage.length(); + } + +public: + NONCOPYABLE(ArrayWithFreeList); + + ArrayWithFreeList(int initial_capacity = 8) + : _backing_storage(initial_capacity), + _free_start(nil) {} + + template + I allocate(Args... args) { + static_assert_E_satisfies_type_requirements(); + BackingElement* be; + I i; + if (_free_start != nil) { + // Must point to already existing index + be = &_backing_storage.at(_free_start); + i = _free_start; + _free_start = be->link; + } else { + // There are no free elements, allocate a new one. + i = _backing_storage.append(BackingElement()); + be = _backing_storage.adr_at(i); + } + + ::new (be) E{args...}; + return i; + } + + void deallocate(I i) { + static_assert_E_satisfies_type_requirements(); + assert(i == nil || is_in_bounds(i), "out of bounds free"); + if (i == nil) return; + BackingElement& be_freed = _backing_storage.at(i); + be_freed.link = _free_start; + _free_start = i; + } + + E& at(I i) { + static_assert_E_satisfies_type_requirements(); + assert(i != nil, "null pointer dereference"); + assert(is_in_bounds(i), "out of bounds dereference"); + return _backing_storage.at(i).e; + } +}; + +#endif // SHARE_NMT_ARRAYWITHFREELIST_HPP diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp new file mode 100644 index 0000000000000..fd7a67a358e87 --- /dev/null +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "nmt/nmtNativeCallStackStorage.hpp" + +NativeCallStackStorage::StackIndex NativeCallStackStorage::put(const NativeCallStack& value) { + int bucket = value.calculate_hash() % _table_size; + TableEntryIndex link = _table[bucket]; + while (link != TableEntryStorage::nil) { + TableEntry& l = _entry_storage.at(link); + if (value.equals(get(l.stack))) { + return l.stack; + } + link = l.next; + } + int idx = _stacks.append(value); + StackIndex si{idx}; + TableEntryIndex new_link = _entry_storage.allocate(_table[bucket], si); + _table[bucket] = new_link; + return si; +} +NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_size) + : _table_size(table_size), + _table(nullptr), + _stacks(), + _is_detailed_mode(is_detailed_mode), + _fake_stack() { + if (_is_detailed_mode) { + _table = NEW_C_HEAP_ARRAY(TableEntryIndex, _table_size, mtNMT); + for (int i = 0; i < _table_size; i++) { + _table[i] = TableEntryStorage::nil; + } + } +} +NativeCallStackStorage::~NativeCallStackStorage() { + FREE_C_HEAP_ARRAY(LinkPtr, _table); +} diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 5f05e0c9304d6..1b09002028e53 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -25,8 +25,7 @@ #ifndef SHARE_NMT_NMTNATIVECALLSTACKSTORAGE_HPP #define SHARE_NMT_NMTNATIVECALLSTACKSTORAGE_HPP -#include "memory/allocation.hpp" -#include "memory/arena.hpp" +#include "nmt/arrayWithFreeList.hpp" #include "utilities/growableArray.hpp" #include "utilities/nativeCallStack.hpp" @@ -40,64 +39,41 @@ // - Have fast comparisons // - Have constant time access // We achieve this by using a closed hashtable for finding previously existing NCS:s and referring to them by an index that's smaller than a pointer. -class NativeCallStackStorage : public CHeapObj { +class NativeCallStackStorage : public CHeapObjBase { public: struct StackIndex { friend NativeCallStackStorage; - - private: - static constexpr const int32_t _invalid = -1; - int32_t _stack_index; - StackIndex(int32_t stack_index) - : _stack_index(stack_index) { - } - public: + static constexpr const int32_t invalid = -1; static bool equals(const StackIndex& a, const StackIndex& b) { return a._stack_index == b._stack_index; } bool is_invalid() { - return _stack_index == _invalid; - } - - StackIndex() - : _stack_index(_invalid) { + return _stack_index == invalid; } }; private: - struct Link : public ArenaObj { - Link* next; + struct TableEntry; + using TableEntryStorage = ArrayWithFreeList; + using TableEntryIndex = typename TableEntryStorage::I; + + TableEntryStorage _entry_storage; + + struct TableEntry { + TableEntryIndex next; StackIndex stack; - Link(Link* next, StackIndex v) - : next(next), - stack(v) { - } }; - StackIndex put(const NativeCallStack& value) { - int bucket = value.calculate_hash() % _table_size; - Link* link = _table[bucket]; - while (link != nullptr) { - if (value.equals(get(link->stack))) { - return link->stack; - } - link = link->next; - } - int idx = _stacks.append(value); - Link* new_link = new (&_arena) Link(_table[bucket], StackIndex(idx)); - _table[bucket] = new_link; - return new_link->stack; - } - // For storage of the Links - Arena _arena; + StackIndex put(const NativeCallStack& value); + // Pick a prime number of buckets. // 4099 gives a 50% probability of collisions at 76 stacks (as per birthday problem). static const constexpr int default_table_size = 4099; - int _table_size; - Link** _table; + const int _table_size; + TableEntryIndex* _table; GrowableArrayCHeap _stacks; const bool _is_detailed_mode; @@ -107,7 +83,7 @@ class NativeCallStackStorage : public CHeapObj { StackIndex push(const NativeCallStack& stack) { // Not in detailed mode, so not tracking stacks. if (!_is_detailed_mode) { - return StackIndex(); + return StackIndex{StackIndex::invalid}; } return put(stack); } @@ -119,16 +95,9 @@ class NativeCallStackStorage : public CHeapObj { return _stacks.at(si._stack_index); } - NativeCallStackStorage(bool is_detailed_mode, int table_size = default_table_size) - : _arena(mtNMT), _table_size(table_size), _table(nullptr), _stacks(), - _is_detailed_mode(is_detailed_mode), _fake_stack() { - if (_is_detailed_mode) { - _table = NEW_ARENA_ARRAY(&_arena, Link*, _table_size); - for (int i = 0; i < _table_size; i++) { - _table[i] = nullptr; - } - } - } + NativeCallStackStorage(bool is_detailed_mode, int table_size = default_table_size); + + ~NativeCallStackStorage(); }; #endif // SHARE_NMT_NMTNATIVECALLSTACKSTORAGE_HPP diff --git a/test/hotspot/gtest/nmt/test_arrayWithFreeList.cpp b/test/hotspot/gtest/nmt/test_arrayWithFreeList.cpp new file mode 100644 index 0000000000000..a2110e9e22e87 --- /dev/null +++ b/test/hotspot/gtest/nmt/test_arrayWithFreeList.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + + */ + +#include "precompiled.hpp" +#include "unittest.hpp" +#include "nmt/arrayWithFreeList.hpp" + +using A = ArrayWithFreeList; + +class ArrayWithFreeListTest : public testing::Test { +}; + +// A linked list which sets the allocator itself +template +struct LL { + struct Node; + using NodeAllocator = ArrayWithFreeList; + using NodePtr = typename NodeAllocator::I; + NodeAllocator alloc; + struct Node { + E e; + NodePtr next; + }; + + NodePtr start; + LL() + : start{NodeAllocator::nil} { + } + + void push(E e) { + NodePtr new_element = alloc.allocate(e, NodeAllocator::nil); + NodePtr& current = start; + if (current == NodeAllocator::nil) { + current = new_element; + return; + } + alloc.at(new_element).next = current; + current = new_element; + }; + + E pop() { + assert(start != NodeAllocator::nil, "must be"); + Node& n = alloc.at(start); + E e = n.e; + NodePtr next_start = n.next; + alloc.deallocate(start); + start = next_start; + return e; + } +}; + +// A linked list which is capable of having multiple different allocators. This is done through higher-kinded types. +// That's a very fancy word that means that a templated type like Foo can be passed around like only Foo at first +// and then be 'applied' to some E. Think of it like passing around a lambda or function pointer, but on a template level, +// where Foo is a function that can be called on some type with the return type being Foo. +template class Allocator> +struct LL2 { + struct Node; + using NodeAllocator = Allocator; + using NodePtr = typename NodeAllocator::I; + NodeAllocator alloc; + struct Node { + E e; + NodePtr next; + }; + + NodePtr start; + LL2() + : start(NodeAllocator::nil) { + } + + void push(E e) { + NodePtr new_element = alloc.allocate(e, NodeAllocator::nil); + NodePtr& current = start; + if (current == NodeAllocator::nil) { + current = new_element; + return; + } + alloc.at(new_element).next = current; + current = new_element; + }; + + E pop() { + assert(start != NodeAllocator::nil, "must be"); + Node& n = alloc.at(start); + E e = n.e; + NodePtr next_start = n.next; + alloc.deallocate(start); + start = next_start; + return e; + } +}; + +template +void test_with_list(List& list) { + list.push(1); + list.push(2); + EXPECT_EQ(2, list.pop()); + EXPECT_EQ(1, list.pop()); +} + +TEST_VM_F(ArrayWithFreeListTest, TestLinkedLists) { + { + LL list; + test_with_list(list); + } + { + LL2 list; + test_with_list(list); + } +} + +TEST_VM_F(ArrayWithFreeListTest, FreeingShouldReuseMemory) { + A alloc; + A::I i = alloc.allocate(1); + int* x = &alloc.at(i); + alloc.deallocate(i); + i = alloc.allocate(1); + int* y = &alloc.at(i); + EXPECT_EQ(x, y); +} + +TEST_VM_F(ArrayWithFreeListTest, FreeingInTheMiddleWorks) { + A alloc; + A::I i0 = alloc.allocate(0); + A::I i1 = alloc.allocate(0); + A::I i2 = alloc.allocate(0); + int* p1 = &alloc.at(i1); + alloc.deallocate(i1); + A::I i3 = alloc.allocate(0); + EXPECT_EQ(p1, &alloc.at(i3)); +} From 9c89f0861c1b6d25e1a7c3ac1add9a168d807788 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 25 Jun 2024 16:04:03 +0000 Subject: [PATCH 038/288] 8334421: assert(!oldbox->is_unbalanced()) failed: this should not be called for unbalanced region Reviewed-by: vlivanov, thartmann --- src/hotspot/share/opto/callnode.cpp | 20 ++ src/hotspot/share/opto/callnode.hpp | 4 + src/hotspot/share/opto/escape.cpp | 5 +- src/hotspot/share/opto/locknode.hpp | 6 +- src/hotspot/share/opto/macro.cpp | 2 +- ...oarsenedAndNotEscapedLocksElimination.java | 205 ++++++++++++++++++ 6 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 98837e5e046ad..6ac3d6e4c611c 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1950,6 +1950,22 @@ bool AbstractLockNode::find_unlocks_for_region(const RegionNode* region, LockNod } +// Check that all locks/unlocks associated with object come from balanced regions. +bool AbstractLockNode::is_balanced() { + Node* obj = obj_node(); + for (uint j = 0; j < obj->outcnt(); j++) { + Node* n = obj->raw_out(j); + if (n->is_AbstractLock() && + n->as_AbstractLock()->obj_node()->eqv_uncast(obj)) { + BoxLockNode* n_box = n->as_AbstractLock()->box_node()->as_BoxLock(); + if (n_box->is_unbalanced()) { + return false; + } + } + } + return true; +} + const char* AbstractLockNode::_kind_names[] = {"Regular", "NonEscObj", "Coarsened", "Nested"}; const char * AbstractLockNode::kind_as_string() const { @@ -2056,6 +2072,8 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { int unlocks = 0; if (Verbose) { tty->print_cr("=== Locks coarsening ==="); + tty->print("Obj: "); + obj_node()->dump(); } for (int i = 0; i < lock_ops.length(); i++) { AbstractLockNode* lock = lock_ops.at(i); @@ -2064,6 +2082,8 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { else unlocks++; if (Verbose) { + tty->print("Box %d: ", i); + box_node()->dump(); tty->print(" %d: ", i); lock->dump(); } diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index efa84850bb236..818640a6f6575 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -1154,6 +1154,10 @@ class AbstractLockNode: public CallNode { void set_coarsened() { _kind = Coarsened; set_eliminated_lock_counter(); } void set_nested() { _kind = Nested; set_eliminated_lock_counter(); } + // Check that all locks/unlocks associated with object come from balanced regions. + // They can become unbalanced after coarsening optimization or on OSR entry. + bool is_balanced(); + // locking does not modify its arguments virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase){ return false; } diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 8a80392d5c786..1338bb3c90901 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -3502,12 +3502,11 @@ bool ConnectionGraph::not_global_escape(Node *n) { // and locked code region (identified by BoxLockNode) is balanced: // all compiled code paths have corresponding Lock/Unlock pairs. bool ConnectionGraph::can_eliminate_lock(AbstractLockNode* alock) { - BoxLockNode* box = alock->box_node()->as_BoxLock(); - if (!box->is_unbalanced() && not_global_escape(alock->obj_node())) { + if (alock->is_balanced() && not_global_escape(alock->obj_node())) { if (EliminateNestedLocks) { // We can mark whole locking region as Local only when only // one object is used for locking. - box->set_local(); + alock->box_node()->as_BoxLock()->set_local(); } return true; } diff --git a/src/hotspot/share/opto/locknode.hpp b/src/hotspot/share/opto/locknode.hpp index 0a7e4bd4905c7..229dcb73292c1 100644 --- a/src/hotspot/share/opto/locknode.hpp +++ b/src/hotspot/share/opto/locknode.hpp @@ -44,7 +44,7 @@ class BoxLockNode : public Node { Eliminated // All lock/unlock in region were eliminated } _kind; -#ifdef ASSERT +#ifndef PRODUCT const char* _kind_name[6] = { "Regular", "Local", @@ -122,7 +122,9 @@ class BoxLockNode : public Node { #ifndef PRODUCT virtual void format( PhaseRegAlloc *, outputStream *st ) const; - virtual void dump_spec(outputStream *st) const { st->print(" Lock %d",_slot); } + virtual void dump_spec(outputStream *st) const { + st->print(" Lock slot: %d, Kind: %s", _slot, _kind_name[(int)_kind]); + } #endif }; diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 21dfacf9fe1ce..de804457a262d 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2045,7 +2045,7 @@ void PhaseMacroExpand::mark_eliminated_box(Node* box, Node* obj) { //-----------------------mark_eliminated_locking_nodes----------------------- void PhaseMacroExpand::mark_eliminated_locking_nodes(AbstractLockNode *alock) { - if (alock->box_node()->as_BoxLock()->is_unbalanced()) { + if (!alock->is_balanced()) { return; // Can't do any more elimination for this locking region } if (EliminateNestedLocks) { diff --git a/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java b/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java new file mode 100644 index 0000000000000..4b20ddc0033e1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8334421 + * @summary C2 incorrectly marks not-escaped locks for elimination after + * coarsened locks were eliminated and created unbalanced regions. + * @requires vm.compMode != "Xint" + * @run main/othervm -XX:-TieredCompilation TestCoarsenedAndNotEscapedLocksElimination + * @run main TestCoarsenedAndNotEscapedLocksElimination + */ + +import java.util.Vector; + +class TestVector extends Vector { + + TestVector() { + super(); + } + + TestVector(int initialCapacity) { + super(initialCapacity); + } + + TestVector(int initialCapacity, int capacityIncrement) { + super(initialCapacity, capacityIncrement); + } + + Object[] getElementData () { + return elementData; // access protected field + } +} + +public class TestCoarsenedAndNotEscapedLocksElimination { + + public static void main(String[] strArr) { + TestCoarsenedAndNotEscapedLocksElimination tc = new TestCoarsenedAndNotEscapedLocksElimination(); + String result = null; + for (int i = 0; i < 12000; ++i) { + result = tc.test(); + if (result != null) break; + } + System.out.println(result == null? "passed" : result); + } + + int [][] vector_types = { + {-1, -1}, + {0, -1}, + {1, -1}, + {2, -1}, + {1025, -1}, + {0, -2}, + {1, -2}, + {2, -2}, + {1025, -2}, + {0, 0}, + {1, 0}, + {2, 0}, + {1025, 0}, + {0, 1}, + {1, 1}, + {2, 1}, + {1025, 1}, + {0, 1025 }, + {1, 1025 }, + {2, 1025 }, + {1025, 1025 } + }; + + Object [] elems = { + null, + new Object(), + new Vector(), + new Object[0] + }; + + int cntr = 0, mode = 0; + + void reset() { + cntr = 0; + mode = 0; + } + + TestVector nextVector() { + if (cntr == vector_types.length) { + return null; + } else { + TestVector vect; + if (vector_types[cntr][0] < 0) { + vect = new TestVector(); + } else if (vector_types[cntr][1] == -2) { + vect = new TestVector(vector_types[cntr][0]); + } else { + vect = new TestVector(vector_types[cntr][0], vector_types[cntr][1]); + } + if (mode == 1) { + vect.addElement(null); + vect.addElement(new Object()); + vect.addElement(new Vector()); + vect.addElement(new Object[0]); + } else if (mode == 2) { + int cap = vect.capacity(); + vect.addElement(null); + for (int i = 0; i < cap; i++) { + vect.addElement(new Object()); + } + } + if (++mode == 3) { + mode = 0; + cntr++; + } + return vect; + } + } + + public String test() { + reset(); + TestVector vect = (TestVector)nextVector(); + while (vect != null) { + Object [] backup_array = new Object[vect.size()]; + System.arraycopy(vect.getElementData(),0,backup_array,0,vect.size()); + + int old_size = vect.size(); + vect.setSize(vect.size()); + if (vect.size() != old_size) { + return "Vector: "+vect+" size changed after setSize(size())"; + } + for (int i = 0; i < vect.size(); i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(size())"; + } + } + + old_size = vect.size(); + vect.setSize(vect.size()*2); + if (vect.size() != old_size*2) { + return "Vector: "+vect+" size incorrectly changed after setSize(size()*2)"; + } + for (int i = 0; i < old_size; i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(size()*2)"; + } + } + for (int i = old_size; i < old_size*2; i++) { + if (vect.elementAt(i) != null) { + return "Vector: "+vect+" : "+i+"th element not null after setSize(size()*2)"; + } + } + + old_size = vect.size(); + int old_cap = vect.capacity(); + vect.setSize(vect.capacity()+1); + if (vect.size() != old_cap+1) { + return "Vector: "+vect+" size incorrectly changed after setSize(capacity()+1)"; + } + for (int i = 0; i < old_size && i < backup_array.length; i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(capacity()+1)"; + } + } + for (int i = old_size; i < old_cap + 1; i++) { + if (vect.elementAt(i) != null) { + return "Vector: "+vect+" : "+i+"th element not null after setSize(capacity()+1)"; + } + } + + old_size = vect.size(); + vect.setSize(vect.size()/2); + if (vect.size() != old_size/2) { + return "Vector: "+vect+" size incorrectly changed after setSize(size()/2)"; + } + for (int i = 0; i < old_size/2 && i < backup_array.length; i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(size()/2)"; + } + } + + vect = nextVector(); + } + return null; + } + +} + From 7429c37e63ffd50884d91d8f583d409633bfb04d Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 25 Jun 2024 16:44:41 +0000 Subject: [PATCH 039/288] 8334598: Default classlist in JDK is not deterministic after JDK-8293980 Reviewed-by: ccheung, dholmes, stuefe, erikj --- make/GenerateLinkOptData.gmk | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/make/GenerateLinkOptData.gmk b/make/GenerateLinkOptData.gmk index 5052e4c0358c8..b6989042d6aed 100644 --- a/make/GenerateLinkOptData.gmk +++ b/make/GenerateLinkOptData.gmk @@ -62,14 +62,14 @@ ifeq ($(EXTERNAL_BUILDJDK), true) INTERIM_IMAGE_DIR := $(BUILD_JDK) endif -# These are needed for deterministic classlist: +# To make the classlist deterministic: # - The classlist can be influenced by locale. Always set it to en/US. -# - Run with -Xint, as the compiler can speculatively resolve constant pool entries. -# - ForkJoinPool parallelism can cause constant pool resolution to be non-deterministic. +# - Concurrency in the core libraries can cause constant pool resolution +# to be non-deterministic. Since the benefits of resolved CP references in the +# default classlist is minimal, let's filter out the '@cp' lines until we can +# find a proper solution. CLASSLIST_FILE_VM_OPTS = \ - -Duser.language=en -Duser.country=US \ - -Xint \ - -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 + -Duser.language=en -Duser.country=US # Save the stderr output of the command and print it along with stdout in case # something goes wrong. @@ -101,9 +101,10 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST exit $$exitcode \ ) $(GREP) -v HelloClasslist $@.raw.2 > $@.raw.3 + $(GREP) -v @cp $@.raw.3 > $@.raw.4 $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java \ -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ - build.tools.classlist.SortClasslist $@.raw.3 > $@ + build.tools.classlist.SortClasslist $@.raw.4 > $@ # The jli trace is created by the same recipe as classlist. By declaring these # dependencies, make will correctly rebuild both jli trace and classlist From 933eababf2b79586a911082af36fdcc41763c7b9 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 25 Jun 2024 17:10:20 +0000 Subject: [PATCH 040/288] 8334629: [BACKOUT] PhaseIdealLoop::conditional_move is too conservative Reviewed-by: epeter, thartmann, jkarthikeyan --- src/hotspot/share/opto/loopopts.cpp | 19 ++++-- test/hotspot/jtreg/ProblemList.txt | 1 + .../org/openjdk/bench/vm/compiler/CMove.java | 59 ------------------- 3 files changed, 14 insertions(+), 65 deletions(-) delete mode 100644 test/micro/org/openjdk/bench/vm/compiler/CMove.java diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 182947e552e88..ba0ce344122af 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -802,18 +802,25 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { // Avoid duplicated float compare. if (phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return nullptr; - // Ignore cost if CMOVE can be moved outside the loop. - if (used_inside_loop && cost >= ConditionalMoveLimit) { - return nullptr; + float infrequent_prob = PROB_UNLIKELY_MAG(3); + // Ignore cost and blocks frequency if CMOVE can be moved outside the loop. + if (used_inside_loop) { + if (cost >= ConditionalMoveLimit) return nullptr; // Too much goo + + // BlockLayoutByFrequency optimization moves infrequent branch + // from hot path. No point in CMOV'ing in such case (110 is used + // instead of 100 to take into account not exactness of float value). + if (BlockLayoutByFrequency) { + infrequent_prob = MAX2(infrequent_prob, (float)BlockLayoutMinDiamondPercentage/110.0f); + } } // Check for highly predictable branch. No point in CMOV'ing if // we are going to predict accurately all the time. - constexpr float infrequent_prob = PROB_UNLIKELY_MAG(2); if (C->use_cmove() && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) { //keep going - } else if (iff->_prob < infrequent_prob || iff->_prob > (1.0f - infrequent_prob)) { + } else if (iff->_prob < infrequent_prob || + iff->_prob > (1.0f - infrequent_prob)) return nullptr; - } // -------------- // Now replace all Phis with CMOV's diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 469a410e31d8e..254e621bfdd47 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -53,6 +53,7 @@ compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all +compiler/c2/irTests/TestIfMinMax.java 8334816 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/codecache/CheckLargePages.java 8332654 linux-x64 diff --git a/test/micro/org/openjdk/bench/vm/compiler/CMove.java b/test/micro/org/openjdk/bench/vm/compiler/CMove.java deleted file mode 100644 index 0f92a681c727d..0000000000000 --- a/test/micro/org/openjdk/bench/vm/compiler/CMove.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.openjdk.bench.vm.compiler; - -import java.util.concurrent.TimeUnit; -import java.util.random.RandomGeneratorFactory; -import org.openjdk.jmh.annotations.*; -import org.openjdk.jmh.infra.Blackhole; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 5, time = 1) -@Measurement(iterations = 5, time = 1) -@Fork(value = 1) -public class CMove { - static final int SIZE = 1000000; - - @Param({"0.003", "0.006", "0.01", "0.02", "0.03", "0.06", "0.1", "0.2", "0.3", "0.6"}) - double freq; - - boolean[] conds; - - @Setup(Level.Iteration) - public void setup() { - var r = RandomGeneratorFactory.getDefault().create(1); - conds = new boolean[SIZE]; - for (int i = 0; i < SIZE; i++) { - conds[i] = r.nextDouble() < freq; - } - } - - @Benchmark - public void run(Blackhole bh) { - for (int i = 0; i < conds.length; i++) { - bh.consume(conds[i] ? 2 : 1); - } - } -} \ No newline at end of file From f8bf470b773884911290fa6ce059f7cc13686186 Mon Sep 17 00:00:00 2001 From: Yude Lin Date: Tue, 25 Jun 2024 18:19:42 +0000 Subject: [PATCH 041/288] 8334810: Redo: Un-ProblemList LocaleProvidersRun and CalendarDataRegression 8268379: java/util/Locale/LocaleProvidersRun.java and sun/util/locale/provider/CalendarDataRegression.java timed out Reviewed-by: naoto, jlu --- test/jdk/ProblemList.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b3fb31dc789da..2bf83e8ea81e0 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -717,9 +717,6 @@ com/sun/jdi/InvokeHangTest.java 8218463 linux-al # jdk_util -java/util/Locale/LocaleProvidersRun.java 8268379 macosx-x64 -sun/util/locale/provider/CalendarDataRegression.java 8268379 macosx-x64 - ############################################################################ # jdk_instrument From 861aefcafacdc21459ef966307f52568e327fd49 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 25 Jun 2024 19:05:01 +0000 Subject: [PATCH 042/288] 8334418: Update IANA Language Subtag Registry to Version 2024-06-14 Reviewed-by: lancea, iris, srl, naoto --- .../share/data/lsrdata/language-subtag-registry.txt | 6 +++++- test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 512134311e485..3079d77ed8b14 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2024-05-16 +File-Date: 2024-06-14 %% Type: language Subtag: aa @@ -48009,7 +48009,9 @@ Type: variant Subtag: laukika Description: Classical Sanskrit Added: 2010-07-28 +Deprecated: 2024-06-08 Prefix: sa +Comments: Preferred tag is cls %% Type: variant Subtag: lemosin @@ -48385,9 +48387,11 @@ Type: variant Subtag: vaidika Description: Vedic Sanskrit Added: 2010-07-28 +Deprecated: 2024-06-08 Prefix: sa Comments: The most ancient dialect of Sanskrit used in verse and prose composed until about the 4th century B.C.E. +Comments: Preferred tag is vsn %% Type: variant Subtag: valbadia diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index 184e007becd9d..cb3d4dde914ba 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 8332424 + * 8327631 8332424 8334418 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2024-05-16) with Locale and Locale.LanguageRange + * (LSR Revision: 2024-06-14) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ From 86b0cf259fb3cbe3a1973151148e5d36c6a99d91 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 25 Jun 2024 19:05:22 +0000 Subject: [PATCH 043/288] 8334653: ISO 4217 Amendment 177 Update Reviewed-by: naoto --- .../sun/util/resources/CurrencyNames.properties | 4 +++- .../share/data/currency/CurrencyData.properties | 10 +++++----- test/jdk/java/util/Currency/CheckDataVersion.java | 4 ++-- test/jdk/java/util/Currency/CurrencyTest.java | 6 +++--- .../Currency/{tablea1.txt => ISO4217-list-one.txt} | 8 ++++---- test/jdk/java/util/Currency/ValidateISO4217.java | 11 ++++++----- 6 files changed, 23 insertions(+), 20 deletions(-) rename test/jdk/java/util/Currency/{tablea1.txt => ISO4217-list-one.txt} (97%) diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 3cbbf15ed0252..7e6acccf6e5a9 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -287,6 +287,7 @@ ZAR=ZAR ZMK=ZMK ZMW=ZMW ZWD=ZWD +ZWG=ZWG ZWL=ZWL ZWN=ZWN ZWR=ZWR @@ -512,5 +513,6 @@ yum=Yugoslavian New Dinar (1994-2002) zar=South African Rand zmk=Zambian Kwacha zwd=Zimbabwean Dollar (1980-2008) +zwg=Zimbabwe Gold zwl=Zimbabwean Dollar (2009) zwr=Zimbabwean Dollar (2008) diff --git a/src/java.base/share/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties index 1661b4cccbaa4..5a28abccd00d2 100644 --- a/src/java.base/share/data/currency/CurrencyData.properties +++ b/src/java.base/share/data/currency/CurrencyData.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. # 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,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=176 +dataVersion=177 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -56,8 +56,8 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ XBB956-XBC957-XBD958-XCD951-XCG532-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ - XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWL932-\ - ZWN942-ZWR935 + XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWG924-\ + ZWL932-ZWN942-ZWR935 # Mappings from ISO 3166 country codes to ISO 4217 currency codes. @@ -582,7 +582,7 @@ YE=YER # ZAMBIA ZM=ZMW # ZIMBABWE -ZW=ZWL +ZW=ZWG # List of currencies with non-2digit decimals for minor units, diff --git a/test/jdk/java/util/Currency/CheckDataVersion.java b/test/jdk/java/util/Currency/CheckDataVersion.java index ba18677dbbe06..303603c5b85e2 100644 --- a/test/jdk/java/util/Currency/CheckDataVersion.java +++ b/test/jdk/java/util/Currency/CheckDataVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import java.util.Currency; class CheckDataVersion { - static final String datafile = "tablea1.txt"; + static final String datafile = "ISO4217-list-one.txt"; static final String FILEVERSIONKEY = "FILEVERSION="; static final String DATAVERSIONKEY = "DATAVERSION="; static String fileVersion; diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index 495de30e821f4..c8dfb5013bd52 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143 - * 8264792 + * 8264792 8334653 * @summary Basic tests for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -59,7 +59,7 @@ public class CurrencyTest { - // 'tablea1.txt' should be up-to-date before testing + // 'ISO4217-list-one.txt' should be up-to-date before testing @Test public void dataVersionTest() { CheckDataVersion.check(); diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/ISO4217-list-one.txt similarity index 97% rename from test/jdk/java/util/Currency/tablea1.txt rename to test/jdk/java/util/Currency/ISO4217-list-one.txt index 6e85de5e6d2b7..1912b5cc7dbb9 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/ISO4217-list-one.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 176 -# (As of 06 December 2023) +# Amendments up until ISO 4217 AMENDMENT NUMBER 177 +# (As of 20 June 2024) # # Version FILEVERSION=3 -DATAVERSION=176 +DATAVERSION=177 # ISO 4217 currency data AF AFN 971 2 @@ -276,7 +276,7 @@ WF XPF 953 0 EH MAD 504 2 YE YER 886 2 ZM ZMW 967 2 -ZW ZWL 932 2 +ZW ZWG 924 2 #XAU XAU 959 #XBA XBA 955 #XBB XBB 956 diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index 53788c899b342..cd6e4f41a9f06 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 + * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 8334653 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -60,7 +60,8 @@ /** * This class tests the latest ISO 4217 data and Java's currency data which is - * based on ISO 4217. The golden-data file (ISO 4217 data) 'tablea1.txt' has the following + * based on ISO 4217. The golden-data file, 'ISO4217-list-one.txt', based on the + * “List one: Currency, fund and precious metal codes” has the following * format: \t\t\t[\t\t\t\t] * The Cutover Date is given in SimpleDateFormat's 'yyyy-MM-dd-HH-mm-ss' format in the GMT time zone. */ @@ -68,7 +69,7 @@ public class ValidateISO4217 { // Input golden-data file private static final File dataFile = new File(System.getProperty( - "test.src", "."), "tablea1.txt"); + "test.src", "."), "ISO4217-list-one.txt"); // Code statuses private static final byte UNDEFINED = 0; private static final byte DEFINED = 1; @@ -89,7 +90,7 @@ public class ValidateISO4217 { + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-HRK-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" - + "YUM-ZMK-ZWD-ZWN-ZWR"; + + "YUM-ZMK-ZWD-ZWL-ZWN-ZWR"; private static final String[][] extraCodes = { /* Defined in ISO 4217 list, but don't have code and minor unit info. */ {"AQ", "", "", "0"}, // Antarctica From b3bf31a0a08da679ec2fd21613243fb17b1135a9 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 25 Jun 2024 19:50:58 +0000 Subject: [PATCH 044/288] 8333542: Breakpoint in parallel code does not work Co-authored-by: Chris Plummer Reviewed-by: dholmes, vlivanov --- src/hotspot/share/classfile/javaClasses.cpp | 26 +++ src/hotspot/share/classfile/javaClasses.hpp | 8 +- src/hotspot/share/classfile/vmSymbols.hpp | 1 + .../share/interpreter/linkResolver.cpp | 2 +- src/hotspot/share/oops/cpCache.cpp | 45 +++- src/hotspot/share/oops/instanceKlass.cpp | 209 ++++++++---------- src/hotspot/share/oops/instanceKlass.hpp | 64 +++--- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- src/hotspot/share/runtime/synchronizer.cpp | 10 + src/hotspot/share/runtime/synchronizer.hpp | 6 + src/hotspot/share/runtime/vframe.cpp | 5 +- src/hotspot/share/runtime/vmStructs.cpp | 2 +- src/hotspot/share/services/heapDumper.cpp | 16 ++ .../sun/jvm/hotspot/oops/InstanceKlass.java | 5 - .../TestThreadDumpClassInitMonitor.java | 7 +- .../com/sun/jdi/BreakpointOnClassPrepare.java | 156 +++++++++++++ 16 files changed, 387 insertions(+), 177 deletions(-) create mode 100644 test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 5a3fe239324ea..4d3aac1598e01 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -788,6 +788,7 @@ int java_lang_Class::_class_loader_offset; int java_lang_Class::_module_offset; int java_lang_Class::_protection_domain_offset; int java_lang_Class::_component_mirror_offset; +int java_lang_Class::_init_lock_offset; int java_lang_Class::_signers_offset; int java_lang_Class::_name_offset; int java_lang_Class::_source_file_offset; @@ -911,6 +912,12 @@ void java_lang_Class::initialize_mirror_fields(Klass* k, Handle protection_domain, Handle classData, TRAPS) { + // Allocate a simple java object for a lock. + // This needs to be a java object because during class initialization + // it can be held across a java call. + typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK); + set_init_lock(mirror(), r); + // Set protection domain also set_protection_domain(mirror(), protection_domain()); @@ -1132,6 +1139,10 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, if (!k->is_array_klass()) { // - local static final fields with initial values were initialized at dump time + // create the init_lock + typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_(false)); + set_init_lock(mirror(), r); + if (protection_domain.not_null()) { set_protection_domain(mirror(), protection_domain()); } @@ -1196,6 +1207,15 @@ oop java_lang_Class::component_mirror(oop java_class) { return java_class->obj_field(_component_mirror_offset); } +oop java_lang_Class::init_lock(oop java_class) { + assert(_init_lock_offset != 0, "must be set"); + return java_class->obj_field(_init_lock_offset); +} +void java_lang_Class::set_init_lock(oop java_class, oop init_lock) { + assert(_init_lock_offset != 0, "must be set"); + java_class->obj_field_put(_init_lock_offset, init_lock); +} + objArrayOop java_lang_Class::signers(oop java_class) { assert(_signers_offset != 0, "must be set"); return (objArrayOop)java_class->obj_field(_signers_offset); @@ -1415,12 +1435,18 @@ void java_lang_Class::compute_offsets() { InstanceKlass* k = vmClasses::Class_klass(); CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET); + // Init lock is a C union with component_mirror. Only instanceKlass mirrors have + // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops + // GC treats them the same. + _init_lock_offset = _component_mirror_offset; + CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } #if INCLUDE_CDS void java_lang_Class::serialize_offsets(SerializeClosure* f) { f->do_bool(&_offsets_computed); + f->do_u4((u4*)&_init_lock_offset); CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index e3bb453ae0ae4..90095545110d1 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -226,6 +226,7 @@ class java_lang_Class : AllStatic { static int _static_oop_field_count_offset; static int _protection_domain_offset; + static int _init_lock_offset; static int _signers_offset; static int _class_loader_offset; static int _module_offset; @@ -240,6 +241,7 @@ class java_lang_Class : AllStatic { static GrowableArray* _fixup_mirror_list; static GrowableArray* _fixup_module_field_list; + static void set_init_lock(oop java_class, oop init_lock); static void set_protection_domain(oop java_class, oop protection_domain); static void set_class_loader(oop java_class, oop class_loader); static void set_component_mirror(oop java_class, oop comp_mirror); @@ -292,6 +294,10 @@ class java_lang_Class : AllStatic { // Support for embedded per-class oops static oop protection_domain(oop java_class); + static oop init_lock(oop java_class); + static void clear_init_lock(oop java_class) { + set_init_lock(java_class, nullptr); + } static oop component_mirror(oop java_class); static objArrayOop signers(oop java_class); static void set_signers(oop java_class, objArrayOop signers); diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 39340243bc4b8..8d1ae20eac07c 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -557,6 +557,7 @@ class SerializeClosure; template(bool_array_signature, "[Z") \ template(byte_array_signature, "[B") \ template(char_array_signature, "[C") \ + template(int_array_signature, "[I") \ template(runnable_signature, "Ljava/lang/Runnable;") \ template(continuation_signature, "Ljdk/internal/vm/Continuation;") \ template(continuationscope_signature, "Ljdk/internal/vm/ContinuationScope;") \ diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 1fe715f975712..2c7decfa714a2 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -1824,7 +1824,7 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan // the interpreter or runtime performs a serialized check of // the relevant ResolvedIndyEntry::method field. This is done by the caller // of this method, via CPC::set_dynamic_call, which uses - // a lock to do the final serialization of updates + // an ObjectLocker to do the final serialization of updates // to ResolvedIndyEntry state, including method. // Log dynamic info to CDS classlist. diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index c16ba3b76f77a..95c3b8edaf5e1 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -56,6 +56,7 @@ #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/vm_version.hpp" #include "utilities/macros.hpp" @@ -174,7 +175,7 @@ void ConstantPoolCache::set_direct_or_vtable_call(Bytecodes::Code invoke_code, } if (invoke_code == Bytecodes::_invokestatic) { assert(method->method_holder()->is_initialized() || - method->method_holder()->is_init_thread(JavaThread::current()), + method->method_holder()->is_reentrant_initialization(JavaThread::current()), "invalid class initialization state for invoke_static"); if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { @@ -269,11 +270,20 @@ ResolvedMethodEntry* ConstantPoolCache::set_method_handle(int method_index, cons // A losing writer waits on the lock until the winner writes the method and leaves // the lock, so that when the losing writer returns, he can use the linked // cache entry. + // Lock fields to write Bytecodes::Code invoke_code = Bytecodes::_invokehandle; - MutexLocker ml(constant_pool()->pool_holder()->init_monitor()); - ResolvedMethodEntry* method_entry = resolved_method_entry_at(method_index); + JavaThread* current = JavaThread::current(); + objArrayHandle resolved_references(current, constant_pool()->resolved_references()); + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + assert(resolved_references() != nullptr, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, current); + + ResolvedMethodEntry* method_entry = resolved_method_entry_at(method_index); if (method_entry->is_resolved(invoke_code)) { return method_entry; } @@ -311,7 +321,6 @@ ResolvedMethodEntry* ConstantPoolCache::set_method_handle(int method_index, cons // Store appendix, if any. if (has_appendix) { const int appendix_index = method_entry->resolved_references_index(); - objArrayOop resolved_references = constant_pool()->resolved_references(); assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob"); assert(resolved_references->obj_at(appendix_index) == nullptr, "init just once"); resolved_references->obj_at_put(appendix_index, appendix()); @@ -587,7 +596,14 @@ bool ConstantPoolCache::save_and_throw_indy_exc( assert(PENDING_EXCEPTION->is_a(vmClasses::LinkageError_klass()), "No LinkageError exception"); - MutexLocker ml(THREAD, cpool->pool_holder()->init_monitor()); + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + JavaThread* current = THREAD; + objArrayHandle resolved_references(current, cpool->resolved_references()); + assert(resolved_references() != nullptr, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, current); // if the indy_info is resolved or the indy_resolution_failed flag is set then another // thread either succeeded in resolving the method or got a LinkageError @@ -610,11 +626,21 @@ bool ConstantPoolCache::save_and_throw_indy_exc( oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) { ResourceMark rm; - MutexLocker ml(constant_pool()->pool_holder()->init_monitor()); + + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + JavaThread* current = JavaThread::current(); + constantPoolHandle cp(current, constant_pool()); + + objArrayHandle resolved_references(current, cp->resolved_references()); + assert(resolved_references() != nullptr, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, current); assert(index >= 0, "Indy index must be positive at this point"); if (resolved_indy_entry_at(index)->method() != nullptr) { - return constant_pool()->resolved_reference_from_indy(index); + return cp->resolved_reference_from_indy(index); } if (resolved_indy_entry_at(index)->resolution_failed()) { @@ -622,9 +648,7 @@ oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) { // resolution. Ignore our success and throw their exception. guarantee(index >= 0, "Invalid indy index"); int encoded_index = ResolutionErrorTable::encode_indy_index(index); - JavaThread* THREAD = JavaThread::current(); // For exception macros. - constantPoolHandle cp(THREAD, constant_pool()); - ConstantPool::throw_resolution_error(cp, encoded_index, THREAD); + ConstantPool::throw_resolution_error(cp, encoded_index, current); return nullptr; } @@ -648,7 +672,6 @@ oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) { if (has_appendix) { const int appendix_index = resolved_indy_entry_at(index)->resolved_references_index(); - objArrayOop resolved_references = constant_pool()->resolved_references(); assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob"); assert(resolved_references->obj_at(appendix_index) == nullptr, "init just once"); resolved_references->obj_at_put(appendix_index, appendix()); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 8a716c8f9f6a2..328c2edbb9fb5 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -86,6 +86,7 @@ #include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/reflection.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/threads.hpp" #include "services/classLoadingService.hpp" #include "services/finalizerService.hpp" @@ -497,9 +498,6 @@ Array* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) { return vtable_indices; } -static Monitor* create_init_monitor(const char* name) { - return new Monitor(Mutex::safepoint, name); -} InstanceKlass::InstanceKlass() { assert(CDSConfig::is_dumping_static_archive() || CDSConfig::is_using_archive(), "only for CDS"); @@ -517,7 +515,6 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe _nest_host_index(0), _init_state(allocated), _reference_type(reference_type), - _init_monitor(create_init_monitor("InstanceKlassInitMonitor_lock")), _init_thread(nullptr) { set_vtable_length(parser.vtable_size()); @@ -745,6 +742,28 @@ objArrayOop InstanceKlass::signers() const { return java_lang_Class::signers(java_mirror()); } +oop InstanceKlass::init_lock() const { + // return the init lock from the mirror + oop lock = java_lang_Class::init_lock(java_mirror()); + // Prevent reordering with any access of initialization state + OrderAccess::loadload(); + assert(lock != nullptr || !is_not_initialized(), // initialized or in_error state + "only fully initialized state can have a null lock"); + return lock; +} + +// Set the initialization lock to null so the object can be GC'ed. Any racing +// threads to get this lock will see a null lock and will not lock. +// That's okay because they all check for initialized state after getting +// the lock and return. +void InstanceKlass::fence_and_clear_init_lock() { + // make sure previous stores are all done, notably the init_state. + OrderAccess::storestore(); + java_lang_Class::clear_init_lock(java_mirror()); + assert(!is_not_initialized(), "class must be initialized now"); +} + + // See "The Virtual Machine Specification" section 2.16.5 for a detailed explanation of the class initialization // process. The step comments refers to the procedure described in that section. // Note: implementation moved to static method to expose the this pointer. @@ -772,49 +791,6 @@ void InstanceKlass::link_class(TRAPS) { } } -void InstanceKlass::check_link_state_and_wait(JavaThread* current) { - MonitorLocker ml(current, _init_monitor); - - bool debug_logging_enabled = log_is_enabled(Debug, class, init); - - // Another thread is linking this class, wait. - while (is_being_linked() && !is_init_thread(current)) { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" waiting for linking of %s by thread \"%s\"", - current->name(), external_name(), init_thread_name()); - } - ml.wait(); - } - - // This thread is recursively linking this class, continue - if (is_being_linked() && is_init_thread(current)) { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" recursively linking %s", - current->name(), external_name()); - } - return; - } - - // If this class wasn't linked already, set state to being_linked - if (!is_linked()) { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" linking %s", - current->name(), external_name()); - } - set_init_state(being_linked); - set_init_thread(current); - } else { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" found %s already linked", - current->name(), external_name()); - } - } -} - // Called to verify that a class can link during initialization, without // throwing a VerifyError. bool InstanceKlass::link_class_or_fail(TRAPS) { @@ -893,8 +869,9 @@ bool InstanceKlass::link_class_impl(TRAPS) { // verification & rewriting { - LockLinkState init_lock(this, jt); - + HandleMark hm(THREAD); + Handle h_init_lock(THREAD, init_lock()); + ObjectLocker ol(h_init_lock, jt); // rewritten will have been set if loader constraint error found // on an earlier link attempt // don't verify or rewrite if already rewritten @@ -952,7 +929,21 @@ bool InstanceKlass::link_class_impl(TRAPS) { // In case itable verification is ever added. // itable().verify(tty, true); #endif - set_initialization_state_and_notify(linked, THREAD); + if (UseVtableBasedCHA && Universe::is_fully_initialized()) { + DeoptimizationScope deopt_scope; + { + // Now mark all code that assumes the class is not linked. + // Set state under the Compile_lock also. + MutexLocker ml(THREAD, Compile_lock); + + set_init_state(linked); + CodeCache::mark_dependents_on(&deopt_scope, this); + } + // Perform the deopt handshake outside Compile_lock. + deopt_scope.deoptimize_marked(); + } else { + set_init_state(linked); + } if (JvmtiExport::should_post_class_prepare()) { JvmtiExport::post_class_prepare(THREAD, this); } @@ -1084,7 +1075,6 @@ void InstanceKlass::initialize_impl(TRAPS) { DTRACE_CLASSINIT_PROBE(required, -1); bool wait = false; - bool throw_error = false; JavaThread* jt = THREAD; @@ -1093,24 +1083,27 @@ void InstanceKlass::initialize_impl(TRAPS) { // refer to the JVM book page 47 for description of steps // Step 1 { - MonitorLocker ml(jt, _init_monitor); + Handle h_init_lock(THREAD, init_lock()); + ObjectLocker ol(h_init_lock, jt); // Step 2 - while (is_being_initialized() && !is_init_thread(jt)) { + // If we were to use wait() instead of waitInterruptibly() then + // we might end up throwing IE from link/symbol resolution sites + // that aren't expected to throw. This would wreak havoc. See 6320309. + while (is_being_initialized() && !is_reentrant_initialization(jt)) { if (debug_logging_enabled) { ResourceMark rm(jt); log_debug(class, init)("Thread \"%s\" waiting for initialization of %s by thread \"%s\"", jt->name(), external_name(), init_thread_name()); } - wait = true; jt->set_class_to_be_initialized(this); - ml.wait(); + ol.wait_uninterruptibly(jt); jt->set_class_to_be_initialized(nullptr); } // Step 3 - if (is_being_initialized() && is_init_thread(jt)) { + if (is_being_initialized() && is_reentrant_initialization(jt)) { if (debug_logging_enabled) { ResourceMark rm(jt); log_debug(class, init)("Thread \"%s\" recursively initializing %s", @@ -1138,7 +1131,19 @@ void InstanceKlass::initialize_impl(TRAPS) { log_debug(class, init)("Thread \"%s\" found %s is in error state", jt->name(), external_name()); } - throw_error = true; + + DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait); + ResourceMark rm(THREAD); + Handle cause(THREAD, get_initialization_error(THREAD)); + + stringStream ss; + ss.print("Could not initialize class %s", external_name()); + if (cause.is_null()) { + THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string()); + } else { + THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(), + ss.as_string(), cause); + } } else { // Step 6 @@ -1152,22 +1157,6 @@ void InstanceKlass::initialize_impl(TRAPS) { } } - // Throw error outside lock - if (throw_error) { - DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait); - ResourceMark rm(THREAD); - Handle cause(THREAD, get_initialization_error(THREAD)); - - stringStream ss; - ss.print("Could not initialize class %s", external_name()); - if (cause.is_null()) { - THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string()); - } else { - THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(), - ss.as_string(), cause); - } - } - // Step 7 // Next, if C is a class rather than an interface, initialize it's super class and super // interfaces. @@ -1225,7 +1214,7 @@ void InstanceKlass::initialize_impl(TRAPS) { // Step 9 if (!HAS_PENDING_EXCEPTION) { - set_initialization_state_and_notify(fully_initialized, THREAD); + set_initialization_state_and_notify(fully_initialized, CHECK); debug_only(vtable().verify(tty, true);) } else { @@ -1258,43 +1247,26 @@ void InstanceKlass::initialize_impl(TRAPS) { } -void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) { - MonitorLocker ml(current, _init_monitor); - - if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) { - DeoptimizationScope deopt_scope; - { - // Now mark all code that assumes the class is not linked. - // Set state under the Compile_lock also. - MutexLocker ml(current, Compile_lock); - - set_init_thread(nullptr); // reset _init_thread before changing _init_state - set_init_state(state); - - CodeCache::mark_dependents_on(&deopt_scope, this); - } - // Perform the deopt handshake outside Compile_lock. - deopt_scope.deoptimize_marked(); +void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) { + Handle h_init_lock(THREAD, init_lock()); + if (h_init_lock() != nullptr) { + ObjectLocker ol(h_init_lock, THREAD); + set_init_thread(nullptr); // reset _init_thread before changing _init_state + set_init_state(state); + fence_and_clear_init_lock(); + ol.notify_all(CHECK); } else { + assert(h_init_lock() != nullptr, "The initialization state should never be set twice"); set_init_thread(nullptr); // reset _init_thread before changing _init_state set_init_state(state); } - ml.notify_all(); } // Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock // is grabbed, to ensure that the compiler is not using the class hierarchy. -void InstanceKlass::add_to_hierarchy(JavaThread* current) { +void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) { assert(!SafepointSynchronize::is_at_safepoint(), "must NOT be at safepoint"); - // In case we are not using CHA based vtables we need to make sure the loaded - // deopt is completed before anyone links this class. - // Linking is done with _init_monitor held, by loading and deopting with it - // held we make sure the deopt is completed before linking. - if (!UseVtableBasedCHA) { - init_monitor()->lock(); - } - DeoptimizationScope deopt_scope; { MutexLocker ml(current, Compile_lock); @@ -1316,12 +1288,26 @@ void InstanceKlass::add_to_hierarchy(JavaThread* current) { } // Perform the deopt handshake outside Compile_lock. deopt_scope.deoptimize_marked(); +} - if (!UseVtableBasedCHA) { - init_monitor()->unlock(); +void InstanceKlass::add_to_hierarchy(JavaThread* current) { + + if (UseVtableBasedCHA || !Universe::is_fully_initialized()) { + add_to_hierarchy_impl(current); + } else { + // In case we are not using CHA based vtables we need to make sure the loaded + // deopt is completed before anyone links this class. + // Linking is done with init_lock held, by loading and deopting with it + // held we make sure the deopt is completed before linking. + Handle h_init_lock(current, init_lock()); + ObjectLocker ol(h_init_lock, current); + add_to_hierarchy_impl(current); + + // This doesn't need a notify because the wait is only on the class initialization path. } } + InstanceKlass* InstanceKlass::implementor() const { InstanceKlass* volatile* ik = adr_implementor(); if (ik == nullptr) { @@ -2590,7 +2576,6 @@ void InstanceKlass::remove_unshareable_info() { _nest_host = nullptr; init_shared_package_entry(); _dep_context_last_cleaned = 0; - _init_monitor = nullptr; remove_unshareable_flags(); } @@ -2694,9 +2679,6 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation()) { set_is_value_based(); } - - // restore the monitor - _init_monitor = create_init_monitor("InstanceKlassInitMonitorRestored_lock"); } // Check if a class or any of its supertypes has a version older than 50. @@ -2792,9 +2774,6 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) { methods_do(method_release_C_heap_structures); } - // Destroy the init_monitor - delete _init_monitor; - // Deallocate oop map cache if (_oop_map_cache != nullptr) { delete _oop_map_cache; @@ -3486,7 +3465,7 @@ nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_le #define BULLET " - " static const char* state_names[] = { - "allocated", "loaded", "being_linked", "linked", "being_initialized", "fully_initialized", "initialization_error" + "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error" }; static void print_vtable(intptr_t* start, int len, outputStream* st) { @@ -4136,17 +4115,13 @@ void JNIid::verify(Klass* holder) { } void InstanceKlass::set_init_state(ClassState state) { - if (state > loaded) { - assert_lock_strong(_init_monitor); - } #ifdef ASSERT bool good_state = is_shared() ? (_init_state <= state) : (_init_state < state); - bool link_failed = _init_state == being_linked && state == loaded; - assert(good_state || state == allocated || link_failed, "illegal state transition"); + assert(good_state || state == allocated, "illegal state transition"); #endif assert(_init_thread == nullptr, "should be cleared before state change"); - Atomic::store(&_init_state, state); + _init_state = state; } #if INCLUDE_JVMTI diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 27c97e38b62c2..fe281f9514805 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -152,7 +152,6 @@ class InstanceKlass: public Klass { enum ClassState : u1 { allocated, // allocated (but not yet linked) loaded, // loaded and inserted in class hierarchy (but not linked yet) - being_linked, // currently running verifier and rewriter linked, // successfully linked/verified (but not initialized yet) being_initialized, // currently running class initializer fully_initialized, // initialized (successful final state) @@ -226,14 +225,20 @@ class InstanceKlass: public Klass { volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change + // _is_marked_dependent can be set concurrently, thus cannot be part of the + // _misc_flags. + bool _is_marked_dependent; // used for marking during flushing and deoptimization + + // Class states are defined as ClassState (see above). + // Place the _init_state here to utilize the unused 2-byte after + // _idnum_allocated_count. volatile ClassState _init_state; // state of class - u1 _reference_type; // reference type + u1 _reference_type; // reference type // State is set either at parse time or while executing, atomically to not disturb other state InstanceKlassFlags _misc_flags; - Monitor* _init_monitor; // mutual exclusion to _init_state and _init_thread. JavaThread* volatile _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization) OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily) @@ -497,41 +502,23 @@ class InstanceKlass: public Klass { TRAPS); JavaThread* init_thread() { return Atomic::load(&_init_thread); } - // We can safely access the name as long as we hold the _init_monitor. const char* init_thread_name() { - assert(_init_monitor->owned_by_self(), "Must hold _init_monitor here"); return init_thread()->name_raw(); } public: // initialization state - bool is_loaded() const { return init_state() >= loaded; } - bool is_linked() const { return init_state() >= linked; } - bool is_being_linked() const { return init_state() == being_linked; } - bool is_initialized() const { return init_state() == fully_initialized; } - bool is_not_initialized() const { return init_state() < being_initialized; } - bool is_being_initialized() const { return init_state() == being_initialized; } - bool is_in_error_state() const { return init_state() == initialization_error; } - bool is_init_thread(JavaThread *thread) { return thread == init_thread(); } - ClassState init_state() const { return Atomic::load(&_init_state); } + bool is_loaded() const { return _init_state >= loaded; } + bool is_linked() const { return _init_state >= linked; } + bool is_initialized() const { return _init_state == fully_initialized; } + bool is_not_initialized() const { return _init_state < being_initialized; } + bool is_being_initialized() const { return _init_state == being_initialized; } + bool is_in_error_state() const { return _init_state == initialization_error; } + bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; } + ClassState init_state() const { return _init_state; } const char* init_state_name() const; bool is_rewritten() const { return _misc_flags.rewritten(); } - class LockLinkState : public StackObj { - InstanceKlass* _ik; - JavaThread* _current; - public: - LockLinkState(InstanceKlass* ik, JavaThread* current) : _ik(ik), _current(current) { - ik->check_link_state_and_wait(current); - } - ~LockLinkState() { - if (!_ik->is_linked()) { - // Reset to loaded if linking failed. - _ik->set_initialization_state_and_notify(loaded, _current); - } - } - }; - // is this a sealed class bool is_sealed() const; @@ -829,7 +816,7 @@ class InstanceKlass: public Klass { // initialization void call_class_initializer(TRAPS); - void set_initialization_state_and_notify(ClassState state, JavaThread* current); + void set_initialization_state_and_notify(ClassState state, TRAPS); // OopMapCache support OopMapCache* oop_map_cache() { return _oop_map_cache; } @@ -841,6 +828,10 @@ class InstanceKlass: public Klass { void set_jni_ids(JNIid* ids) { _jni_ids = ids; } JNIid* jni_id_for(int offset); + private: + void add_to_hierarchy_impl(JavaThread* current); + + public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); void mark_dependent_nmethods(DeoptimizationScope* deopt_scope, KlassDepChange& changes); @@ -1055,7 +1046,7 @@ class InstanceKlass: public Klass { public: u2 idnum_allocated_count() const { return _idnum_allocated_count; } - private: +private: // initialization state void set_init_state(ClassState state); void set_rewritten() { _misc_flags.set_rewritten(true); } @@ -1072,6 +1063,12 @@ class InstanceKlass: public Klass { jmethodID update_jmethod_id(jmethodID* jmeths, Method* method, int idnum); public: + // Lock for (1) initialization; (2) access to the ConstantPool of this class. + // Must be one per class and it has to be a VM internal object so java code + // cannot lock it (like the mirror). + // It has to be an object not a Mutex because it's held through java calls. + oop init_lock() const; + // Returns the array class for the n'th dimension virtual ArrayKlass* array_klass(int n, TRAPS); virtual ArrayKlass* array_klass_or_null(int n); @@ -1081,10 +1078,9 @@ class InstanceKlass: public Klass { virtual ArrayKlass* array_klass_or_null(); static void clean_initialization_error_table(); - - Monitor* init_monitor() const { return _init_monitor; } private: - void check_link_state_and_wait(JavaThread* current); + void fence_and_clear_init_lock(); + bool link_class_impl (TRAPS); bool verify_code (TRAPS); void initialize_impl (TRAPS); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index f794a15ac070b..0e6d367586b9d 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1336,7 +1336,7 @@ methodHandle SharedRuntime::resolve_helper(bool is_virtual, bool is_optimized, T if (invoke_code == Bytecodes::_invokestatic) { assert(callee_method->method_holder()->is_initialized() || - callee_method->method_holder()->is_init_thread(current), + callee_method->method_holder()->is_reentrant_initialization(current), "invalid class initialization state for invoke_static"); if (!VM_Version::supports_fast_class_init_checks() && callee_method->needs_clinit_barrier()) { // In order to keep class initialization check, do not patch call diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 27b4163238aa9..047f6703b545c 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -821,6 +821,16 @@ int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { return ret_code; } +void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { + if (millis < 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); + } + ObjectSynchronizer::inflate(THREAD, + obj(), + inflate_cause_wait)->wait(millis, false, THREAD); +} + + void ObjectSynchronizer::notify(Handle obj, TRAPS) { JavaThread* current = THREAD; diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 786defcbca4de..7406af678e0e7 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -119,6 +119,11 @@ class ObjectSynchronizer : AllStatic { static bool quick_notify(oopDesc* obj, JavaThread* current, bool All); static bool quick_enter(oop obj, JavaThread* current, BasicLock* Lock); + // Special internal-use-only method for use by JVM infrastructure + // that needs to wait() on a java-level object but that can't risk + // throwing unexpected InterruptedExecutionExceptions. + static void waitUninterruptibly(Handle obj, jlong Millis, TRAPS); + // Inflate light weight monitor to heavy weight monitor static ObjectMonitor* inflate(Thread* current, oop obj, const InflateCause cause); // Used to inflate a monitor as if it was done from the thread JavaThread. @@ -225,6 +230,7 @@ class ObjectLocker : public StackObj { // Monitor behavior void wait(TRAPS) { ObjectSynchronizer::wait(_obj, 0, CHECK); } // wait forever + void wait_uninterruptibly(TRAPS) { ObjectSynchronizer::waitUninterruptibly(_obj, 0, CHECK); } // wait forever void notify_all(TRAPS) { ObjectSynchronizer::notifyall(_obj, CHECK); } }; diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index ccb90c427b05a..be2e275bf7fc3 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -205,8 +205,9 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { Klass* k = obj->klass(); st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", p2i(obj), k->external_name()); } - else if (thread()->osthread()->get_state() == CONDVAR_WAIT) { - // We are waiting on the native class initialization monitor. + else if (thread()->osthread()->get_state() == OBJECT_WAIT) { + // We are waiting on an Object monitor but Object.wait() isn't the + // top-frame, so we should be waiting on a Class initialization monitor. InstanceKlass* k = thread()->class_to_be_initialized(); if (k != nullptr) { st->print_cr("\t- waiting on the Class initialization monitor for %s", k->external_name()); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 8ff766af128b7..4b6381bd05ebd 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -246,6 +246,7 @@ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ + nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ nonstatic_field(InstanceKlass, _itable_len, int) \ nonstatic_field(InstanceKlass, _nest_host_index, u2) \ nonstatic_field(InstanceKlass, _reference_type, u1) \ @@ -2163,7 +2164,6 @@ \ declare_constant(InstanceKlass::allocated) \ declare_constant(InstanceKlass::loaded) \ - declare_constant(InstanceKlass::being_linked) \ declare_constant(InstanceKlass::linked) \ declare_constant(InstanceKlass::being_initialized) \ declare_constant(InstanceKlass::fully_initialized) \ diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 6f113cfca95ca..5b3749381a01b 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1089,6 +1089,14 @@ u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) { } } + // Also provide a pointer to the init_lock if present, so there aren't unreferenced int[0] + // arrays. + oop init_lock = ik->init_lock(); + if (init_lock != nullptr) { + field_count++; + size += sizeof(address); + } + // We write the value itself plus a name and a one byte type tag per field. return checked_cast(size + field_count * (sizeof(address) + 1)); } @@ -1126,6 +1134,14 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) { prev = prev->previous_versions(); } } + + // Add init lock to the end if the class is not yet initialized + oop init_lock = ik->init_lock(); + if (init_lock != nullptr) { + writer->write_symbolID(vmSymbols::init_lock_name()); // name + writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type + writer->write_objectID(init_lock); + } } // dump the raw values of the instance fields of the given object diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index b13171745bba3..0f05b15af7636 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -57,7 +57,6 @@ public void update(Observable o, Object data) { // ClassState constants private static int CLASS_STATE_ALLOCATED; private static int CLASS_STATE_LOADED; - private static int CLASS_STATE_BEING_LINKED; private static int CLASS_STATE_LINKED; private static int CLASS_STATE_BEING_INITIALIZED; private static int CLASS_STATE_FULLY_INITIALIZED; @@ -101,7 +100,6 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc // read ClassState constants CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue(); CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue(); - CLASS_STATE_BEING_LINKED = db.lookupIntConstant("InstanceKlass::being_linked").intValue(); CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue(); CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue(); CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue(); @@ -158,7 +156,6 @@ public InstanceKlass(Address addr) { public static class ClassState { public static final ClassState ALLOCATED = new ClassState("allocated"); public static final ClassState LOADED = new ClassState("loaded"); - public static final ClassState BEING_LINKED = new ClassState("beingLinked"); public static final ClassState LINKED = new ClassState("linked"); public static final ClassState BEING_INITIALIZED = new ClassState("beingInitialized"); public static final ClassState FULLY_INITIALIZED = new ClassState("fullyInitialized"); @@ -182,8 +179,6 @@ public ClassState getInitState() { return ClassState.ALLOCATED; } else if (state == CLASS_STATE_LOADED) { return ClassState.LOADED; - } else if (state == CLASS_STATE_BEING_LINKED) { - return ClassState.BEING_LINKED; } else if (state == CLASS_STATE_LINKED) { return ClassState.LINKED; } else if (state == CLASS_STATE_BEING_INITIALIZED) { diff --git a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java index 0154f43244e94..6260088fa3337 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java +++ b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -60,8 +60,7 @@ public class TestThreadDumpClassInitMonitor { */ final static String TEST_THREAD = "TestThread"; final static String TEST_THREAD_ENTRY = "\"" + TEST_THREAD; - // final static String IN_OBJECT_WAIT = "in Object.wait()"; - final static String IN_CONVAR_WAIT = "waiting on condition"; + final static String IN_OBJECT_WAIT = "in Object.wait()"; final static String THREAD_STATE = "java.lang.Thread.State: RUNNABLE"; final static String THREAD_INFO = "Thread:"; // the details are not important final static String JAVATHREAD_STATE = "JavaThread state: _thread_blocked"; @@ -140,7 +139,7 @@ public static void main(String[] args) throws Throwable { continue; } foundLines++; - if (!line.contains(IN_CONVAR_WAIT)) { + if (!line.contains(IN_OBJECT_WAIT)) { throw new Error("Unexpected initial stack line: " + line); } continue; diff --git a/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java new file mode 100644 index 0000000000000..f4f1427e39b24 --- /dev/null +++ b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333542 + * @summary Missed breakpoint due to JVM not blocking other threads while + * delivering a ClassPrepareEvent. + * + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g BreakpointOnClassPrepare.java + * @run driver BreakpointOnClassPrepare SUSPEND_NONE + * @run driver BreakpointOnClassPrepare SUSPEND_EVENT_THREAD + * @run driver BreakpointOnClassPrepare SUSPEND_ALL + */ + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +import java.util.*; + +// The debuggee spawns 50 threads that call LoadedClass.foo(). The debugger enables +// ClassPrepareEvent for LoadedClass, and sets a breakpoint on LoadedClass.foo() when +// the ClassPrepareEvent arrives. The debugger expects 50 breakpoints to be hit. +// This verifies that the thread that causes the generation of the ClassPrepareEvent +// has properly blocked all other threads from executing LoadedClass.foo() until the +// ClassPrepareEvent has been delivered. + +class LoadedClass { + static void foo(int k) { + System.out.println("HIT = " + k); // set breakpoint here + } +} + +class BreakpointOnClassPrepareTarg { + public static void main(String[] args) throws InterruptedException { + System.out.println("Start"); + Thread threads[] = new Thread[BreakpointOnClassPrepare.NUM_BREAKPOINTS]; + for (int i = 0; i < BreakpointOnClassPrepare.NUM_BREAKPOINTS; i++) { + int k = i; + Thread t = DebuggeeWrapper.newThread(() -> { + System.out.println("k = " + k); + LoadedClass.foo(k); + }); + threads[i] = t; + t.setDaemon(true); + t.setName("MyThread-" + k); + t.start(); + } + + for (int i = 0; i < BreakpointOnClassPrepare.NUM_BREAKPOINTS; i++) { + try { + Thread t = threads[i]; + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + System.out.println("Finish"); + } +} + + /********** test program **********/ + +public class BreakpointOnClassPrepare extends TestScaffold { + ClassType targetClass; + ThreadReference mainThread; + + BreakpointOnClassPrepare(String args[]) { + super(args); + } + + public static void main(String[] args) throws Exception { + new BreakpointOnClassPrepare(args).startTests(); + } + + /********** event handlers **********/ + + static final int NUM_BREAKPOINTS = 50; + int bkptCount; + BreakpointRequest bkptRequest; + + public void breakpointReached(BreakpointEvent event) { + bkptCount++; + System.out.println("Got BreakpointEvent: " + bkptCount + " for thread " + event.thread()); + } + + public void vmDisconnected(VMDisconnectEvent event) { + println("Got VMDisconnectEvent"); + } + + /********** test core **********/ + + protected void runTests() throws Exception { + /* Determine which suspend policy to use. */ + int policy; + if (args.length != 1) { + throw new RuntimeException("Invalid number of args: " + args.length); + } + String policyString = args[0]; + if (policyString.equals("SUSPEND_NONE")) { + policy = EventRequest.SUSPEND_NONE; + } else if (policyString.equals("SUSPEND_ALL")) { + policy = EventRequest.SUSPEND_ALL; + } else if (policyString.equals("SUSPEND_EVENT_THREAD")) { + policy = EventRequest.SUSPEND_EVENT_THREAD; + } else { + throw new RuntimeException("Invalid suspend policy: " + policyString); + } + + /* Stop when the target is loaded. */ + BreakpointEvent bpe = startToMain("BreakpointOnClassPrepareTarg"); + + /* Stop when "LoadedClass" is loaded. */ + EventRequestManager erm = vm().eventRequestManager(); + ClassPrepareEvent cpe = resumeToPrepareOf("LoadedClass"); + println("Got ClassPrepareEvent: " + cpe); + + /* Set a breakpoint for each time LoadedClass.foo() is called. */ + ClassType loadedClass = (ClassType)cpe.referenceType() ; + Location loc1 = findMethodLocation(loadedClass, "foo", "(I)V", 1); + bkptRequest = erm.createBreakpointRequest(loc1); + bkptRequest.setSuspendPolicy(policy); + bkptRequest.enable(); + + listenUntilVMDisconnect(); + + if (!testFailed && bkptCount == NUM_BREAKPOINTS) { + println("BreakpointOnClassPrepare: passed"); + } else { + throw new Exception("BreakpointOnClassPrepare: failed. bkptCount == " + bkptCount); + } + } +} From f101e153cee68750fcf1f12da10e29806875b522 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Tue, 25 Jun 2024 22:31:39 +0000 Subject: [PATCH 045/288] 8333583: Crypto-XDH.generateSecret regression after JDK-8329538 Reviewed-by: sviswanathan, kvn, ascarpino --- .../classes/build/tools/intpoly/FieldGen.java | 10 +- .../x86/stubGenerator_x86_64_poly_mont.cpp | 1 - src/hotspot/share/classfile/vmIntrinsics.hpp | 4 +- src/hotspot/share/opto/library_call.cpp | 2 - src/hotspot/share/opto/runtime.cpp | 6 +- .../util/math/intpoly/IntegerPolynomial.java | 24 ++-- .../math/intpoly/IntegerPolynomial1305.java | 6 +- .../intpoly/IntegerPolynomialModBinP.java | 6 +- .../MontgomeryIntegerPolynomialP256.java | 104 +++++++++--------- 9 files changed, 73 insertions(+), 90 deletions(-) diff --git a/make/jdk/src/classes/build/tools/intpoly/FieldGen.java b/make/jdk/src/classes/build/tools/intpoly/FieldGen.java index 234f5cfce0d26..2bf8c5c0b2001 100644 --- a/make/jdk/src/classes/build/tools/intpoly/FieldGen.java +++ b/make/jdk/src/classes/build/tools/intpoly/FieldGen.java @@ -778,7 +778,7 @@ private String generate(FieldParams params) throws IOException { result.appendLine("}"); result.appendLine("@Override"); - result.appendLine("protected int mult(long[] a, long[] b, long[] r) {"); + result.appendLine("protected void mult(long[] a, long[] b, long[] r) {"); result.incrIndent(); for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { result.appendIndent(); @@ -804,9 +804,6 @@ private String generate(FieldParams params) throws IOException { } } result.append(");\n"); - result.appendIndent(); - result.append("return 0;"); - result.appendLine(); result.decrIndent(); result.appendLine("}"); @@ -836,7 +833,7 @@ private String generate(FieldParams params) throws IOException { // } // } result.appendLine("@Override"); - result.appendLine("protected int square(long[] a, long[] r) {"); + result.appendLine("protected void square(long[] a, long[] r) {"); result.incrIndent(); for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { result.appendIndent(); @@ -877,9 +874,6 @@ private String generate(FieldParams params) throws IOException { } } result.append(");\n"); - result.appendIndent(); - result.append("return 0;"); - result.appendLine(); result.decrIndent(); result.appendLine("}"); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp index 25ee68072492c..4e909afbacc70 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp @@ -249,7 +249,6 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() { const Register tmp = r9; montgomeryMultiply(aLimbs, bLimbs, rLimbs, tmp, _masm); - __ mov64(rax, 0x1); // Return 1 (Fig. 5, Step 6 [1] skipped in montgomeryMultiply) __ leave(); __ ret(0); diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index b8d8c40cc47a4..7a5c2ee47bb52 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -529,8 +529,8 @@ class methodHandle; /* support for sun.security.util.math.intpoly.MontgomeryIntegerPolynomialP256 */ \ do_class(sun_security_util_math_intpoly_MontgomeryIntegerPolynomialP256, "sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256") \ do_intrinsic(_intpoly_montgomeryMult_P256, sun_security_util_math_intpoly_MontgomeryIntegerPolynomialP256, intPolyMult_name, intPolyMult_signature, F_R) \ - do_name(intPolyMult_name, "mult") \ - do_signature(intPolyMult_signature, "([J[J[J)I") \ + do_name(intPolyMult_name, "multImpl") \ + do_signature(intPolyMult_signature, "([J[J[J)V") \ \ do_class(sun_security_util_math_intpoly_IntegerPolynomial, "sun/security/util/math/intpoly/IntegerPolynomial") \ do_intrinsic(_intpoly_assign, sun_security_util_math_intpoly_IntegerPolynomial, intPolyAssign_name, intPolyAssign_signature, F_S) \ diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 596e637652dfb..0148d985bc59b 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -7580,8 +7580,6 @@ bool LibraryCallKit::inline_intpoly_montgomeryMult_P256() { OptoRuntime::intpoly_montgomeryMult_P256_Type(), stubAddr, stubName, TypePtr::BOTTOM, a_start, b_start, r_start); - Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms)); - set_result(result); return true; } diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 2953a1f7b726a..465404bb4693f 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1435,8 +1435,8 @@ const TypeFunc* OptoRuntime::intpoly_montgomeryMult_P256_Type() { // result type needed fields = TypeTuple::fields(1); - fields[TypeFunc::Parms + 0] = TypeInt::INT; // carry bits in output - const TypeTuple* range = TypeTuple::make(TypeFunc::Parms+1, fields); + fields[TypeFunc::Parms + 0] = nullptr; // void + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); return TypeFunc::make(domain, range); } @@ -1455,7 +1455,7 @@ const TypeFunc* OptoRuntime::intpoly_assign_Type() { // result type needed fields = TypeTuple::fields(1); - fields[TypeFunc::Parms + 0] = NULL; // void + fields[TypeFunc::Parms + 0] = nullptr; // void const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); return TypeFunc::make(domain, range); } diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java index bb8d727ba982b..404c0dbd46966 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java @@ -90,12 +90,11 @@ public abstract sealed class IntegerPolynomial implements IntegerFieldModuloP * store the result in an IntegerPolynomial representation in a. Requires * that a.length == numLimbs. */ - protected int multByInt(long[] a, long b) { + protected void multByInt(long[] a, long b) { for (int i = 0; i < a.length; i++) { a[i] *= b; } reduce(a); - return 0; } /** @@ -104,7 +103,7 @@ protected int multByInt(long[] a, long b) { * a.length == b.length == r.length == numLimbs. It is allowed for a and r * to be the same array. */ - protected abstract int mult(long[] a, long[] b, long[] r); + protected abstract void mult(long[] a, long[] b, long[] r); /** * Multiply an IntegerPolynomial representation (a) with itself and store @@ -112,7 +111,7 @@ protected int multByInt(long[] a, long b) { * a.length == r.length == numLimbs. It is allowed for a and r * to be the same array. */ - protected abstract int square(long[] a, long[] r); + protected abstract void square(long[] a, long[] r); IntegerPolynomial(int bitsPerLimb, int numLimbs, @@ -622,8 +621,8 @@ public ImmutableElement multiply(IntegerModuloP genB) { } long[] newLimbs = new long[limbs.length]; - int numAdds = mult(limbs, b.limbs, newLimbs); - return new ImmutableElement(newLimbs, numAdds); + mult(limbs, b.limbs, newLimbs); + return new ImmutableElement(newLimbs, 0); } @Override @@ -635,8 +634,8 @@ public ImmutableElement square() { } long[] newLimbs = new long[limbs.length]; - int numAdds = IntegerPolynomial.this.square(limbs, newLimbs); - return new ImmutableElement(newLimbs, numAdds); + IntegerPolynomial.this.square(limbs, newLimbs); + return new ImmutableElement(newLimbs, 0); } public void addModPowerTwo(IntegerModuloP arg, byte[] result) { @@ -751,7 +750,8 @@ public MutableElement setProduct(IntegerModuloP genB) { b.numAdds = 0; } - numAdds = mult(limbs, b.limbs, limbs); + mult(limbs, b.limbs, limbs); + numAdds = 0; return this; } @@ -764,7 +764,8 @@ public MutableElement setProduct(SmallValue v) { } int value = ((Limb)v).value; - numAdds += multByInt(limbs, value); + multByInt(limbs, value); + numAdds = 0; return this; } @@ -824,7 +825,8 @@ public MutableElement setSquare() { numAdds = 0; } - numAdds = IntegerPolynomial.this.square(limbs, limbs); + IntegerPolynomial.this.square(limbs, limbs); + numAdds = 0; return this; } diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java index 706651330d389..c4cd6b9da7d2e 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java @@ -50,7 +50,7 @@ private IntegerPolynomial1305() { super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS); } - protected int mult(long[] a, long[] b, long[] r) { + protected void mult(long[] a, long[] b, long[] r) { // Use grade-school multiplication into primitives to avoid the // temporary array allocation. This is equivalent to the following @@ -73,7 +73,6 @@ protected int mult(long[] a, long[] b, long[] r) { long c8 = (a[4] * b[4]); carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8); - return 0; } private void carryReduce(long[] r, long c0, long c1, long c2, long c3, @@ -100,7 +99,7 @@ private void carryReduce(long[] r, long c0, long c1, long c2, long c3, } @Override - protected int square(long[] a, long[] r) { + protected void square(long[] a, long[] r) { // Use grade-school multiplication with a simple squaring optimization. // Multiply into primitives to avoid the temporary array allocation. // This is equivalent to the following code: @@ -123,7 +122,6 @@ protected int square(long[] a, long[] r) { long c8 = (a[4] * a[4]); carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8); - return 0; } @Override diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java index e57316ed964f6..3e9b191ddcee3 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java @@ -131,12 +131,11 @@ private void multOnly(long[] a, long[] b, long[] c) { } @Override - protected int mult(long[] a, long[] b, long[] r) { + protected void mult(long[] a, long[] b, long[] r) { long[] c = new long[2 * numLimbs]; multOnly(a, b, c); carryReduce(c, r); - return 0; } private void modReduceInBits(long[] limbs, int index, int bits, long x) { @@ -189,7 +188,7 @@ protected void reduce(long[] a) { } @Override - protected int square(long[] a, long[] r) { + protected void square(long[] a, long[] r) { long[] c = new long[2 * numLimbs]; for (int i = 0; i < numLimbs; i++) { @@ -200,7 +199,6 @@ protected int square(long[] a, long[] r) { } carryReduce(c, r); - return 0; } /** diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java b/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java index 3a84b5f508802..e50890bd976e7 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java @@ -31,6 +31,7 @@ import sun.security.util.math.IntegerFieldModuloP; import java.math.BigInteger; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.ForceInline; // Reference: // - [1] Shay Gueron and Vlad Krasnov "Fast Prime Field Elliptic Curve @@ -103,8 +104,8 @@ public ImmutableElement getElement(BigInteger v) { setLimbsValuePositive(v, vLimbs); // Convert to Montgomery domain - int numAdds = mult(vLimbs, h, montLimbs); - return new ImmutableElement(montLimbs, numAdds); + mult(vLimbs, h, montLimbs); + return new ImmutableElement(montLimbs, 0); } @Override @@ -114,24 +115,6 @@ public SmallValue getSmallValue(int value) { return super.getSmallValue(value); } - /* - * This function is used by IntegerPolynomial.setProduct(SmallValue v) to - * multiply by a small constant (i.e. (int) 1,2,3,4). Instead of doing a - * montgomery conversion followed by a montgomery multiplication, just use - * the spare top (64-BITS_PER_LIMB) bits to multiply by a constant. (See [1] - * Section 4 ) - * - * Will return an unreduced value - */ - @Override - protected int multByInt(long[] a, long b) { - assert (b < (1 << BITS_PER_LIMB)); - for (int i = 0; i < a.length; i++) { - a[i] *= b; - } - return (int) (b - 1); - } - @Override public ImmutableIntegerModuloP fromMontgomery(ImmutableIntegerModuloP n) { assert n.getField() == MontgomeryIntegerPolynomialP256.ONE; @@ -163,10 +146,11 @@ private void halfLimbs(long[] a, long[] r) { } @Override - protected int square(long[] a, long[] r) { - return mult(a, a, r); + protected void square(long[] a, long[] r) { + mult(a, a, r); } + /** * Unrolled Word-by-Word Montgomery Multiplication r = a * b * 2^-260 (mod P) * @@ -174,8 +158,15 @@ protected int square(long[] a, long[] r) { * for a Montgomery Friendly modulus p". Note: Step 6. Skipped; Instead use * numAdds to reuse existing overflow logic. */ + @Override + protected void mult(long[] a, long[] b, long[] r) { + multImpl(a, b, r); + reducePositive(r); + } + + @ForceInline @IntrinsicCandidate - protected int mult(long[] a, long[] b, long[] r) { + private void multImpl(long[] a, long[] b, long[] r) { long aa0 = a[0]; long aa1 = a[1]; long aa2 = a[2]; @@ -408,36 +399,16 @@ protected int mult(long[] a, long[] b, long[] r) { d4 += n4 & LIMB_MASK; c5 += d1 + dd0 + (d0 >>> BITS_PER_LIMB); - c6 += d2 + dd1 + (c5 >>> BITS_PER_LIMB); - c7 += d3 + dd2 + (c6 >>> BITS_PER_LIMB); - c8 += d4 + dd3 + (c7 >>> BITS_PER_LIMB); - c9 = dd4 + (c8 >>> BITS_PER_LIMB); - - c5 &= LIMB_MASK; - c6 &= LIMB_MASK; - c7 &= LIMB_MASK; - c8 &= LIMB_MASK; - - // At this point, the result could overflow by one modulus. - c0 = c5 - modulus[0]; - c1 = c6 - modulus[1] + (c0 >> BITS_PER_LIMB); - c0 &= LIMB_MASK; - c2 = c7 - modulus[2] + (c1 >> BITS_PER_LIMB); - c1 &= LIMB_MASK; - c3 = c8 - modulus[3] + (c2 >> BITS_PER_LIMB); - c2 &= LIMB_MASK; - c4 = c9 - modulus[4] + (c3 >> BITS_PER_LIMB); - c3 &= LIMB_MASK; - - long mask = c4 >> BITS_PER_LIMB; // Signed shift! - - r[0] = ((c5 & mask) | (c0 & ~mask)); - r[1] = ((c6 & mask) | (c1 & ~mask)); - r[2] = ((c7 & mask) | (c2 & ~mask)); - r[3] = ((c8 & mask) | (c3 & ~mask)); - r[4] = ((c9 & mask) | (c4 & ~mask)); - - return 0; + c6 += d2 + dd1; + c7 += d3 + dd2; + c8 += d4 + dd3; + c9 = dd4; + + r[0] = c5; + r[1] = c6; + r[2] = c7; + r[3] = c8; + r[4] = c9; } @Override @@ -516,8 +487,8 @@ public ImmutableElement getElement(byte[] v, int offset, int length, super.encode(v, offset, length, highByte, vLimbs); // Convert to Montgomery domain - int numAdds = mult(vLimbs, h, montLimbs); - return new ImmutableElement(montLimbs, numAdds); + mult(vLimbs, h, montLimbs); + return new ImmutableElement(montLimbs, 0); } /* @@ -556,4 +527,27 @@ protected void reduceIn(long[] limbs, long v, int i) { limbs[i - 5] += (v << 4) & LIMB_MASK; limbs[i - 4] += v >> 48; } + + // Used when limbs a could overflow by one modulus. + @ForceInline + protected void reducePositive(long[] a) { + long aa0 = a[0]; + long aa1 = a[1] + (aa0>>BITS_PER_LIMB); + long aa2 = a[2] + (aa1>>BITS_PER_LIMB); + long aa3 = a[3] + (aa2>>BITS_PER_LIMB); + long aa4 = a[4] + (aa3>>BITS_PER_LIMB); + + long c0 = a[0] - modulus[0]; + long c1 = a[1] - modulus[1] + (c0 >> BITS_PER_LIMB); + long c2 = a[2] - modulus[2] + (c1 >> BITS_PER_LIMB); + long c3 = a[3] - modulus[3] + (c2 >> BITS_PER_LIMB); + long c4 = a[4] - modulus[4] + (c3 >> BITS_PER_LIMB); + long mask = c4 >> BITS_PER_LIMB; // Signed shift! + + a[0] = ((aa0 & mask) | (c0 & ~mask)) & LIMB_MASK; + a[1] = ((aa1 & mask) | (c1 & ~mask)) & LIMB_MASK; + a[2] = ((aa2 & mask) | (c2 & ~mask)) & LIMB_MASK; + a[3] = ((aa3 & mask) | (c3 & ~mask)) & LIMB_MASK; + a[4] = ((aa4 & mask) | (c4 & ~mask)); + } } From c66f785fb685d5c378fb4c4cdebdef29c01d321b Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Wed, 26 Jun 2024 00:59:49 +0000 Subject: [PATCH 046/288] 8334505: RISC-V: Several tests fail when MaxVectorSize does not match VM_Version::_initial_vector_length Reviewed-by: fyang --- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 995e8b722485d..b9467bb2245da 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -327,15 +327,11 @@ void VM_Version::c2_initialize() { FLAG_SET_DEFAULT(MaxVectorSize, 0); FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false); } else { - if (FLAG_IS_DEFAULT(MaxVectorSize)) { - MaxVectorSize = _initial_vector_length; - } else if (!is_power_of_2(MaxVectorSize)) { - vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d, must be a power of 2", (int)MaxVectorSize)); - } else if (MaxVectorSize > _initial_vector_length) { - warning("Current system only supports max RVV vector length %d. Set MaxVectorSize to %d", - _initial_vector_length, _initial_vector_length); - MaxVectorSize = _initial_vector_length; + if (!FLAG_IS_DEFAULT(MaxVectorSize) && MaxVectorSize != _initial_vector_length) { + warning("Current system does not support RVV vector length for MaxVectorSize %d. Set MaxVectorSize to %d", + (int)MaxVectorSize, _initial_vector_length); } + MaxVectorSize = _initial_vector_length; if (MaxVectorSize < 16) { warning("RVV does not support vector length less than 16 bytes. Disabling RVV."); UseRVV = false; From 25c3845be270462388ee5e7330cc7315e5c738df Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 26 Jun 2024 05:15:36 +0000 Subject: [PATCH 047/288] 8333133: Simplify QuickSort::sort Reviewed-by: shade, dholmes --- src/hotspot/share/classfile/moduleEntry.cpp | 2 +- src/hotspot/share/classfile/packageEntry.cpp | 3 +- .../compiler/compilationMemoryStatistic.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp | 3 +- .../shenandoahAdaptiveHeuristics.cpp | 2 +- src/hotspot/share/logging/logSelection.cpp | 2 +- src/hotspot/share/oops/method.cpp | 2 +- src/hotspot/share/utilities/quickSort.hpp | 66 ++++++----------- .../gtest/gc/shared/test_oopStorage.cpp | 2 +- .../gtest/utilities/test_quicksort.cpp | 72 +------------------ 11 files changed, 33 insertions(+), 125 deletions(-) diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index e7f05bedb292a..6c60d60d21192 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -568,7 +568,7 @@ Array* ModuleEntryTable::allocate_archived_entries() { if (n > 1) { // Always allocate in the same order to produce deterministic archive. - QuickSort::sort(archived_modules->data(), n, (_sort_Fn)compare_module_by_name, true); + QuickSort::sort(archived_modules->data(), n, compare_module_by_name); } for (int i = 0; i < n; i++) { archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry()); diff --git a/src/hotspot/share/classfile/packageEntry.cpp b/src/hotspot/share/classfile/packageEntry.cpp index c6236e51c0a02..052960e1735dd 100644 --- a/src/hotspot/share/classfile/packageEntry.cpp +++ b/src/hotspot/share/classfile/packageEntry.cpp @@ -300,7 +300,8 @@ Array* PackageEntryTable::allocate_archived_entries() { _table.iterate_all(grab); if (n > 1) { - QuickSort::sort(archived_packages->data(), n, (_sort_Fn)compare_package_by_name, true); + // Always allocate in the same order to produce deterministic archive. + QuickSort::sort(archived_packages->data(), n, compare_package_by_name); } for (int i = 0; i < n; i++) { archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry()); diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index 196a11fd06537..07d8ec41598d9 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -604,7 +604,7 @@ void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool human_ st->print_cr("(%d/%d)", num, _the_table->number_of_entries()); } if (num > 0) { - QuickSort::sort(filtered, num, diff_entries_by_size, false); + QuickSort::sort(filtered, num, diff_entries_by_size); // Now print. Has to happen under lock protection too, since entries may be changed. for (int i = 0; i < num; i ++) { filtered[i]->print_on(st, human_readable); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index a70d003ab53e5..5da8f26b3310b 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -383,7 +383,7 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { double non_young_end_time_sec = os::elapsedTime(); phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); - QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx, true); + QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); } void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions) { diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp index 67059b6ec1c47..cc23e0dabe579 100644 --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp @@ -359,8 +359,7 @@ class G1RefineBufferedCards : public StackObj { void sort_cards(size_t start_index) { QuickSort::sort(&_node_buffer[start_index], _node_buffer_capacity - start_index, - compare_cards, - false); + compare_cards); } // Returns the index to the first clean card in the buffer. diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 6dc57139f45e5..331e98b1e85bf 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -97,7 +97,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage)); // Better select garbage-first regions - QuickSort::sort(data, (int)size, compare_by_garbage, false); + QuickSort::sort(data, size, compare_by_garbage); size_t cur_cset = 0; size_t cur_garbage = 0; diff --git a/src/hotspot/share/logging/logSelection.cpp b/src/hotspot/share/logging/logSelection.cpp index 16c6c6f63ca40..aea5719b36d4f 100644 --- a/src/hotspot/share/logging/logSelection.cpp +++ b/src/hotspot/share/logging/logSelection.cpp @@ -322,7 +322,7 @@ void LogSelection::suggest_similar_matching(outputStream* out) const { // Sort found suggestions to suggest the best one first SimilarityComparator sc(*this); - QuickSort::sort(suggestions, nsuggestions, sc, false); + QuickSort::sort(suggestions, nsuggestions, sc); out->print("Did you mean any of the following?"); for (size_t i = 0; i < nsuggestions; i++) { diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 525ec284c086a..e5ba0d610314b 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1733,7 +1733,7 @@ void Method::sort_methods(Array* methods, bool set_idnums, method_compa } { NoSafepointVerifier nsv; - QuickSort::sort(methods->data(), length, func, /*idempotent=*/false); + QuickSort::sort(methods->data(), length, func); } // Reset method ordering if (set_idnums) { diff --git a/src/hotspot/share/utilities/quickSort.hpp b/src/hotspot/share/utilities/quickSort.hpp index 7134463f38762..e434a59da3501 100644 --- a/src/hotspot/share/utilities/quickSort.hpp +++ b/src/hotspot/share/utilities/quickSort.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * 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,25 +26,23 @@ #define SHARE_UTILITIES_QUICKSORT_HPP #include "memory/allStatic.hpp" -#include "runtime/globals.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" class QuickSort : AllStatic { private: template - static void swap(T* array, size_t x, size_t y) { - T tmp = array[x]; - array[x] = array[y]; - array[y] = tmp; + static void swap_elements(T* array, size_t x, size_t y) { + swap(array[x], array[y]); } // As pivot we use the median of the first, last and middle elements. - // We swap in these three values at the right place in the array. This - // means that this method not only returns the index of the pivot - // element. It also alters the array so that: + // We swap these three values as needed so that // array[first] <= array[middle] <= array[last] - // A side effect of this is that arrays of length <= 3 are sorted. + // As a result, the first and last elements are placed in the proper + // partition, and arrays of length <= 3 are sorted. + // The middle index is returned, designating that element as the pivot. template static size_t find_pivot(T* array, size_t length, C comparator) { assert(length > 1, "length of array must be > 0"); @@ -53,20 +51,20 @@ class QuickSort : AllStatic { size_t last_index = length - 1; if (comparator(array[0], array[middle_index]) > 0) { - swap(array, 0, middle_index); + swap_elements(array, 0, middle_index); } if (comparator(array[0], array[last_index]) > 0) { - swap(array, 0, last_index); + swap_elements(array, 0, last_index); } if (comparator(array[middle_index], array[last_index]) > 0) { - swap(array, middle_index, last_index); + swap_elements(array, middle_index, last_index); } // Now the value in the middle of the array is the median - // of the fist, last and middle values. Use this as pivot. + // of the first, last and middle values. Use this as pivot. return middle_index; } - template + template static size_t partition(T* array, size_t pivot, size_t length, C comparator) { size_t left_index = 0; size_t right_index = length - 1; @@ -74,27 +72,22 @@ class QuickSort : AllStatic { for ( ; true; ++left_index, --right_index) { for ( ; comparator(array[left_index], pivot_val) < 0; ++left_index) { - assert(left_index < length, "reached end of partition"); + assert(left_index < (length - 1), "reached end of partition"); } for ( ; comparator(array[right_index], pivot_val) > 0; --right_index) { assert(right_index > 0, "reached start of partition"); } - if (left_index < right_index) { - if (!idempotent || comparator(array[left_index], array[right_index]) != 0) { - swap(array, left_index, right_index); - } + swap_elements(array, left_index, right_index); } else { return right_index; } } - - ShouldNotReachHere(); - return 0; } - template - static void inner_sort(T* array, size_t length, C comparator) { + public: + template + static void sort(T* array, size_t length, C comparator) { if (length < 2) { return; } @@ -103,28 +96,11 @@ class QuickSort : AllStatic { // arrays up to length 3 will be sorted after finding the pivot return; } - size_t split = partition(array, pivot, length, comparator); + size_t split = partition(array, pivot, length, comparator); size_t first_part_length = split + 1; - inner_sort(array, first_part_length, comparator); - inner_sort(&array[first_part_length], length - first_part_length, comparator); - } - - public: - // The idempotent parameter prevents the sort from - // reordering a previous valid sort by not swapping - // fields that compare as equal. This requires extra - // calls to the comparator, so the performance - // impact depends on the comparator. - template - static void sort(T* array, size_t length, C comparator, bool idempotent) { - // Switch "idempotent" from function parameter to template parameter - if (idempotent) { - inner_sort(array, length, comparator); - } else { - inner_sort(array, length, comparator); - } + sort(array, first_part_length, comparator); + sort(&array[first_part_length], length - first_part_length, comparator); } }; - #endif // SHARE_UTILITIES_QUICKSORT_HPP diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp index 6758c61325a26..a4ac2fee66ba4 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -461,7 +461,7 @@ class OopStorageTestBlockRelease : public OopStorageTestWithAllocation { *to_release[i] = nullptr; } if (sorted) { - QuickSort::sort(to_release, nrelease, PointerCompare(), false); + QuickSort::sort(to_release, nrelease, PointerCompare()); } storage().release(to_release, nrelease); diff --git a/test/hotspot/gtest/utilities/test_quicksort.cpp b/test/hotspot/gtest/utilities/test_quicksort.cpp index 2ce18486e3e2e..14614110493ba 100644 --- a/test/hotspot/gtest/utilities/test_quicksort.cpp +++ b/test/hotspot/gtest/utilities/test_quicksort.cpp @@ -48,23 +48,11 @@ static bool compare_arrays(int* actual, int* expected, size_t length) { } template -static bool sort_and_compare(int* arrayToSort, int* expectedResult, size_t length, C comparator, bool idempotent = false) { - QuickSort::sort(arrayToSort, length, comparator, idempotent); +static bool sort_and_compare(int* arrayToSort, int* expectedResult, size_t length, C comparator) { + QuickSort::sort(arrayToSort, length, comparator); return compare_arrays(arrayToSort, expectedResult, length); } -static int test_even_odd_comparator(int a, int b) { - bool a_is_odd = ((a % 2) == 1); - bool b_is_odd = ((b % 2) == 1); - if (a_is_odd == b_is_odd) { - return 0; - } - if (a_is_odd) { - return -1; - } - return 1; -} - extern "C" { static int test_stdlib_comparator(const void* a, const void* b) { int ai = *(int*)a; @@ -126,50 +114,6 @@ TEST(QuickSort, quicksort) { int expected_array[] = {6,7,8,8,9,9,11,11,13,21,22,24,24,25,27,27,28,31,32,39,40,40,40,41,44,46,51,55,56,59,64,64,65,69,71,74,75,75,76,78,81,82}; EXPECT_TRUE(sort_and_compare(test_array, expected_array, 42, test_comparator)); } - { - int test_array[] = {2,8,1,4}; - int expected_array[] = {1,4,2,8}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 4, test_even_odd_comparator)); - } -} - -TEST(QuickSort, idempotent) { - { - // An array of lenght 3 is only sorted by find_pivot. Make sure that it is idempotent. - int test_array[] = {1, 4, 8}; - int expected_array[] = {1, 4, 8}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 3, test_even_odd_comparator, true)); - } - { - int test_array[] = {1, 7, 9, 4, 8, 2}; - int expected_array[] = {1, 7, 9, 4, 8, 2}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true)); - } - { - int test_array[] = {1, 9, 7, 4, 2, 8}; - int expected_array[] = {1, 9, 7, 4, 2, 8}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true)); - } - { - int test_array[] = {7, 9, 1, 2, 8, 4}; - int expected_array[] = {7, 9, 1, 2, 8, 4}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true)); - } - { - int test_array[] = {7, 1, 9, 2, 4, 8}; - int expected_array[] = {7, 1, 9, 2, 4, 8}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true)); - } - { - int test_array[] = {9, 1, 7, 4, 8, 2}; - int expected_array[] = {9, 1, 7, 4, 8, 2}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true)); - } - { - int test_array[] = {9, 7, 1, 4, 2, 8}; - int expected_array[] = {9, 7, 1, 4, 2, 8}; - EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true)); - } } TEST(QuickSort, random) { @@ -186,18 +130,6 @@ TEST(QuickSort, random) { // Compare sorting to stdlib::qsort() qsort(expected_array, length, sizeof(int), test_stdlib_comparator); EXPECT_TRUE(sort_and_compare(test_array, expected_array, length, test_comparator)); - - // Make sure sorting is idempotent. - // Both test_array and expected_array are sorted by the test_comparator. - // Now sort them once with the test_even_odd_comparator. Then sort the - // test_array one more time with test_even_odd_comparator and verify that - // it is idempotent. - QuickSort::sort(expected_array, length, test_even_odd_comparator, true); - QuickSort::sort(test_array, length, test_even_odd_comparator, true); - EXPECT_TRUE(compare_arrays(test_array, expected_array, length)); - QuickSort::sort(test_array, length, test_even_odd_comparator, true); - EXPECT_TRUE(compare_arrays(test_array, expected_array, length)); - FREE_C_HEAP_ARRAY(int, test_array); FREE_C_HEAP_ARRAY(int, expected_array); } From a5f401f3a8534a64cf3c27c2ef67f17860de6d6b Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 26 Jun 2024 07:09:50 +0000 Subject: [PATCH 048/288] 8334650: Add debug information about whether an Assertion Predicate is for the init or last value Reviewed-by: roland, kvn --- src/hotspot/share/opto/cfgnode.hpp | 37 ++++++++++++++------- src/hotspot/share/opto/ifnode.cpp | 42 +++++++++++++++++++++--- src/hotspot/share/opto/loopPredicate.cpp | 15 ++++++--- src/hotspot/share/opto/loopTransform.cpp | 17 +++++----- src/hotspot/share/opto/loopnode.hpp | 13 ++++---- src/hotspot/share/opto/predicates.hpp | 9 +++++ 6 files changed, 97 insertions(+), 36 deletions(-) diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index de37f4cdd65ca..32ac8c0162f22 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -57,6 +57,7 @@ class JProjNode; class JumpProjNode; class SCMemProjNode; class PhaseIdealLoop; +enum class AssertionPredicateType; // The success projection of a Parse Predicate is always an IfTrueNode and the uncommon projection an IfFalseNode typedef IfTrueNode ParsePredicateSuccessProj; @@ -318,11 +319,23 @@ class MultiBranchNode : public MultiNode { //------------------------------IfNode----------------------------------------- // Output selected Control, based on a boolean test class IfNode : public MultiBranchNode { + public: + float _prob; // Probability of true path being taken. + float _fcnt; // Frequency counter + + private: + NOT_PRODUCT(AssertionPredicateType _assertion_predicate_type;) + + void init_node(Node* control, Node* bol) { + init_class_id(Class_If); + init_req(0, control); + init_req(1, bol); + } + // Size is bigger to hold the probability field. However, _prob does not // change the semantics so it does not appear in the hash & cmp functions. virtual uint size_of() const { return sizeof(*this); } -private: // Helper methods for fold_compares bool cmpi_folds(PhaseIterGVN* igvn, bool fold_ne = false); bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn); @@ -413,14 +426,8 @@ class IfNode : public MultiBranchNode { // Magic manifest probabilities such as 0.83, 0.7, ... can be found in // gen_subtype_check() and catch_inline_exceptions(). - float _prob; // Probability of true path being taken. - float _fcnt; // Frequency counter - IfNode( Node *control, Node *b, float p, float fcnt ) - : MultiBranchNode(2), _prob(p), _fcnt(fcnt) { - init_class_id(Class_If); - init_req(0,control); - init_req(1,b); - } + IfNode(Node* control, Node* bol, float p, float fcnt); + NOT_PRODUCT(IfNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type);) static IfNode* make_with_same_profile(IfNode* if_node_profile, Node* ctrl, BoolNode* bol); @@ -450,13 +457,19 @@ class IfNode : public MultiBranchNode { class RangeCheckNode : public IfNode { private: - int is_range_check(Node* &range, Node* &index, jint &offset); + int is_range_check(Node*& range, Node*& index, jint& offset); public: - RangeCheckNode(Node* control, Node *b, float p, float fcnt) - : IfNode(control, b, p, fcnt) { + RangeCheckNode(Node* control, Node* bol, float p, float fcnt) : IfNode(control, bol, p, fcnt) { + init_class_id(Class_RangeCheck); + } + +#ifndef PRODUCT + RangeCheckNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type) + : IfNode(control, bol, p, fcnt, assertion_predicate_type) { init_class_id(Class_RangeCheck); } +#endif // NOT PRODUCT virtual int Opcode() const; virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 9760be95ddde9..a5722c45a5e6a 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -47,6 +47,24 @@ extern uint explicit_null_checks_elided; #endif +IfNode::IfNode(Node* control, Node* bol, float p, float fcnt) + : MultiBranchNode(2), + _prob(p), + _fcnt(fcnt) + NOT_PRODUCT(COMMA _assertion_predicate_type(AssertionPredicateType::None)) { + init_node(control, bol); +} + +#ifndef PRODUCT +IfNode::IfNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type) + : MultiBranchNode(2), + _prob(p), + _fcnt(fcnt), + _assertion_predicate_type(assertion_predicate_type) { + init_node(control, bol); +} +#endif // NOT_PRODUCT + //============================================================================= //------------------------------Value------------------------------------------ // Return a tuple for whichever arm of the IF is reachable @@ -1822,11 +1840,23 @@ void IfProjNode::pin_array_access_nodes(PhaseIterGVN* igvn) { } #ifndef PRODUCT -//------------------------------dump_spec-------------------------------------- -void IfNode::dump_spec(outputStream *st) const { - st->print("P=%f, C=%f",_prob,_fcnt); +void IfNode::dump_spec(outputStream* st) const { + switch (_assertion_predicate_type) { + case AssertionPredicateType::Init_value: + st->print("#Init Value Assertion Predicate "); + break; + case AssertionPredicateType::Last_value: + st->print("#Last Value Assertion Predicate "); + break; + case AssertionPredicateType::None: + // No Assertion Predicate + break; + default: + fatal("Unknown Assertion Predicate type"); + } + st->print("P=%f, C=%f", _prob, _fcnt); } -#endif +#endif // NOT PRODUCT //------------------------------idealize_test---------------------------------- // Try to canonicalize tests better. Peek at the Cmp/Bool/If sequence and @@ -2181,6 +2211,8 @@ void ParsePredicateNode::dump_spec(outputStream* st) const { default: fatal("unknown kind"); } + if (_useless) { + st->print("#useless "); + } } - #endif // NOT PRODUCT diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 998d3a27178e1..f8d3fa0b6d91d 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -101,7 +101,8 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred, // is an IfTrue projection. This code is also used to clone predicates to cloned loops. IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_success_proj, Node* new_entry, const Deoptimization::DeoptReason reason, - const int opcode, const bool rewire_uncommon_proj_phi_inputs) { + const int opcode, const bool rewire_uncommon_proj_phi_inputs + NOT_PRODUCT (COMMA AssertionPredicateType assertion_predicate_type)) { assert(parse_predicate_success_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); ParsePredicateNode* parse_predicate = parse_predicate_success_proj->in(0)->as_ParsePredicate(); ParsePredicateUncommonProj* uncommon_proj = parse_predicate->uncommon_proj(); @@ -143,10 +144,12 @@ IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessPro IfNode* new_iff = nullptr; switch (opcode) { case Op_If: - new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt); + new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt + NOT_PRODUCT(COMMA assertion_predicate_type)); break; case Op_RangeCheck: - new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt); + new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt + NOT_PRODUCT(COMMA assertion_predicate_type)); break; case Op_ParsePredicate: new_iff = new ParsePredicateNode(entry, reason, &_igvn); @@ -1320,7 +1323,8 @@ IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, upper_bound_proj); - IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); + IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(), + false NOT_PRODUCT(COMMA AssertionPredicateType::Init_value)); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(opaque_init->outcnt() > 0, "should be used"); @@ -1345,7 +1349,8 @@ IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, new_proj); - new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); + new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(), + false NOT_PRODUCT(COMMA AssertionPredicateType::Last_value)); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(max_value->outcnt() > 0, "should be used"); assert(assertion_predicate_has_loop_opaque_node(new_proj->in(0)->as_If()), "unexpected"); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index a02690778a019..1b29d31ba68f7 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -2769,10 +2769,9 @@ bool PhaseIdealLoop::is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, N // Same as PhaseIdealLoop::duplicate_predicates() but for range checks // eliminated by iteration splitting. -Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* ctrl, - const int scale_con, Node* offset, Node* limit, - jint stride_con, Node* value, - const bool is_template) { +Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate( + IdealLoopTree* loop, Node* ctrl, const int scale_con, Node* offset, Node* limit, jint stride_con, Node* value, + const bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type)) { bool overflow = false; BoolNode* bol = rc_predicate(ctrl, scale_con, offset, value, nullptr, stride_con, limit, (stride_con > 0) != (scale_con > 0), overflow); @@ -2993,8 +2992,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Add two Template Assertion Predicates to create new Initialized Assertion Predicates from when either // unrolling or splitting this main-loop further. - loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, opaque_init, true); + loop_entry = add_range_check_elimination_assertion_predicate( + loop, loop_entry, scale_con, int_offset, int_limit, stride_con, opaque_init, true + NOT_PRODUCT(COMMA AssertionPredicateType::Init_value)); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride()); @@ -3006,8 +3006,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi max_value = new CastIINode(max_value, loop->_head->as_CountedLoop()->phi()->bottom_type()); register_new_node(max_value, loop_entry); - loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, max_value, true); + loop_entry = add_range_check_elimination_assertion_predicate( + loop, loop_entry, scale_con, int_offset, int_limit, stride_con, max_value, true + NOT_PRODUCT(COMMA AssertionPredicateType::Last_value)); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); } else { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 17145c825a420..79faf9c931dd2 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1339,9 +1339,10 @@ class PhaseIdealLoop : public PhaseTransform { bool* p_short_scale, int depth); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted - IfTrueNode* create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, - Deoptimization::DeoptReason reason, int opcode, - bool rewire_uncommon_proj_phi_inputs = false); + IfTrueNode* create_new_if_for_predicate( + ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason, int opcode, + bool rewire_uncommon_proj_phi_inputs = false + NOT_PRODUCT (COMMA AssertionPredicateType assertion_predicate_type = AssertionPredicateType::None)); private: // Helper functions for create_new_if_for_predicate() @@ -1382,9 +1383,9 @@ class PhaseIdealLoop : public PhaseTransform { IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit, jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason); void eliminate_hoisted_range_check(IfTrueNode* hoisted_check_proj, IfTrueNode* template_assertion_predicate_proj); - Node* add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* predicate_proj, int scale_con, - Node* offset, Node* limit, int stride_con, Node* value, - bool is_template); + Node* add_range_check_elimination_assertion_predicate( + IdealLoopTree* loop, Node* predicate_proj, int scale_con, Node* offset, Node* limit, int stride_con, Node* value, + bool is_template NOT_PRODUCT(COMMA AssertionPredicateType assertion_predicate_type = AssertionPredicateType::None)); // Helper function to collect predicate for eliminating the useless ones void eliminate_useless_predicates(); diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 9cac98eb9936f..08aa64f03e583 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -193,6 +193,15 @@ * Main Loop Head */ +#ifndef PRODUCT +// Assertion Predicates are either emitted to check the initial value of a range check in the first iteration or the last +// value of a range check in the last iteration of a loop. +enum class AssertionPredicateType { + None, // Not an Assertion Predicate + Init_value, + Last_value +}; +#endif // NOT PRODUCT // Class to represent Assertion Predicates with a HaltNode instead of an UCT (i.e. either an Initialized Assertion // Predicate or a Template Assertion Predicate created after the initial one at Loop Predication). From b88af94269640a160fbacf25618f3a00756464aa Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 26 Jun 2024 07:40:35 +0000 Subject: [PATCH 049/288] 8269870: PS: Membar in PSPromotionManager::copy_unmarked_to_survivor_space could be relaxed Co-authored-by: Hamlin Li Reviewed-by: mli, kbarrett, tschatzl --- .../gc/parallel/psPromotionManager.inline.hpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index eb27e9776ed9b..f01d1a852997c 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -148,10 +148,6 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { if (!m.is_forwarded()) { return copy_unmarked_to_survivor_space(o, m); } else { - // Ensure any loads from the forwardee follow all changes that precede - // the release-cmpxchg that performed the forwarding, possibly in some - // other thread. - OrderAccess::acquire(); // Return the already installed forwardee. return m.forwardee(); } @@ -258,8 +254,11 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, ContinuationGCSupport::transform_stack_chunk(new_obj); // Now we have to CAS in the header. - // Make copy visible to threads reading the forwardee. - oop forwardee = o->forward_to_atomic(new_obj, test_mark, memory_order_release); + // Because the forwarding is done with memory_order_relaxed there is no + // ordering with the above copy. Clients that get the forwardee must not + // examine its contents without other synchronization, since the contents + // may not be up to date for them. + oop forwardee = o->forward_to_atomic(new_obj, test_mark, memory_order_relaxed); if (forwardee == nullptr) { // forwardee is null when forwarding is successful // We won any races, we "own" this object. assert(new_obj == o->forwardee(), "Sanity"); @@ -295,9 +294,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, return new_obj; } else { // We lost, someone else "owns" this object. - // Ensure loads from the forwardee follow all changes that preceded the - // release-cmpxchg that performed the forwarding in another thread. - OrderAccess::acquire(); assert(o->is_forwarded(), "Object must be forwarded if the cas failed."); assert(o->forwardee() == forwardee, "invariant"); From e1390056c9dbf0a02a131864ebee23435e997852 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 26 Jun 2024 08:44:17 +0000 Subject: [PATCH 050/288] 8333994: NMT: call stacks should show source information Reviewed-by: jsjolen, gziemski --- src/hotspot/share/nmt/memReporter.cpp | 10 +-- src/hotspot/share/nmt/memReporter.hpp | 10 ++- .../share/nmt/nativeCallStackPrinter.cpp | 55 ++++++++++++++ .../share/nmt/nativeCallStackPrinter.hpp | 51 +++++++++++++ .../share/nmt/virtualMemoryTracker.cpp | 6 +- .../share/utilities/nativeCallStack.cpp | 76 ++++++++++--------- .../share/utilities/nativeCallStack.hpp | 2 + .../NMT/CheckForProperDetailStackTrace.java | 34 ++++----- 8 files changed, 181 insertions(+), 63 deletions(-) create mode 100644 src/hotspot/share/nmt/nativeCallStackPrinter.cpp create mode 100644 src/hotspot/share/nmt/nativeCallStackPrinter.hpp diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index bd2f38acdd0a0..b09cf7ae2bdbc 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -337,7 +337,7 @@ int MemDetailReporter::report_malloc_sites() { continue; } const NativeCallStack* stack = malloc_site->call_stack(); - stack->print_on(out); + _stackprinter.print_stack(stack); MEMFLAGS flag = malloc_site->flag(); assert(NMTUtil::flag_is_valid(flag) && flag != mtNone, "Must have a valid memory type"); @@ -374,7 +374,7 @@ int MemDetailReporter::report_virtual_memory_allocation_sites() { continue; } const NativeCallStack* stack = virtual_memory_site->call_stack(); - stack->print_on(out); + _stackprinter.print_stack(stack); INDENT_BY(29, out->print("("); print_total(virtual_memory_site->reserved(), virtual_memory_site->committed()); @@ -428,7 +428,7 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* out->cr(); } else { out->print_cr(" from"); - INDENT_BY(4, stack->print_on(out);) + INDENT_BY(4, _stackprinter.print_stack(stack);) } if (all_committed) { @@ -869,7 +869,7 @@ void MemDetailDiffReporter::diff_malloc_site(const NativeCallStack* stack, size_ return; } - stack->print_on(out); + _stackprinter.print_stack(stack); INDENT_BY(28, out->print("("); print_malloc_diff(current_size, current_count, early_size, early_count, flags); @@ -904,7 +904,7 @@ void MemDetailDiffReporter::diff_virtual_memory_site(const NativeCallStack* stac return; } - stack->print_on(out); + _stackprinter.print_stack(stack); INDENT_BY(28, out->print("(mmap: "); print_virtual_memory_diff(current_reserved, current_committed, early_reserved, early_committed); diff --git a/src/hotspot/share/nmt/memReporter.hpp b/src/hotspot/share/nmt/memReporter.hpp index c10a99795080a..095c05509391b 100644 --- a/src/hotspot/share/nmt/memReporter.hpp +++ b/src/hotspot/share/nmt/memReporter.hpp @@ -28,8 +28,10 @@ #include "memory/metaspace.hpp" #include "nmt/mallocTracker.hpp" #include "nmt/memBaseline.hpp" +#include "nmt/nativeCallStackPrinter.hpp" #include "nmt/nmtCommon.hpp" #include "nmt/virtualMemoryTracker.hpp" +#include "utilities/nativeCallStack.hpp" /* * Base class that provides helpers @@ -149,11 +151,11 @@ class MemSummaryReporter : public MemReporterBase { class MemDetailReporter : public MemSummaryReporter { private: MemBaseline& _baseline; - + NativeCallStackPrinter _stackprinter; public: MemDetailReporter(MemBaseline& baseline, outputStream* output, size_t scale = default_scale) : MemSummaryReporter(baseline, output, scale), - _baseline(baseline) { } + _baseline(baseline), _stackprinter(output) { } // Generate detail report. // The report contains summary and detail sections. @@ -229,10 +231,12 @@ class MemSummaryDiffReporter : public MemReporterBase { * both baselines have to be detail baseline. */ class MemDetailDiffReporter : public MemSummaryDiffReporter { + NativeCallStackPrinter _stackprinter; public: MemDetailDiffReporter(MemBaseline& early_baseline, MemBaseline& current_baseline, outputStream* output, size_t scale = default_scale) : - MemSummaryDiffReporter(early_baseline, current_baseline, output, scale) { } + MemSummaryDiffReporter(early_baseline, current_baseline, output, scale), + _stackprinter(output) { } // Generate detail comparison report virtual void report_diff(); diff --git a/src/hotspot/share/nmt/nativeCallStackPrinter.cpp b/src/hotspot/share/nmt/nativeCallStackPrinter.cpp new file mode 100644 index 0000000000000..70031698a7d80 --- /dev/null +++ b/src/hotspot/share/nmt/nativeCallStackPrinter.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "nmt/nativeCallStackPrinter.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/nativeCallStack.hpp" +#include "utilities/ostream.hpp" + +NativeCallStackPrinter::NativeCallStackPrinter(outputStream* out) : + _text_storage(mtNMT, Arena::Tag::tag_other, 128 * K), _out(out) +{} + +void NativeCallStackPrinter::print_stack(const NativeCallStack* stack) const { + for (int i = 0; i < NMT_TrackingStackDepth; i++) { + const address pc = stack->get_frame(i); + if (pc == nullptr) { + break; + } + bool created = false; + const char** cached_frame_text = _cache.put_if_absent(pc, &created); + if (created) { + stringStream ss(4 * K); + stack->print_frame(&ss, pc); + const size_t len = ss.size(); + char* store = NEW_ARENA_ARRAY(&_text_storage, char, len + 1); + memcpy(store, ss.base(), len + 1); + (*cached_frame_text) = store; + } + _out->print_raw_cr(*cached_frame_text); + } +} diff --git a/src/hotspot/share/nmt/nativeCallStackPrinter.hpp b/src/hotspot/share/nmt/nativeCallStackPrinter.hpp new file mode 100644 index 0000000000000..deebb338626eb --- /dev/null +++ b/src/hotspot/share/nmt/nativeCallStackPrinter.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_NMT_NATIVECALLSTACKPRINTER_HPP +#define SHARE_NMT_NATIVECALLSTACKPRINTER_HPP + +#include "memory/arena.hpp" +#include "nmt/memflags.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/resourceHash.hpp" + +class outputStream; +class NativeCallStack; + +// This is a text cache for NativeCallStack frames by PC. When printing tons of +// NativeCallStack instances (e.g. during NMT detail reports), printing through +// this printer speeds up frame description resolution by quite a bit. +class NativeCallStackPrinter { + // Cache-related data are mutable to be able to use NativeCallStackPrinter as + // inline member in classes with const printing methods. + mutable Arena _text_storage; + mutable ResourceHashtable _cache; + outputStream* const _out; +public: + NativeCallStackPrinter(outputStream* out); + void print_stack(const NativeCallStack* stack) const; +}; + +#endif // SHARE_NMT_NATIVECALLSTACKPRINTER_HPP diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index 46d7e4b644f9b..d25f3689a4268 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -26,6 +26,7 @@ #include "memory/metaspaceStats.hpp" #include "memory/metaspaceUtils.hpp" #include "nmt/memTracker.hpp" +#include "nmt/nativeCallStackPrinter.hpp" #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/os.hpp" @@ -679,16 +680,17 @@ class PrintRegionWalker : public VirtualMemoryWalker { private: const address _p; outputStream* _st; + NativeCallStackPrinter _stackprinter; public: PrintRegionWalker(const void* p, outputStream* st) : - _p((address)p), _st(st) { } + _p((address)p), _st(st), _stackprinter(st) { } bool do_allocation_site(const ReservedMemoryRegion* rgn) { if (rgn->contain_address(_p)) { _st->print_cr(PTR_FORMAT " in mmap'd memory region [" PTR_FORMAT " - " PTR_FORMAT "], tag %s", p2i(_p), p2i(rgn->base()), p2i(rgn->base() + rgn->size()), NMTUtil::flag_to_enum_name(rgn->flag())); if (MemTracker::tracking_level() == NMT_detail) { - rgn->call_stack()->print_on(_st); + _stackprinter.print_stack(rgn->call_stack()); _st->cr(); } return false; diff --git a/src/hotspot/share/utilities/nativeCallStack.cpp b/src/hotspot/share/utilities/nativeCallStack.cpp index 873f3856b74e8..cc4796f54d393 100644 --- a/src/hotspot/share/utilities/nativeCallStack.cpp +++ b/src/hotspot/share/utilities/nativeCallStack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,44 +72,48 @@ int NativeCallStack::frames() const { } // Decode and print this call path -void NativeCallStack::print_on(outputStream* out) const { - DEBUG_ONLY(assert_not_fake();) - address pc; + +void NativeCallStack::print_frame(outputStream* out, address pc) const { char buf[1024]; int offset; - if (is_empty()) { - out->print("[BOOTSTRAP]"); - } else { - for (int frame = 0; frame < NMT_TrackingStackDepth; frame ++) { - pc = get_frame(frame); - if (pc == nullptr) break; - out->print("[" PTR_FORMAT "]", p2i(pc)); - // Print function and library; shorten library name to just its last component - // for brevity, and omit it completely for libjvm.so - bool function_printed = false; - if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { - out->print("%s+0x%x", buf, offset); - function_printed = true; - } - if ((!function_printed || !os::address_is_in_vm(pc)) && - os::dll_address_to_library_name(pc, buf, sizeof(buf), &offset)) { - const char* libname = strrchr(buf, os::file_separator()[0]); - if (libname != nullptr) { - libname++; - } else { - libname = buf; - } - out->print(" in %s", libname); - if (!function_printed) { - out->print("+0x%x", offset); - } + int line; + const bool pc_in_VM = os::address_is_in_vm(pc); + out->print("[" PTR_FORMAT "]", p2i(pc)); + // Print function and library; shorten library name to just its last component + // for brevity, and omit it completely for libjvm.so + bool function_printed = false; + if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { + out->print("%s+0x%x", buf, offset); + function_printed = true; + if (Decoder::get_source_info(pc, buf, sizeof(buf), &line, false)) { + // For intra-vm functions, we omit the full path + const char* s = buf; + if (pc_in_VM) { + s = strrchr(s, os::file_separator()[0]); + s = (s != nullptr) ? s + 1 : buf; } - - // Note: we deliberately omit printing source information here. NativeCallStack::print_on() - // can be called thousands of times as part of NMT detail reporting, and source printing - // can slow down reporting by a factor of 5 or more depending on platform (see JDK-8296931). - - out->cr(); + out->print(" (%s:%d)", s, line); + } + } + if ((!function_printed || !pc_in_VM) && + os::dll_address_to_library_name(pc, buf, sizeof(buf), &offset)) { + const char* libname = strrchr(buf, os::file_separator()[0]); + if (libname != nullptr) { + libname++; + } else { + libname = buf; + } + out->print(" in %s", libname); + if (!function_printed) { + out->print("+0x%x", offset); } } } + +void NativeCallStack::print_on(outputStream* out) const { + DEBUG_ONLY(assert_not_fake();) + for (int i = 0; i < NMT_TrackingStackDepth && _stack[i] != nullptr; i++) { + print_frame(out, _stack[i]); + } + out->cr(); +} diff --git a/src/hotspot/share/utilities/nativeCallStack.hpp b/src/hotspot/share/utilities/nativeCallStack.hpp index 6c04169146e87..3ab72d67eca30 100644 --- a/src/hotspot/share/utilities/nativeCallStack.hpp +++ b/src/hotspot/share/utilities/nativeCallStack.hpp @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "nmt/nmtCommon.hpp" #include "utilities/ostream.hpp" +#include "utilities/resourceHash.hpp" /* * This class represents a native call path (does not include Java frame) @@ -123,6 +124,7 @@ class NativeCallStack : public StackObj { return (unsigned int)hash; } + void print_frame(outputStream* out, address pc) const; void print_on(outputStream* out) const; }; diff --git a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java index 411676b1b6393..049d70702665e 100644 --- a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java +++ b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,8 @@ public class CheckForProperDetailStackTrace { private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); + private static final boolean expectSourceInformation = Platform.isLinux() || Platform.isWindows(); + /* The stack trace we look for by default. Note that :: has been replaced by .* to make sure it matches even if the symbol is not unmangled. */ @@ -121,29 +123,27 @@ public static void main(String args[]) throws Exception { // It's ok for ARM not to have symbols, because it does not support NMT detail // when targeting thumb2. It's also ok for Windows not to have symbols, because // they are only available if the symbols file is included with the build. - if (Platform.isWindows() || Platform.isARM()) { - return; // we are done + if (!Platform.isWindows() && !Platform.isARM()) { + output.reportDiagnosticSummary(); + throw new RuntimeException("Expected symbol missing from output: " + expectedSymbol); } - output.reportDiagnosticSummary(); - throw new RuntimeException("Expected symbol missing from output: " + expectedSymbol); } // Make sure the expected NMT detail stack trace is found System.out.println("Looking for a stack matching:"); - if (okToHaveAllocateHeap) { - System.out.print(stackTraceAllocateHeap); - if (stackTraceMatches(stackTraceAllocateHeap, output)) { - return; - } - } else { - System.out.print(stackTraceDefault); - if (stackTraceMatches(stackTraceDefault, output)) { - return; + String toMatch = okToHaveAllocateHeap ? stackTraceAllocateHeap : stackTraceDefault; + if (!stackTraceMatches(toMatch, output)) { + output.reportDiagnosticSummary(); + throw new RuntimeException("Expected stack trace missing from output"); + } + + System.out.println("Looking for source information:"); + if (expectSourceInformation) { + if (!stackTraceMatches(".*moduleEntry.cpp.*", output)) { + output.reportDiagnosticSummary(); + throw new RuntimeException("Expected source information missing from output"); } } - // Failed to match so dump all the output - output.reportDiagnosticSummary(); - throw new RuntimeException("Expected stack trace missing from output"); } public static boolean stackTraceMatches(String stackTrace, OutputAnalyzer output) { From 7f6804ceb63568d72e825d45b02d08f314c9b0fc Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Wed, 26 Jun 2024 09:09:13 +0000 Subject: [PATCH 051/288] 8334872: BigEndian: java/lang/invoke/condy Tests failing since JDK-8294960 Reviewed-by: redestad --- .../java/lang/invoke/ClassSpecializer.java | 386 ++++++++++-------- 1 file changed, 206 insertions(+), 180 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java index cca05a906ff08..1df3b3c662825 100644 --- a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java +++ b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java @@ -31,6 +31,7 @@ import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.LambdaForm.BasicType; +import java.lang.invoke.InnerClassLambdaMetafactory.MethodBody; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -39,6 +40,7 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import java.util.function.Function; import jdk.internal.constant.MethodTypeDescImpl; @@ -66,6 +68,8 @@ abstract class ClassSpecializer.SpeciesDat private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); private static final ClassDesc CD_BoundMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;"); + private static final Consumer STATIC_FIELD_FLAGS = new InnerClassLambdaMetafactory.FieldFlags(ACC_STATIC); + private static final Consumer FINAL_FIELD_FLAGS = new InnerClassLambdaMetafactory.FieldFlags(ACC_FINAL); private final Class topClass; private final Class keyType; @@ -613,198 +617,220 @@ Class generateConcreteSpeciesCode(String className, ClassSpecialize byte[] generateConcreteSpeciesCodeFile(String className0, ClassSpecializer.SpeciesData speciesData) { final ClassDesc classDesc = ClassDesc.of(className0); final ClassDesc superClassDesc = classDesc(speciesData.deriveSuperClass()); - return ClassFile.of().build(classDesc, clb -> { - clb.withFlags(ACC_FINAL | ACC_SUPER) - .withSuperclass(superClassDesc) - .with(SourceFileAttribute.of(classDesc.displayName())) - - // emit static types and BMH_SPECIES fields - .withField(sdFieldName, CD_SPECIES_DATA, ACC_STATIC); - - // handy holder for dealing with groups of typed values (ctor arguments and fields) - class Var { - final int index; - final String name; - final Class type; - final ClassDesc desc; - final BasicType basicType; - final int slotIndex; - Var(int index, int slotIndex) { - this.index = index; - this.slotIndex = slotIndex; - name = null; type = null; desc = null; - basicType = BasicType.V_TYPE; - } - Var(String name, Class type, Var prev) { - int slotIndex = prev.nextSlotIndex(); - int index = prev.nextIndex(); - if (name == null) name = "x"; - if (name.endsWith("#")) - name = name.substring(0, name.length()-1) + index; - assert(!type.equals(void.class)); - this.index = index; - this.name = name; - this.type = type; - this.desc = classDesc(type); - this.basicType = BasicType.basicType(type); - this.slotIndex = slotIndex; - } - Var lastOf(List vars) { - int n = vars.size(); - return (n == 0 ? this : vars.get(n-1)); - } - List fromTypes(List types) { - Var prev = this; - ArrayList result = new ArrayList<>(types.size()); - int i = 0; - for (X x : types) { - String vn = name; - Class vt; - if (x instanceof Class cl) { - vt = cl; - // make the names friendlier if debugging - assert((vn = vn + "_" + (i++)) != null); - } else { - @SuppressWarnings("unchecked") - Var v = (Var) x; - vn = v.name; - vt = v.type; + return ClassFile.of().build(classDesc, new Consumer() { + @Override + public void accept(ClassBuilder clb) { + clb.withFlags(ACC_FINAL | ACC_SUPER) + .withSuperclass(superClassDesc) + .with(SourceFileAttribute.of(classDesc.displayName())) + + // emit static types and BMH_SPECIES fields + .withField(sdFieldName, CD_SPECIES_DATA, STATIC_FIELD_FLAGS); + + // handy holder for dealing with groups of typed values (ctor arguments and fields) + class Var { + final int index; + final String name; + final Class type; + final ClassDesc desc; + final BasicType basicType; + final int slotIndex; + Var(int index, int slotIndex) { + this.index = index; + this.slotIndex = slotIndex; + name = null; type = null; desc = null; + basicType = BasicType.V_TYPE; + } + Var(String name, Class type, Var prev) { + int slotIndex = prev.nextSlotIndex(); + int index = prev.nextIndex(); + if (name == null) name = "x"; + if (name.endsWith("#")) + name = name.substring(0, name.length()-1) + index; + assert(!type.equals(void.class)); + this.index = index; + this.name = name; + this.type = type; + this.desc = classDesc(type); + this.basicType = BasicType.basicType(type); + this.slotIndex = slotIndex; + } + Var lastOf(List vars) { + int n = vars.size(); + return (n == 0 ? this : vars.get(n-1)); + } + List fromTypes(List types) { + Var prev = this; + ArrayList result = new ArrayList<>(types.size()); + int i = 0; + for (X x : types) { + String vn = name; + Class vt; + if (x instanceof Class cl) { + vt = cl; + // make the names friendlier if debugging + assert((vn = vn + "_" + (i++)) != null); + } else { + @SuppressWarnings("unchecked") + Var v = (Var) x; + vn = v.name; + vt = v.type; + } + prev = new Var(vn, vt, prev); + result.add(prev); } - prev = new Var(vn, vt, prev); - result.add(prev); + return result; } - return result; - } - - int slotSize() { return basicType.basicTypeSlots(); } - int nextIndex() { return index + (slotSize() == 0 ? 0 : 1); } - int nextSlotIndex() { return slotIndex >= 0 ? slotIndex + slotSize() : slotIndex; } - boolean isInHeap() { return slotIndex < 0; } - void emitLoadInstruction(CodeBuilder cob) { - cob.loadLocal(basicType.btKind, slotIndex); - } - } - - final Var NO_THIS = new Var(0, 0), - AFTER_THIS = new Var(0, 1), - IN_HEAP = new Var(0, -1); - - // figure out the field types - final List> fieldTypes = speciesData.fieldTypes(); - final List fields = new ArrayList<>(fieldTypes.size()); - { - Var nextF = IN_HEAP; - for (Class ft : fieldTypes) { - String fn = chooseFieldName(ft, nextF.nextIndex()); - nextF = new Var(fn, ft, nextF); - fields.add(nextF); - } - } - - // emit bound argument fields - for (Var field : fields) { - clb.withField(field.name, field.desc, ACC_FINAL); - } - - // emit implementation of speciesData() - clb.withMethodBody(SPECIES_DATA_NAME, MTD_SPECIES_DATA, (SPECIES_DATA_MODS & ACC_PPP) | ACC_FINAL, - cob -> cob.getstatic(classDesc, sdFieldName, CD_SPECIES_DATA) - .areturn()); - // figure out the constructor arguments - MethodType superCtorType = ClassSpecializer.this.baseConstructorType(); - MethodType thisCtorType = superCtorType.appendParameterTypes(fieldTypes); - - // emit constructor - clb.withMethodBody(INIT_NAME, methodDesc(thisCtorType), ACC_PRIVATE, cob -> { - cob.aload(0); // this - - final List ctorArgs = AFTER_THIS.fromTypes(superCtorType.parameterList()); - for (Var ca : ctorArgs) { - ca.emitLoadInstruction(cob); + int slotSize() { return basicType.basicTypeSlots(); } + int nextIndex() { return index + (slotSize() == 0 ? 0 : 1); } + int nextSlotIndex() { return slotIndex >= 0 ? slotIndex + slotSize() : slotIndex; } + boolean isInHeap() { return slotIndex < 0; } + void emitLoadInstruction(CodeBuilder cob) { + cob.loadLocal(basicType.btKind, slotIndex); + } } - // super(ca...) - cob.invokespecial(superClassDesc, INIT_NAME, methodDesc(superCtorType)); - - // store down fields - Var lastFV = AFTER_THIS.lastOf(ctorArgs); - for (Var f : fields) { - // this.argL1 = argL1 - cob.aload(0); // this - lastFV = new Var(f.name, f.type, lastFV); - lastFV.emitLoadInstruction(cob); - cob.putfield(classDesc, f.name, f.desc); + final Var NO_THIS = new Var(0, 0), + AFTER_THIS = new Var(0, 1), + IN_HEAP = new Var(0, -1); + + // figure out the field types + final List> fieldTypes = speciesData.fieldTypes(); + final List fields = new ArrayList<>(fieldTypes.size()); + { + Var nextF = IN_HEAP; + for (Class ft : fieldTypes) { + String fn = chooseFieldName(ft, nextF.nextIndex()); + nextF = new Var(fn, ft, nextF); + fields.add(nextF); + } } - cob.return_(); - }); - - // emit make() ...factory method wrapping constructor - MethodType ftryType = thisCtorType.changeReturnType(topClass()); - clb.withMethodBody("make", methodDesc(ftryType), ACC_STATIC, cob -> { - // make instance - cob.new_(classDesc) - .dup(); - // load factory method arguments: ctarg... and arg... - for (Var v : NO_THIS.fromTypes(ftryType.parameterList())) { - v.emitLoadInstruction(cob); + // emit bound argument fields + for (Var field : fields) { + clb.withField(field.name, field.desc, FINAL_FIELD_FLAGS); } - // finally, invoke the constructor and return - cob.invokespecial(classDesc, INIT_NAME, methodDesc(thisCtorType)) - .areturn(); - }); - - // For each transform, emit the customized override of the transform method. - // This method mixes together some incoming arguments (from the transform's - // static type signature) with the field types themselves, and passes - // the resulting mish-mosh of values to a method handle produced by - // the species itself. (Typically this method handle is the factory - // method of this species or a related one.) - for (int i = 0; i < TRANSFORM_NAMES.size(); i++) { - final int whichtm = i; - final String TNAME = TRANSFORM_NAMES.get(whichtm); - final MethodType TTYPE = TRANSFORM_TYPES.get(whichtm); - final int TMODS = TRANSFORM_MODS.get(whichtm); - clb.withMethod(TNAME, methodDesc(TTYPE), (TMODS & ACC_PPP) | ACC_FINAL, mb -> { - mb.with(ExceptionsAttribute.ofSymbols(CD_Throwable)) - .withCode(cob -> { - // return a call to the corresponding "transform helper", something like this: - // MY_SPECIES.transformHelper(whichtm).invokeBasic(ctarg, ..., argL0, ..., xarg) - cob.getstatic(classDesc, sdFieldName, CD_SPECIES_DATA) - .loadConstant(whichtm) - .invokevirtual(CD_SPECIES_DATA, "transformHelper", MTD_TRANFORM_HELPER); - - List targs = AFTER_THIS.fromTypes(TTYPE.parameterList()); - List tfields = new ArrayList<>(fields); - // mix them up and load them for the transform helper: - List helperArgs = speciesData.deriveTransformHelperArguments(transformMethods.get(whichtm), whichtm, targs, tfields); - ClassDesc[] helperTypes = new ClassDesc[helperArgs.size()]; - for (int hi = 0; hi < helperTypes.length; hi++) { - Var ha = helperArgs.get(hi); - helperTypes[hi] = ha.basicType.basicTypeWrapper().basicClassDescriptor(); - if (ha.isInHeap()) { - assert(tfields.contains(ha)); - cob.aload(0); - cob.getfield(classDesc, ha.name, ha.desc); - } else { - assert(targs.contains(ha)); - ha.emitLoadInstruction(cob); + // emit implementation of speciesData() + clb.withMethod(SPECIES_DATA_NAME, MTD_SPECIES_DATA, (SPECIES_DATA_MODS & ACC_PPP) | ACC_FINAL, + new MethodBody(new Consumer() { + @Override + public void accept(CodeBuilder cob) { + cob.getstatic(classDesc, sdFieldName, CD_SPECIES_DATA) + .areturn(); } - } - - // jump into the helper (which is probably a factory method) - final Class rtype = TTYPE.returnType(); - if (!rtype.isPrimitive()) { - cob.invokevirtual(CD_MethodHandle, "invokeBasic", MethodTypeDescImpl.ofValidated(CD_Object, helperTypes)) - .checkcast(classDesc(rtype)) - .areturn(); - } else { - throw newInternalError("NYI: transform of type "+rtype); + })); + + // figure out the constructor arguments + MethodType superCtorType = ClassSpecializer.this.baseConstructorType(); + MethodType thisCtorType = superCtorType.appendParameterTypes(fieldTypes); + + // emit constructor + clb.withMethod(INIT_NAME, methodDesc(thisCtorType), ACC_PRIVATE, + new MethodBody(new Consumer() { + @Override + public void accept(CodeBuilder cob) { + cob.aload(0); // this + + final List ctorArgs = AFTER_THIS.fromTypes(superCtorType.parameterList()); + for (Var ca : ctorArgs) { + ca.emitLoadInstruction(cob); + } + + // super(ca...) + cob.invokespecial(superClassDesc, INIT_NAME, methodDesc(superCtorType)); + + // store down fields + Var lastFV = AFTER_THIS.lastOf(ctorArgs); + for (Var f : fields) { + // this.argL1 = argL1 + cob.aload(0); // this + lastFV = new Var(f.name, f.type, lastFV); + lastFV.emitLoadInstruction(cob); + cob.putfield(classDesc, f.name, f.desc); + } + + cob.return_(); + } + })); + + // emit make() ...factory method wrapping constructor + MethodType ftryType = thisCtorType.changeReturnType(topClass()); + clb.withMethod("make", methodDesc(ftryType), ACC_STATIC, + new MethodBody(new Consumer() { + @Override + public void accept(CodeBuilder cob) { + // make instance + cob.new_(classDesc) + .dup(); + // load factory method arguments: ctarg... and arg... + for (Var v : NO_THIS.fromTypes(ftryType.parameterList())) { + v.emitLoadInstruction(cob); + } + + // finally, invoke the constructor and return + cob.invokespecial(classDesc, INIT_NAME, methodDesc(thisCtorType)) + .areturn(); + } + })); + + // For each transform, emit the customized override of the transform method. + // This method mixes together some incoming arguments (from the transform's + // static type signature) with the field types themselves, and passes + // the resulting mish-mosh of values to a method handle produced by + // the species itself. (Typically this method handle is the factory + // method of this species or a related one.) + for (int i = 0; i < TRANSFORM_NAMES.size(); i++) { + final int whichtm = i; + final String TNAME = TRANSFORM_NAMES.get(whichtm); + final MethodType TTYPE = TRANSFORM_TYPES.get(whichtm); + final int TMODS = TRANSFORM_MODS.get(whichtm); + clb.withMethod(TNAME, methodDesc(TTYPE), (TMODS & ACC_PPP) | ACC_FINAL, new Consumer() { + @Override + public void accept(MethodBuilder mb) { + mb.with(ExceptionsAttribute.ofSymbols(CD_Throwable)) + .withCode(new Consumer() { + @Override + public void accept(CodeBuilder cob) { + // return a call to the corresponding "transform helper", something like this: + // MY_SPECIES.transformHelper(whichtm).invokeBasic(ctarg, ..., argL0, ..., xarg) + cob.getstatic(classDesc, sdFieldName, CD_SPECIES_DATA) + .loadConstant(whichtm) + .invokevirtual(CD_SPECIES_DATA, "transformHelper", MTD_TRANFORM_HELPER); + + List targs = AFTER_THIS.fromTypes(TTYPE.parameterList()); + List tfields = new ArrayList<>(fields); + // mix them up and load them for the transform helper: + List helperArgs = speciesData.deriveTransformHelperArguments(transformMethods.get(whichtm), whichtm, targs, tfields); + ClassDesc[] helperTypes = new ClassDesc[helperArgs.size()]; + for (int hi = 0; hi < helperTypes.length; hi++) { + Var ha = helperArgs.get(hi); + helperTypes[hi] = ha.basicType.basicTypeWrapper().basicClassDescriptor(); + if (ha.isInHeap()) { + assert(tfields.contains(ha)); + cob.aload(0); + cob.getfield(classDesc, ha.name, ha.desc); + } else { + assert(targs.contains(ha)); + ha.emitLoadInstruction(cob); + } + } + + // jump into the helper (which is probably a factory method) + final Class rtype = TTYPE.returnType(); + if (!rtype.isPrimitive()) { + cob.invokevirtual(CD_MethodHandle, "invokeBasic", MethodTypeDescImpl.ofValidated(CD_Object, helperTypes)) + .checkcast(classDesc(rtype)) + .areturn(); + } else { + throw newInternalError("NYI: transform of type "+rtype); + } + } + }); } }); - }); + } } }); } From 4ce8822b6c53b8bd72713f1bfaf6673b91aabea4 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 26 Jun 2024 09:12:02 +0000 Subject: [PATCH 052/288] 8334037: Local class creation in lambda in pre-construction context crashes javac 8333313: NullPointerException in lambda instantiating an inner local class in prologue 8333766: Stack overflow with anonymous class in super() parameter 8334679: Wrong bug number in regression test for JDK-8334252 Co-authored-by: Archie Cobbs Reviewed-by: jlahoda, vromero --- .../sun/tools/javac/comp/CompileStates.java | 4 +- .../sun/tools/javac/comp/LambdaToMethod.java | 675 +----------------- .../com/sun/tools/javac/comp/Lower.java | 480 +++++++++++-- .../sun/tools/javac/main/JavaCompiler.java | 18 +- .../com/sun/tools/javac/tree/JCTree.java | 1 + .../com/sun/tools/javac/tree/TreeInfo.java | 2 + .../javac/SuperInit/AnonSuperLambdaCrash.java | 42 ++ .../javac/SuperInit/EarlyLocalTest1.java | 43 ++ .../javac/SuperInit/EarlyLocalTest4.java | 47 ++ .../javac/SuperInit/EarlyLocalTest5.java | 49 ++ .../javac/SuperInit/EarlyLocalTest6.java | 48 ++ .../javac/SuperInit/EarlyLocalTest7.java | 44 ++ .../SuperInit/LambdaLocalEarlyCrash.java | 57 ++ .../javac/SuperInit/LambdaOuterCapture.java | 2 +- .../javac/lambda/T8129740/Universe.java.out | 32 +- 15 files changed, 793 insertions(+), 751 deletions(-) create mode 100644 test/langtools/tools/javac/SuperInit/AnonSuperLambdaCrash.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java create mode 100644 test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java index b044f956fdf58..cbeedfcbadebb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java @@ -60,8 +60,8 @@ public enum CompileState { FLOW(5), TRANSTYPES(6), TRANSPATTERNS(7), - UNLAMBDA(8), - LOWER(9), + LOWER(8), + UNLAMBDA(9), GENERATE(10); CompileState(int value) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index 7e5dcee0e8d67..66d499f54fede 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -40,20 +40,15 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Symbol.TypeSymbol; 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.Type.MethodType; -import com.sun.tools.javac.code.Type.TypeVar; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; -import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; import com.sun.tools.javac.resources.CompilerProperties.Notes; -import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import com.sun.source.tree.MemberReferenceTree.ReferenceMode; import java.util.EnumMap; import java.util.HashMap; @@ -72,7 +67,6 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; import javax.lang.model.element.ElementKind; -import javax.lang.model.type.TypeKind; import com.sun.tools.javac.main.Option; @@ -126,9 +120,6 @@ public class LambdaToMethod extends TreeTranslator { /** deduplicate lambda implementation methods */ private final boolean deduplicateLambdas; - /** lambda proxy is a dynamic nestmate */ - private final boolean nestmateLambdas; - /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ public static final int FLAG_SERIALIZABLE = 1 << 0; @@ -175,7 +166,6 @@ private LambdaToMethod(Context context) { debugLinesOrVars = lineDebugInfo || varDebugInfo; verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication"); deduplicateLambdas = options.getBoolean("deduplicateLambdas", true); - nestmateLambdas = Target.instance(context).runtimeUseNestAccess(); } // @@ -284,6 +274,7 @@ public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMake this.attrEnv = env; this.context = null; this.contextMap = new HashMap<>(); + cdef = analyzer.analyzeAndPreprocessClass((JCClassDecl) cdef); return translate(cdef); } // @@ -297,10 +288,6 @@ public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMake */ @Override public void visitClassDef(JCClassDecl tree) { - if (tree.sym.owner.kind == PCK) { - //analyze class - tree = analyzer.analyzeAndPreprocessClass(tree); - } KlassInfo prevKlassInfo = kInfo; try { kInfo = new KlassInfo(tree); @@ -418,9 +405,7 @@ public void visitLambda(JCLambda tree) { ListBuffer syntheticInits = new ListBuffer<>(); - if (localContext.methodReferenceReceiver != null) { - syntheticInits.append(localContext.methodReferenceReceiver); - } else if (!sym.isStatic()) { + if (!sym.isStatic()) { syntheticInits.append(makeThis( sym.owner.enclClass().asType(), localContext.owner.enclClass())); @@ -433,11 +418,6 @@ public void visitLambda(JCLambda tree) { syntheticInits.append(captured_local); } } - // add captured outer this instances (used only when `this' capture itself is illegal) - for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) { - JCExpression captured_local = make.QualThis(fv.type); - syntheticInits.append(captured_local); - } //then, determine the arguments to the indy call List indy_args = translate(syntheticInits.toList(), localContext.prev); @@ -553,54 +533,6 @@ public void visitIdent(JCIdent tree) { } } - /** - * Translate qualified `this' references within a lambda to the mapped identifier - * @param tree - */ - @Override - public void visitSelect(JCFieldAccess tree) { - if (context == null || !analyzer.lambdaFieldAccessFilter(tree)) { - super.visitSelect(tree); - } else { - int prevPos = make.pos; - try { - make.at(tree); - - LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; - JCTree ltree = lambdaContext.translate(tree); - if (ltree != null) { - result = ltree; - } else { - super.visitSelect(tree); - } - } finally { - make.at(prevPos); - } - } - } - - /** - * Translate instance creation expressions with implicit enclosing instances - * @param tree - */ - @Override - public void visitNewClass(JCNewClass tree) { - if (context == null || !analyzer.lambdaNewClassFilter(context, tree)) { - super.visitNewClass(tree); - } else { - int prevPos = make.pos; - try { - make.at(tree); - - LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; - tree = lambdaContext.translate(tree); - super.visitNewClass(tree); - } finally { - make.at(prevPos); - } - } - } - @Override public void visitVarDef(JCVariableDecl tree) { LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; @@ -725,7 +657,7 @@ private JCMethodDecl makeDeserializeMethod(Symbol kSym) { deser.sym = kInfo.deserMethodSym; deser.type = kInfo.deserMethodSym.type; //System.err.printf("DESER: '%s'\n", deser); - return deser; + return lower.translateMethod(attrEnv, deser, make); } /** Make an attributed class instance creation expression. @@ -857,245 +789,8 @@ private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owne return new VarSymbol(flags | SYNTHETIC, name, type, owner); } - /** - * Set varargsElement field on a given tree (must be either a new class tree - * or a method call tree) - */ - private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { - if (varargsElement != null) { - switch (tree.getTag()) { - case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; - case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; - case TYPECAST: setVarargsIfNeeded(((JCTypeCast) tree).expr, varargsElement); break; - default: throw new AssertionError(); - } - } - } - - /** - * Convert method/constructor arguments by inserting appropriate cast - * as required by type-erasure - this is needed when bridging a lambda/method - * reference, as the bridged signature might require downcast to be compatible - * with the generated signature. - */ - private List convertArgs(Symbol meth, List args, Type varargsElement) { - Assert.check(meth.kind == MTH); - List formals = types.erasure(meth.type).getParameterTypes(); - if (varargsElement != null) { - Assert.check((meth.flags() & VARARGS) != 0); - } - return transTypes.translateArgs(args, formals, varargsElement, attrEnv); - } - // - /** - * Converts a method reference which cannot be used directly into a lambda - */ - private class MemberReferenceToLambda { - - private final JCMemberReference tree; - private final ReferenceTranslationContext localContext; - private final Symbol owner; - private final ListBuffer args = new ListBuffer<>(); - private final ListBuffer params = new ListBuffer<>(); - - private JCExpression receiverExpression = null; - - MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) { - this.tree = tree; - this.localContext = localContext; - this.owner = owner; - } - - JCLambda lambda() { - int prevPos = make.pos; - try { - make.at(tree); - - //body generation - this can be either a method call or a - //new instance creation expression, depending on the member reference kind - VarSymbol rcvr = addParametersReturnReceiver(); - JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) - ? expressionInvoke(rcvr) - : expressionNew(); - - JCLambda slam = make.Lambda(params.toList(), expr); - slam.target = tree.target; - slam.type = tree.type; - slam.pos = tree.pos; - return slam; - } finally { - make.at(prevPos); - } - } - - /** - * Generate the parameter list for the converted member reference. - * - * @return The receiver variable symbol, if any - */ - VarSymbol addParametersReturnReceiver() { - Type samDesc = localContext.bridgedRefSig(); - List samPTypes = samDesc.getParameterTypes(); - List descPTypes = tree.getDescriptorType(types).getParameterTypes(); - - // Determine the receiver, if any - VarSymbol rcvr; - switch (tree.kind) { - case BOUND: - // The receiver is explicit in the method reference - rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); - receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); - break; - case UNBOUND: - // The receiver is the first parameter, extract it and - // adjust the SAM and unerased type lists accordingly - rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); - samPTypes = samPTypes.tail; - descPTypes = descPTypes.tail; - break; - default: - rcvr = null; - break; - } - List implPTypes = tree.sym.type.getParameterTypes(); - int implSize = implPTypes.size(); - int samSize = samPTypes.size(); - // Last parameter to copy from referenced method, exclude final var args - int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize; - - // Failsafe -- assure match-up - boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); - - // Use parameter types of the implementation method unless the unerased - // SAM parameter type is an intersection type, in that case use the - // erased SAM parameter type so that the supertype relationship - // the implementation method parameters is not obscured. - // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes - // are used as pointers to the current parameter type information - // and are thus not usable afterwards. - for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { - // By default use the implementation method parameter type - Type parmType = implPTypes.head; - if (checkForIntersection) { - if (descPTypes.head.getKind() == TypeKind.INTERSECTION) { - parmType = samPTypes.head; - } - // If the unerased parameter type is a type variable whose - // bound is an intersection (eg. ) then - // use the SAM parameter type - if (descPTypes.head.getKind() == TypeKind.TYPEVAR) { - TypeVar tv = (TypeVar) descPTypes.head; - if (tv.getUpperBound().getKind() == TypeKind.INTERSECTION) { - parmType = samPTypes.head; - } - } - } - addParameter("x$" + i, parmType, true); - - // Advance to the next parameter - implPTypes = implPTypes.tail; - samPTypes = samPTypes.tail; - descPTypes = descPTypes.tail; - } - // Flatten out the var args - for (int i = last; i < samSize; ++i) { - addParameter("xva$" + i, tree.varargsElement, true); - } - - return rcvr; - } - - JCExpression getReceiverExpression() { - return receiverExpression; - } - - private JCExpression makeReceiver(VarSymbol rcvr) { - if (rcvr == null) return null; - JCExpression rcvrExpr = make.Ident(rcvr); - boolean protAccess = - isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner); - Type rcvrType = tree.ownerAccessible && !protAccess ? tree.sym.enclClass().type - : tree.expr.type; - if (rcvrType == syms.arrayClass.type) { - // Map the receiver type to the actually type, not just "array" - rcvrType = tree.getQualifierExpression().type; - } - if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { - rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); - } - return rcvrExpr; - } - - /** - * determine the receiver of the method call - the receiver can - * be a type qualifier, the synthetic receiver parameter or 'super'. - */ - private JCExpression expressionInvoke(VarSymbol rcvr) { - JCExpression qualifier = - (rcvr != null) ? - makeReceiver(rcvr) : - tree.getQualifierExpression(); - - //create the qualifier expression - JCFieldAccess select = make.Select(qualifier, tree.sym.name); - select.sym = tree.sym; - select.type = tree.sym.erasure(types); - - //create the method call expression - JCExpression apply = make.Apply(List.nil(), select, - convertArgs(tree.sym, args.toList(), tree.varargsElement)). - setType(tree.sym.erasure(types).getReturnType()); - - apply = transTypes.coerce(attrEnv, apply, - types.erasure(localContext.tree.referentType.getReturnType())); - - setVarargsIfNeeded(apply, tree.varargsElement); - return apply; - } - - /** - * Lambda body to use for a 'new'. - */ - private JCExpression expressionNew() { - if (tree.kind == ReferenceKind.ARRAY_CTOR) { - //create the array creation expression - JCNewArray newArr = make.NewArray( - make.Type(types.elemtype(tree.getQualifierExpression().type)), - List.of(make.Ident(params.first())), - null); - newArr.type = tree.getQualifierExpression().type; - return newArr; - } else { - //create the instance creation expression - //note that method reference syntax does not allow an explicit - //enclosing class (so the enclosing class is null) - // but this may need to be patched up later with the proxy for the outer this - JCNewClass newClass = make.NewClass(null, - List.nil(), - make.Type(tree.getQualifierExpression().type), - convertArgs(tree.sym, args.toList(), tree.varargsElement), - null); - newClass.constructor = tree.sym; - newClass.constructorType = tree.sym.erasure(types); - newClass.type = tree.getQualifierExpression().type; - setVarargsIfNeeded(newClass, tree.varargsElement); - return newClass; - } - } - - private VarSymbol addParameter(String name, Type p, boolean genArg) { - VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); - vsym.pos = tree.pos; - params.append(make.VarDef(vsym, null)); - if (genArg) { - args.append(make.Ident(vsym)); - } - return vsym; - } - } - private MethodType typeToMethodType(Type mt) { Type type = types.erasure(mt); return new MethodType(type.getParameterTypes(), @@ -1238,11 +933,6 @@ class LambdaAnalyzerPreprocessor extends TreeTranslator { */ private int lambdaCount = 0; - /** - * List of types undergoing construction, i.e., in an early construction context. - */ - private List typesUnderConstruction; - /** * keep the count of lambda expression defined in given context (used to * generate unambiguous names for serializable lambdas) @@ -1273,30 +963,10 @@ int getIndex(StringBuilder buf) { private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { frameStack = List.nil(); - typesUnderConstruction = List.nil(); localClassDefs = new HashMap<>(); return translate(tree); } - @Override - public void visitApply(JCMethodInvocation tree) { - super.visitApply(tree); - if (TreeInfo.isConstructorCall(tree)) { - Assert.check(typesUnderConstruction.head == currentClass()); - typesUnderConstruction = typesUnderConstruction.tail; // end of early construction context - } - } - // where - private ClassSymbol currentClass() { - for (Frame frame : frameStack) { - if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { - JCClassDecl cdef = (JCClassDecl) frame.tree; - return cdef.sym; - } - } - return null; - } - @Override public void visitBlock(JCBlock tree) { List prevStack = frameStack; @@ -1329,21 +999,6 @@ public void visitClassDef(JCClassDecl tree) { } if (directlyEnclosingLambda() != null) { tree.sym.owner = owner(); - if (tree.sym.hasOuterInstance()) { - //if a class is defined within a lambda, the lambda must capture - //its enclosing instance (if any) - TranslationContext localContext = context(); - final TypeSymbol outerInstanceSymbol = tree.sym.type.getEnclosingType().tsym; - while (localContext != null && !localContext.owner.isStatic()) { - if (localContext.tree.hasTag(LAMBDA)) { - JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol); - if (block == null) break; - ((LambdaTranslationContext)localContext) - .addSymbol(outerInstanceSymbol, CAPTURED_THIS); - } - localContext = localContext.prev; - } - } } frameStack = frameStack.prepend(new Frame(tree)); super.visitClassDef(tree); @@ -1398,16 +1053,7 @@ public void visitIdent(JCIdent tree) { @Override public void visitLambda(JCLambda tree) { - analyzeLambda(tree, "lambda.stat"); - } - - private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) { - // Translation of the receiver expression must occur first - JCExpression rcvr = translate(methodReferenceReceiver); - LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1"); - if (rcvr != null) { - context.methodReferenceReceiver = rcvr; - } + analyzeLambda(tree, tree.wasMethodReference ? "mref.stat.1" : "lambda.stat"); } private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) { @@ -1434,85 +1080,14 @@ private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) { @Override public void visitMethodDef(JCMethodDecl tree) { - List prevTypesUnderConstruction = typesUnderConstruction; List prevStack = frameStack; try { - if (TreeInfo.isConstructor(tree)) // start early construction context (Object() notwithstanding) - typesUnderConstruction = typesUnderConstruction.prepend(currentClass()); frameStack = frameStack.prepend(new Frame(tree)); super.visitMethodDef(tree); - } finally { - frameStack = prevStack; - typesUnderConstruction = prevTypesUnderConstruction; - } - } - - @Override - public void visitNewClass(JCNewClass tree) { - TypeSymbol def = tree.type.tsym; - boolean inReferencedClass = currentlyInClass(def); - boolean isLocal = def.isDirectlyOrIndirectlyLocal(); - if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) { - TranslationContext localContext = context(); - final TypeSymbol outerInstanceSymbol = tree.type.getEnclosingType().tsym; - while (localContext != null && !localContext.owner.isStatic()) { - if (localContext.tree.hasTag(LAMBDA)) { - if (outerInstanceSymbol != null) { - JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol); - if (block == null) break; - } - ((LambdaTranslationContext)localContext) - .addSymbol(outerInstanceSymbol, CAPTURED_THIS); - } - localContext = localContext.prev; - } } - super.visitNewClass(tree); - if (context() != null && !inReferencedClass && isLocal) { - LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); - captureLocalClassDefs(def, lambdaContext); - } - } - //where - void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) { - JCClassDecl localCDef = localClassDefs.get(csym); - if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) { - BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() { - @Override - void addFreeVars(ClassSymbol c) { - captureLocalClassDefs(c, lambdaContext); - } - @Override - void visitSymbol(Symbol sym) { - if (sym.kind == VAR && - sym.owner.kind == MTH && - ((VarSymbol)sym).getConstValue() == null) { - TranslationContext localContext = context(); - while (localContext != null) { - if (localContext.tree.getTag() == LAMBDA) { - JCTree block = capturedDecl(localContext.depth, sym); - if (block == null) break; - ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR); - } - localContext = localContext.prev; - } - } - } - }; - fvc.scan(localCDef); - } - } - //where - boolean currentlyInClass(Symbol csym) { - for (Frame frame : frameStack) { - if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { - JCClassDecl cdef = (JCClassDecl) frame.tree; - if (cdef.sym == csym) { - return true; - } - } + finally { + frameStack = prevStack; } - return false; } /** @@ -1531,15 +1106,9 @@ boolean currentlyInClass(Symbol csym) { public void visitReference(JCMemberReference tree) { ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree); contextMap.put(tree, rcontext); - if (rcontext.needsConversionToLambda()) { - // Convert to a lambda, and process as such - MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner()); - analyzeLambda(conv.lambda(), conv.getReceiverExpression()); - } else { - super.visitReference(tree); - if (dumpLambdaToMethodStats) { - log.note(tree, Notes.MrefStat(rcontext.needsAltMetafactory(), null)); - } + super.visitReference(tree); + if (dumpLambdaToMethodStats) { + log.note(tree, Notes.MrefStat(rcontext.needsAltMetafactory(), null)); } } @@ -1773,42 +1342,6 @@ private boolean lambdaIdentSymbolFilter(Symbol sym) { && sym.name != names.init; } - /** - * This is used to filter out those select nodes that need to be adjusted - * when translating away lambda expressions - at the moment, this is the - * set of nodes that select `this' (qualified this) - */ - private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) { - return (context instanceof LambdaTranslationContext lambdaContext) - && !fAccess.sym.isStatic() - && fAccess.name == names._this - && (fAccess.sym.owner.kind == TYP) - && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty(); - } - - /** - * This is used to filter out those new class expressions that need to - * be qualified with an enclosing tree - */ - private boolean lambdaNewClassFilter(TranslationContext context, JCNewClass tree) { - if (context != null - && tree.encl == null - && tree.def == null - && !tree.type.getEnclosingType().hasTag(NONE)) { - Type encl = tree.type.getEnclosingType(); - Type current = context.owner.enclClass().type; - while (!current.hasTag(NONE)) { - if (current.tsym.isSubClass(encl.tsym, types)) { - return true; - } - current = current.getEnclosingType(); - } - return false; - } else { - return false; - } - } - private class Frame { final JCTree tree; List locals; @@ -1918,18 +1451,6 @@ class LambdaTranslationContext extends TranslationContext { List syntheticParams; - /** - * to prevent recursion, track local classes processed - */ - final Set freeVarProcessedLocalClasses; - - /** - * For method references converted to lambdas. The method - * reference receiver expression. Must be treated like a captured - * variable. - */ - JCExpression methodReferenceReceiver; - LambdaTranslationContext(JCLambda tree) { super(tree); Frame frame = frameStack.head; @@ -1960,13 +1481,10 @@ public MethodSymbol originalEnclosingMethod() { } translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); - translatedSymbols.put(PARAM, new LinkedHashMap()); - translatedSymbols.put(LOCAL_VAR, new LinkedHashMap()); - translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap()); - translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap()); - translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap()); - - freeVarProcessedLocalClasses = new HashSet<>(); + translatedSymbols.put(PARAM, new LinkedHashMap<>()); + translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<>()); + translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<>()); + translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<>()); } /** @@ -2066,16 +1584,6 @@ public Symbol baseSymbol() { } }; break; - case CAPTURED_OUTER_THIS: - Name name = names.fromString(sym.flatName().toString().replace('.', '$') + names.dollarThis); - ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) { - @Override - public Symbol baseSymbol() { - //keep mapping with original captured symbol - return sym; - } - }; - break; case LOCAL_VAR: ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym) { @Override @@ -2114,14 +1622,6 @@ public Symbol baseSymbol() { } void addSymbol(Symbol sym, LambdaSymbolKind skind) { - if (skind == CAPTURED_THIS && sym != null && sym.kind == TYP && !typesUnderConstruction.isEmpty()) { - ClassSymbol currentClass = currentClass(); - if (currentClass != null && typesUnderConstruction.contains(currentClass)) { - // reference must be to enclosing outer instance, mutate capture kind. - Assert.check(sym != currentClass); // should have been caught right in Attr - skind = CAPTURED_OUTER_THIS; - } - } Map transMap = getSymbolMap(skind); if (!transMap.containsKey(sym)) { transMap.put(sym, translate(sym, skind)); @@ -2145,54 +1645,11 @@ JCTree translate(JCIdent lambdaIdent) { return t; } break; - case CAPTURED_OUTER_THIS: - Optional proxy = m.keySet().stream() - .filter(out -> lambdaIdent.sym.isMemberOf(out.type.tsym, types)) - .reduce((a, b) -> a.isEnclosedBy((ClassSymbol)b) ? a : b); - if (proxy.isPresent()) { - // Transform outer instance variable references anchoring them to the captured synthetic. - Symbol tSym = m.get(proxy.get()); - JCExpression t = make.Ident(tSym).setType(lambdaIdent.sym.owner.type); - t = make.Select(t, lambdaIdent.name); - t.setType(lambdaIdent.type); - TreeInfo.setSymbol(t, lambdaIdent.sym); - return t; - } - break; } } return null; } - /* Translate away qualified this expressions, anchoring them to synthetic parameters that - capture the qualified this handle. `fieldAccess' is guaranteed to one such. - */ - public JCTree translate(JCFieldAccess fieldAccess) { - Assert.check(fieldAccess.name == names._this); - Map m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS); - if (m.containsKey(fieldAccess.sym.owner)) { - Symbol tSym = m.get(fieldAccess.sym.owner); - JCExpression t = make.Ident(tSym).setType(fieldAccess.sym.owner.type); - return t; - } - return null; - } - - /* Translate away naked new instance creation expressions with implicit enclosing instances, - anchoring them to synthetic parameters that stand proxy for the qualified outer this handle. - */ - public JCNewClass translate(JCNewClass newClass) { - Assert.check(newClass.clazz.type.tsym.hasOuterInstance() && newClass.encl == null); - Map m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS); - final Type enclosingType = newClass.clazz.type.getEnclosingType(); - if (m.containsKey(enclosingType.tsym)) { - Symbol tSym = m.get(enclosingType.tsym); - JCExpression encl = make.Ident(tSym).setType(enclosingType); - newClass.encl = encl; - } - return newClass; - } - /** * The translatedSym is not complete/accurate until the analysis is * finished. Once the analysis is finished, the translatedSym is @@ -2230,10 +1687,6 @@ void complete() { params.append(make.VarDef((VarSymbol) thisSym, null)); parameterSymbols.append((VarSymbol) thisSym); } - for (Symbol thisSym : getSymbolMap(CAPTURED_OUTER_THIS).values()) { - params.append(make.VarDef((VarSymbol) thisSym, null)); - parameterSymbols.append((VarSymbol) thisSym); - } for (Symbol thisSym : getSymbolMap(PARAM).values()) { params.append(make.VarDef((VarSymbol) thisSym, null)); parameterSymbols.append((VarSymbol) thisSym); @@ -2259,102 +1712,12 @@ Type generatedLambdaSig() { } /** - * This class retains all the useful information about a method reference; - * the contents of this class are filled by the LambdaAnalyzer visitor, - * and the used by the main translation routines in order to adjust method - * references (i.e. in case a bridge is needed) + * Simple subclass modelling the translation context of a method reference. */ final class ReferenceTranslationContext extends TranslationContext { - final boolean isSuper; - ReferenceTranslationContext(JCMemberReference tree) { super(tree); - this.isSuper = tree.hasKind(ReferenceKind.SUPER); - } - - boolean needsVarArgsConversion() { - return tree.varargsElement != null; - } - - /** - * @return Is this an array operation like clone() - */ - boolean isArrayOp() { - return tree.sym.owner == syms.arrayClass; - } - - boolean receiverAccessible() { - //hack needed to workaround 292 bug (7087658) - //when 292 issue is fixed we should remove this and change the backend - //code to always generate a method handle to an accessible method - return tree.ownerAccessible; - } - - /** - * This method should be called only when target release <= 14 - * where LambdaMetaFactory does not spin nestmate classes. - * - * This method should be removed when --release 14 is not supported. - */ - boolean isPrivateInOtherClass() { - assert !nestmateLambdas; - return (tree.sym.flags() & PRIVATE) != 0 && - !types.isSameType( - types.erasure(tree.sym.enclClass().asType()), - types.erasure(owner.enclClass().asType())); - } - - /** - * Erasure destroys the implementation parameter subtype - * relationship for intersection types. - * Have similar problems for union types too. - */ - boolean interfaceParameterIsIntersectionOrUnionType() { - List tl = tree.getDescriptorType(types).getParameterTypes(); - for (; tl.nonEmpty(); tl = tl.tail) { - Type pt = tl.head; - if (isIntersectionOrUnionType(pt)) - return true; - } - return false; - } - - boolean isIntersectionOrUnionType(Type t) { - switch (t.getKind()) { - case INTERSECTION: - case UNION: - return true; - case TYPEVAR: - TypeVar tv = (TypeVar) t; - return isIntersectionOrUnionType(tv.getUpperBound()); - } - return false; - } - - /** - * Does this reference need to be converted to a lambda - * (i.e. var args need to be expanded or "super" is used) - */ - final boolean needsConversionToLambda() { - return interfaceParameterIsIntersectionOrUnionType() || - isSuper || - needsVarArgsConversion() || - isArrayOp() || - (!nestmateLambdas && isPrivateInOtherClass()) || - isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner) || - !receiverAccessible() || - (tree.getMode() == ReferenceMode.NEW && - tree.kind != ReferenceKind.ARRAY_CTOR && - (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner())); - } - - Type generatedRefSig() { - return types.erasure(tree.sym.type); - } - - Type bridgedRefSig() { - return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type); } } } @@ -2368,14 +1731,12 @@ enum LambdaSymbolKind { PARAM, // original to translated lambda parameters LOCAL_VAR, // original to translated lambda locals CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters - CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) - CAPTURED_OUTER_THIS; // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740) + CAPTURED_THIS; // class symbols to translated synthetic parameters (for captured member access) boolean propagateAnnotations() { switch (this) { case CAPTURED_VAR: case CAPTURED_THIS: - case CAPTURED_OUTER_THIS: return false; default: return true; @@ -2417,12 +1778,6 @@ private String classSig(Type type) { } } - private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference, - Symbol currentClass) { - return ((targetReference.flags() & PROTECTED) != 0 && - targetReference.packge() != currentClass.packge()); - } - /** * Signature Generation */ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index da0e3f9c747ac..7ab38e86366be 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -28,6 +28,8 @@ import java.util.*; import java.util.stream.Collectors; +import com.sun.source.tree.LambdaExpressionTree.BodyKind; +import com.sun.source.tree.MemberReferenceTree.ReferenceMode; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Kinds.KindSelector; import com.sun.tools.javac.code.Scope.WriteableScope; @@ -35,7 +37,9 @@ import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.main.Option.PkgInfo; import com.sun.tools.javac.resources.CompilerProperties.Fragments; +import com.sun.tools.javac.resources.CompilerProperties.Notes; import com.sun.tools.javac.tree.*; +import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; @@ -62,6 +66,9 @@ import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT; import com.sun.tools.javac.tree.JCTree.JCSwitchExpression; + +import javax.lang.model.type.TypeKind; + import static com.sun.tools.javac.tree.JCTree.Tag.*; /** This pass translates away some syntactic sugar: inner classes, @@ -103,6 +110,7 @@ public static Lower instance(Context context) { private final boolean optimizeOuterThis; private final boolean useMatchException; private final HashMap typePairToName; + private int variableIndex = 0; @SuppressWarnings("this-escape") protected Lower(Context context) { @@ -170,6 +178,11 @@ protected Lower(Context context) { */ Map actualSymbols; + /** + * The current expected return type. + */ + Type currentRestype; + /** The current method definition. */ JCMethodDecl currentMethodDef; @@ -186,12 +199,6 @@ protected Lower(Context context) { */ JCTree outermostMemberDef; - /** A map from local variable symbols to their translation (as per LambdaToMethod). - * This is required when a capturing local class is created from a lambda (in which - * case the captured symbols should be replaced with the translated lambda symbols). - */ - Map lambdaTranslationMap = null; - /** A navigator class for assembling a mapping from local class symbols * to class definition trees. * There is only one case; all other cases simply traverse down the tree. @@ -1233,14 +1240,10 @@ JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean make.at(tree.pos); return makeLit(sym.type, cv); } - if (lambdaTranslationMap != null && lambdaTranslationMap.get(sym) != null) { - return make.at(tree.pos).Ident(lambdaTranslationMap.get(sym)); - } else { - // Otherwise replace the variable by its proxy. - sym = proxies.get(sym); - Assert.check(sym != null && (sym.flags_field & FINAL) != 0); - tree = make.at(tree.pos).Ident(sym); - } + // Otherwise replace the variable by its proxy. + sym = proxies.get(sym); + Assert.check(sym != null && (sym.flags_field & FINAL) != 0); + tree = make.at(tree.pos).Ident(sym); } JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null; switch (sym.kind) { @@ -1325,14 +1328,6 @@ JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean accessBase(tree.pos(), sym), sym).setType(tree.type); } } - } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) { - //sym is a local variable - check the lambda translation map to - //see if sym has been translated to something else in the current - //scope (by LambdaToMethod) - Symbol translatedSym = lambdaTranslationMap.get(sym.baseSymbol()); - if (translatedSym != null) { - tree = make.at(tree.pos).Ident(translatedSym); - } } } return tree; @@ -2779,15 +2774,21 @@ public void visitMethodDef(JCMethodDecl tree) { syms.methodClass); } + Type prevRestype = currentRestype; JCMethodDecl prevMethodDef = currentMethodDef; MethodSymbol prevMethodSym = currentMethodSym; + int prevVariableIndex = variableIndex; try { + currentRestype = types.erasure(tree.type.getReturnType()); currentMethodDef = tree; currentMethodSym = tree.sym; + variableIndex = 0; visitMethodDefInternal(tree); } finally { + currentRestype = prevRestype; currentMethodDef = prevMethodDef; currentMethodSym = prevMethodSym; + variableIndex = prevVariableIndex; } } @@ -2866,16 +2867,7 @@ private void visitMethodDefInternal(JCMethodDecl tree) { outerThisStack = prevOuterThisStack; } else { - Map prevLambdaTranslationMap = - lambdaTranslationMap; - try { - lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 && - tree.sym.name.startsWith(names.lambda) ? - makeTranslationMap(tree) : null; - super.visitMethodDef(tree); - } finally { - lambdaTranslationMap = prevLambdaTranslationMap; - } + super.visitMethodDef(tree); } if (tree.name == names.init && ((tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 || (tree.sym.flags_field & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD))) { @@ -2901,17 +2893,6 @@ private void visitMethodDefInternal(JCMethodDecl tree) { } result = tree; } - //where - private Map makeTranslationMap(JCMethodDecl tree) { - Map translationMap = new HashMap<>(); - for (JCVariableDecl vd : tree.params) { - Symbol p = vd.sym; - if (p != p.baseSymbol()) { - translationMap.put(p.baseSymbol(), p); - } - } - return translationMap; - } public void visitTypeCast(JCTypeCast tree) { tree.clazz = translate(tree.clazz); @@ -2973,7 +2954,7 @@ public void visitTypeTest(JCInstanceOf tree) { // preserving the side effects of the value VarSymbol dollar_s = new VarSymbol(FINAL | SYNTHETIC, - names.fromString("tmp" + tree.pos + this.target.syntheticNameChar()), + names.fromString("tmp" + variableIndex++ + this.target.syntheticNameChar()), types.erasure(tree.expr.type), currentMethodSym); JCStatement var = make.at(tree.pos()) @@ -3132,13 +3113,7 @@ public void visitNewClass(JCNewClass tree) { // If we have an anonymous class, create its flat version, rather // than the class or interface following new. if (tree.def != null) { - Map prevLambdaTranslationMap = lambdaTranslationMap; - try { - lambdaTranslationMap = null; - translate(tree.def); - } finally { - lambdaTranslationMap = prevLambdaTranslationMap; - } + translate(tree.def); tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym)); tree.def = null; @@ -3358,6 +3333,9 @@ public void visitApply(JCMethodInvocation tree) { return; } } + if (tree.args.stream().anyMatch(c -> c == null)) { + throw new AssertionError("Whooops before: " + tree); + } result = tree; } @@ -3845,6 +3823,7 @@ private void visitIterableForeachLoop(JCEnhancedForLoop tree) { public void visitVarDef(JCVariableDecl tree) { MethodSymbol oldMethodSym = currentMethodSym; + int prevVariableIndex = variableIndex; tree.mods = translate(tree.mods); tree.vartype = translate(tree.vartype); if (currentMethodSym == null) { @@ -3854,9 +3833,13 @@ public void visitVarDef(JCVariableDecl tree) { names.empty, null, currentClass); } - if (tree.init != null) tree.init = translate(tree.init, tree.type); - result = tree; - currentMethodSym = oldMethodSym; + try { + if (tree.init != null) tree.init = translate(tree.init, tree.type); + result = tree; + } finally { + currentMethodSym = oldMethodSym; + variableIndex = prevVariableIndex; + } } public void visitBlock(JCBlock tree) { @@ -3868,8 +3851,14 @@ public void visitBlock(JCBlock tree) { names.empty, null, currentClass); } - super.visitBlock(tree); - currentMethodSym = oldMethodSym; + int prevVariableIndex = variableIndex; + try { + variableIndex = 0; + super.visitBlock(tree); + } finally { + currentMethodSym = oldMethodSym; + variableIndex = prevVariableIndex; + } } public void visitDoLoop(JCDoWhileLoop tree) { @@ -3896,11 +3885,355 @@ public void visitForLoop(JCForLoop tree) { public void visitReturn(JCReturn tree) { if (tree.expr != null) tree.expr = translate(tree.expr, - types.erasure(currentMethodDef - .restype.type)); + currentRestype); result = tree; } + @Override + public void visitLambda(JCLambda tree) { + Type prevRestype = currentRestype; + try { + currentRestype = types.erasure(tree.getDescriptorType(types)).getReturnType(); + tree.body = tree.getBodyKind() == BodyKind.EXPRESSION ? + translate((JCExpression) tree.body, currentRestype) : + translate(tree.body); + } finally { + currentRestype = prevRestype; + } + result = tree; + } + + @Override + public void visitReference(JCMemberReference tree) { + if (needsConversionToLambda(tree)) { + // Convert to a lambda, and process as such + MemberReferenceToLambda conv = new MemberReferenceToLambda(tree); + result = translate(conv.lambda()); + } else { + super.visitReference(tree); + } + } + // where + boolean needsVarArgsConversion(JCMemberReference tree) { + return tree.varargsElement != null; + } + + /** + * @return Is this an array operation like clone() + */ + boolean isArrayOp(JCMemberReference tree) { + return tree.sym.owner == syms.arrayClass; + } + + boolean receiverAccessible(JCMemberReference tree) { + //hack needed to workaround 292 bug (7087658) + //when 292 issue is fixed we should remove this and change the backend + //code to always generate a method handle to an accessible method + return tree.ownerAccessible; + } + + /** + * Erasure destroys the implementation parameter subtype + * relationship for intersection types. + * Have similar problems for union types too. + */ + boolean interfaceParameterIsIntersectionOrUnionType(JCMemberReference tree) { + List tl = tree.getDescriptorType(types).getParameterTypes(); + for (; tl.nonEmpty(); tl = tl.tail) { + Type pt = tl.head; + if (isIntersectionOrUnionType(pt)) + return true; + } + return false; + } + + boolean isIntersectionOrUnionType(Type t) { + switch (t.getKind()) { + case INTERSECTION: + case UNION: + return true; + case TYPEVAR: + TypeVar tv = (TypeVar) t; + return isIntersectionOrUnionType(tv.getUpperBound()); + } + return false; + } + + private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference, + Symbol currentClass) { + return ((targetReference.flags() & PROTECTED) != 0 && + targetReference.packge() != currentClass.packge()); + } + + /** + * This method should be called only when target release <= 14 + * where LambdaMetaFactory does not spin nestmate classes. + * + * This method should be removed when --release 14 is not supported. + */ + boolean isPrivateInOtherClass(JCMemberReference tree) { + assert !target.runtimeUseNestAccess(); + return (tree.sym.flags() & PRIVATE) != 0 && + !types.isSameType( + types.erasure(tree.sym.enclClass().asType()), + types.erasure(currentClass.asType())); + } + + /** + * Does this reference need to be converted to a lambda + * (i.e. var args need to be expanded or "super" is used) + */ + boolean needsConversionToLambda(JCMemberReference tree) { + return interfaceParameterIsIntersectionOrUnionType(tree) || + tree.hasKind(ReferenceKind.SUPER) || + needsVarArgsConversion(tree) || + isArrayOp(tree) || + (!target.runtimeUseNestAccess() && isPrivateInOtherClass(tree)) || + isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, currentClass) || + !receiverAccessible(tree) || + (tree.getMode() == ReferenceMode.NEW && + tree.kind != ReferenceKind.ARRAY_CTOR && + (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner())); + } + + /** + * Converts a method reference which cannot be used directly into a lambda + */ + private class MemberReferenceToLambda { + + private final JCMemberReference tree; + private final ListBuffer args = new ListBuffer<>(); + private final ListBuffer params = new ListBuffer<>(); + private final MethodSymbol owner = new MethodSymbol(0, names.empty, Type.noType, currentClass); + + private JCExpression receiverExpression = null; + + MemberReferenceToLambda(JCMemberReference tree) { + this.tree = tree; + } + + JCExpression lambda() { + int prevPos = make.pos; + try { + make.at(tree); + + //body generation - this can be either a method call or a + //new instance creation expression, depending on the member reference kind + VarSymbol rcvr = addParametersReturnReceiver(); + JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) + ? expressionInvoke(rcvr) + : expressionNew(); + + JCLambda slam = make.Lambda(params.toList(), expr); + slam.target = tree.target; + slam.type = tree.type; + slam.pos = tree.pos; + slam.wasMethodReference = true; + if (receiverExpression != null) { + // use a let expression so that the receiver expression is evaluated eagerly + return make.at(tree.pos).LetExpr( + make.VarDef(rcvr, translate(receiverExpression)), slam).setType(tree.type); + } else { + return slam; + } + } finally { + make.at(prevPos); + } + } + + /** + * Generate the parameter list for the converted member reference. + * + * @return The receiver variable symbol, if any + */ + VarSymbol addParametersReturnReceiver() { + Type samDesc = types.erasure(types.findDescriptorSymbol(tree.target.tsym).type); + List samPTypes = samDesc.getParameterTypes(); + List descPTypes = tree.getDescriptorType(types).getParameterTypes(); + + // Determine the receiver, if any + VarSymbol rcvr; + switch (tree.kind) { + case BOUND: + // The receiver is explicit in the method reference + rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner); + rcvr.pos = tree.pos; + receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); + break; + case UNBOUND: + // The receiver is the first parameter, extract it and + // adjust the SAM and unerased type lists accordingly + rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); + samPTypes = samPTypes.tail; + descPTypes = descPTypes.tail; + break; + default: + rcvr = null; + break; + } + List implPTypes = tree.sym.type.getParameterTypes(); + int implSize = implPTypes.size(); + int samSize = samPTypes.size(); + // Last parameter to copy from referenced method, exclude final var args + int last = needsVarArgsConversion(tree) ? implSize - 1 : implSize; + + // Failsafe -- assure match-up + boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); + + // Use parameter types of the implementation method unless the unerased + // SAM parameter type is an intersection type, in that case use the + // erased SAM parameter type so that the supertype relationship + // the implementation method parameters is not obscured. + // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes + // are used as pointers to the current parameter type information + // and are thus not usable afterwards. + for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { + // By default use the implementation method parameter type + Type parmType = implPTypes.head; + if (checkForIntersection) { + if (descPTypes.head.getKind() == TypeKind.INTERSECTION) { + parmType = samPTypes.head; + } + // If the unerased parameter type is a type variable whose + // bound is an intersection (eg. ) then + // use the SAM parameter type + if (descPTypes.head.getKind() == TypeKind.TYPEVAR) { + TypeVar tv = (TypeVar) descPTypes.head; + if (tv.getUpperBound().getKind() == TypeKind.INTERSECTION) { + parmType = samPTypes.head; + } + } + } + addParameter("x$" + i, parmType, true); + + // Advance to the next parameter + implPTypes = implPTypes.tail; + samPTypes = samPTypes.tail; + descPTypes = descPTypes.tail; + } + // Flatten out the var args + for (int i = last; i < samSize; ++i) { + addParameter("xva$" + i, tree.varargsElement, true); + } + + return rcvr; + } + + private JCExpression makeReceiver(VarSymbol rcvr) { + if (rcvr == null) return null; + JCExpression rcvrExpr = make.Ident(rcvr); + boolean protAccess = + isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, currentClass); + Type rcvrType = tree.ownerAccessible && !protAccess ? tree.sym.enclClass().type + : tree.expr.type; + if (rcvrType == syms.arrayClass.type) { + // Map the receiver type to the actually type, not just "array" + rcvrType = tree.getQualifierExpression().type; + } + if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { + rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); + } + return rcvrExpr; + } + + /** + * determine the receiver of the method call - the receiver can + * be a type qualifier, the synthetic receiver parameter or 'super'. + */ + private JCExpression expressionInvoke(VarSymbol rcvr) { + JCExpression qualifier = + (rcvr != null) ? + makeReceiver(rcvr) : + tree.getQualifierExpression(); + + //create the qualifier expression + JCFieldAccess select = make.Select(qualifier, tree.sym.name); + select.sym = tree.sym; + select.type = tree.sym.erasure(types); + + //create the method call expression + JCExpression apply = make.Apply(List.nil(), select, + convertArgs(tree.sym, args.toList(), tree.varargsElement)). + setType(tree.sym.erasure(types).getReturnType()); + + apply = transTypes.coerce(attrEnv, apply, + types.erasure(tree.referentType.getReturnType())); + + setVarargsIfNeeded(apply, tree.varargsElement); + return apply; + } + + /** + * Lambda body to use for a 'new'. + */ + private JCExpression expressionNew() { + if (tree.kind == ReferenceKind.ARRAY_CTOR) { + //create the array creation expression + JCNewArray newArr = make.NewArray( + make.Type(types.elemtype(tree.getQualifierExpression().type)), + List.of(make.Ident(params.first())), + null); + newArr.type = tree.getQualifierExpression().type; + return newArr; + } else { + //create the instance creation expression + //note that method reference syntax does not allow an explicit + //enclosing class (so the enclosing class is null) + // but this may need to be patched up later with the proxy for the outer this + JCNewClass newClass = make.NewClass(null, + List.nil(), + make.Type(tree.getQualifierExpression().type), + convertArgs(tree.sym, args.toList(), tree.varargsElement), + null); + newClass.constructor = tree.sym; + newClass.constructorType = tree.sym.erasure(types); + newClass.type = tree.getQualifierExpression().type; + setVarargsIfNeeded(newClass, tree.varargsElement); + return newClass; + } + } + + private VarSymbol addParameter(String name, Type p, boolean genArg) { + VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); + vsym.pos = tree.pos; + params.append(make.VarDef(vsym, null)); + if (genArg) { + args.append(make.Ident(vsym)); + } + return vsym; + } + } + + /** + * Convert method/constructor arguments by inserting appropriate cast + * as required by type-erasure - this is needed when bridging a lambda/method + * reference, as the bridged signature might require downcast to be compatible + * with the generated signature. + */ + private List convertArgs(Symbol meth, List args, Type varargsElement) { + Assert.check(meth.kind == MTH); + List formals = types.erasure(meth.type).getParameterTypes(); + if (varargsElement != null) { + Assert.check((meth.flags() & VARARGS) != 0); + } + return transTypes.translateArgs(args, formals, varargsElement, attrEnv); + } + + /** + * Set varargsElement field on a given tree (must be either a new class tree + * or a method call tree) + */ + private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { + if (varargsElement != null) { + switch (tree.getTag()) { + case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; + case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; + case TYPECAST: setVarargsIfNeeded(((JCTypeCast) tree).expr, varargsElement); break; + default: throw new AssertionError(); + } + } + } + public void visitSwitch(JCSwitch tree) { List cases = tree.patternSwitch ? addDefaultIfNeeded(tree.patternSwitch, tree.wasEnumSelector, @@ -4018,7 +4351,7 @@ public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List c //switch ($selector != null ? $mapVar[$selector.ordinal()] : -1) {...} //replacing case null with case -1: VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC, - names.fromString("s" + tree.pos + this.target.syntheticNameChar()), + names.fromString("s" + variableIndex++ + this.target.syntheticNameChar()), selector.type, currentMethodSym); JCStatement var = make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type); @@ -4175,13 +4508,13 @@ public JCTree visitStringSwitch(JCTree tree, JCExpression selector, List */ VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC, - names.fromString("s" + tree.pos + target.syntheticNameChar()), + names.fromString("s" + variableIndex++ + target.syntheticNameChar()), syms.stringType, currentMethodSym); stmtList.append(make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type)); VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC, - names.fromString("tmp" + tree.pos + target.syntheticNameChar()), + names.fromString("tmp" + variableIndex++ + target.syntheticNameChar()), syms.intType, currentMethodSym); JCVariableDecl dollar_tmp_def = @@ -4323,7 +4656,7 @@ private JCTree visitBoxedPrimitiveSwitch(JCTree tree, JCExpression selector, Lis while (constants.contains(replacementValue)) replacementValue++; VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC, - names.fromString("s" + tree.pos + this.target.syntheticNameChar()), + names.fromString("s" + variableIndex++ + this.target.syntheticNameChar()), selector.type, currentMethodSym); JCStatement var = make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type); @@ -4381,7 +4714,7 @@ public void visitSelect(JCFieldAccess tree) { TreeInfo.name(tree.selected) == names._super && !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass); tree.selected = translate(tree.selected); - if (tree.name == names._class) { + if (tree.name == names._class && tree.selected.type.isPrimitiveOrVoid()) { result = classOf(tree.selected); } else if (tree.name == names._super && @@ -4457,6 +4790,7 @@ public List translateTopLevelClass(Env env, JCTree cdef, Tr this.make = make; endPosTable = env.toplevel.endPositions; currentClass = null; + currentRestype = null; currentMethodDef = null; outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null; outermostMemberDef = null; @@ -4486,6 +4820,7 @@ public List translateTopLevelClass(Env env, JCTree cdef, Tr this.make = null; endPosTable = null; currentClass = null; + currentRestype = null; currentMethodDef = null; outermostClassDef = null; outermostMemberDef = null; @@ -4505,4 +4840,23 @@ public List translateTopLevelClass(Env env, JCTree cdef, Tr } return translated.toList(); } + + // needed for the lambda deserialization method, which is expressed as a big switch on strings + public JCMethodDecl translateMethod(Env env, JCMethodDecl methodDecl, TreeMaker make) { + try { + this.attrEnv = env; + this.make = make; + this.currentClass = methodDecl.sym.enclClass(); + proxies = new HashMap<>(); + return translate(methodDecl); + } finally { + this.attrEnv = null; + this.make = null; + this.currentClass = null; + // the two fields below are set when visiting the method + this.currentMethodSym = null; + this.currentMethodDef = null; + this.proxies = null; + } + } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index a12271c790419..9600e4f6e4ff9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1618,14 +1618,6 @@ public void visitSwitchExpression(JCSwitchExpression tree) { compileStates.put(env, CompileState.TRANSPATTERNS); - if (scanner.hasLambdas) { - if (shouldStop(CompileState.UNLAMBDA)) - return; - - env.tree = LambdaToMethod.instance(context).translateTopLevelClass(env, env.tree, localMake); - compileStates.put(env, CompileState.UNLAMBDA); - } - if (shouldStop(CompileState.LOWER)) return; @@ -1647,6 +1639,16 @@ public void visitSwitchExpression(JCSwitchExpression tree) { if (shouldStop(CompileState.LOWER)) return; + if (scanner.hasLambdas) { + if (shouldStop(CompileState.UNLAMBDA)) + return; + + for (JCTree def : cdefs) { + LambdaToMethod.instance(context).translateTopLevelClass(env, def, localMake); + } + compileStates.put(env, CompileState.UNLAMBDA); + } + //generate code for each class for (List l = cdefs; l.nonEmpty(); l = l.tail) { JCClassDecl cdef = (JCClassDecl)l.head; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index 5af482516b4e6..6f3b8b5d8aaca 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -2013,6 +2013,7 @@ public enum ParameterKind { public JCTree body; public boolean canCompleteNormally = true; public ParameterKind paramKind; + public boolean wasMethodReference; public JCLambda(List params, JCTree body) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index f2edd5c97e9e7..5e3b043fb1187 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -344,11 +344,13 @@ public void visitExec(JCExpressionStatement stat) { @Override public void visitClassDef(JCClassDecl tree) { // don't descend any further + result = tree; } @Override public void visitLambda(JCLambda tree) { // don't descend any further + result = tree; } } diff --git a/test/langtools/tools/javac/SuperInit/AnonSuperLambdaCrash.java b/test/langtools/tools/javac/SuperInit/AnonSuperLambdaCrash.java new file mode 100644 index 0000000000000..3ca895194f184 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/AnonSuperLambdaCrash.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333766 + * @summary Test for compiler crash when anonymous class created in early lambda + */ + +public class AnonSuperLambdaCrash { + class Inner { + Inner() { + this(() -> new Object() { { AnonSuperLambdaCrash.this.hashCode(); } }); + } + Inner(Runnable r) { + r.run(); + } + } + + public static void main(String[] args) { + new AnonSuperLambdaCrash().new Inner(); + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java new file mode 100644 index 0000000000000..5d9060da83c26 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333313 + * @summary Verify references to local classes declared in early construction contexts + * @enablePreview + */ +public class EarlyLocalTest1 { + + class Test { + Test() { + class InnerLocal { } + Runnable r = () -> new InnerLocal(); + r.run(); + super(); + } + } + + public static void main(String[] args) { + new EarlyLocalTest1().new Test(); + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java new file mode 100644 index 0000000000000..cce6092f60696 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333313 + * @summary Verify references to local classes declared in early construction contexts + * @enablePreview + */ +public class EarlyLocalTest4 { + + class Test { + Test() { + class InnerLocal { } + Runnable r = new Runnable() { + public void run() { + new InnerLocal(); + } + }; + r.run(); + super(); + } + } + + public static void main(String[] args) { + new EarlyLocalTest4().new Test(); + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java new file mode 100644 index 0000000000000..6858e068af839 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333313 + * @summary Verify references to local classes declared in early construction contexts + * @enablePreview + */ +import java.util.concurrent.atomic.AtomicReference; + +public class EarlyLocalTest5 { + + int y; + + class Test extends AtomicReference { + Test(int x) { + class Foo implements Runnable { + public void run() { + System.out.println(x + y); + } + } + super(new Foo()); + } + } + + public static void main(String[] args) { + new EarlyLocalTest5().new Test(42); + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java new file mode 100644 index 0000000000000..742496a48d547 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333313 + * @summary Verify references to local classes declared in early construction contexts + * @enablePreview + */ +import java.util.concurrent.atomic.AtomicReference; + +public class EarlyLocalTest6 { + + int y; + + class Test extends AtomicReference { + Test(int x) { + super(new Runnable() { + public void run() { + System.out.println(x + y); + } + }); + } + } + + public static void main(String[] args) { + new EarlyLocalTest6().new Test(42); + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java new file mode 100644 index 0000000000000..1ce63bc04ba6c --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8333313 + * @summary Verify references to local classes declared in early construction contexts + * @enablePreview + */ +import java.util.concurrent.atomic.AtomicReference; + +public class EarlyLocalTest7 { + + int y; + + class Test extends AtomicReference { + Test(int x) { + super(() -> System.out.println(x + y)); + } + } + + public static void main(String[] args) { + new EarlyLocalTest7().new Test(42); + } +} diff --git a/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java b/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java new file mode 100644 index 0000000000000..660e7d19f4e01 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8334037 + * @summary Test for compiler crash when local class created in early lambda + * @enablePreview + */ + +public class LambdaLocalEarlyCrash { + interface A { } + + class Inner { + Inner() { + this(() -> { + class Local { + void g() { + m(); + } + } + new Local().g(); // error + }); + } + + Inner(Runnable tr) { + tr.run(); + } + } + + void m() { + System.out.println("Hello"); + } + + public static void main(String[] args) { + new LambdaLocalEarlyCrash().new Inner(); + } +} diff --git a/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java b/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java index 092e2916c69d5..261b23dc298f8 100644 --- a/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java +++ b/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8194743 + * @bug 8334252 * @summary Test lambda declared in early construction context * @enablePreview */ diff --git a/test/langtools/tools/javac/lambda/T8129740/Universe.java.out b/test/langtools/tools/javac/lambda/T8129740/Universe.java.out index 1d8c0e290c29e..919eb14c3c912 100644 --- a/test/langtools/tools/javac/lambda/T8129740/Universe.java.out +++ b/test/langtools/tools/javac/lambda/T8129740/Universe.java.out @@ -69,29 +69,27 @@ class Universe { } Planet(String name, int moonsCount) { - this(name, moonsCount, java.lang.invoke.LambdaMetafactory.metafactory(name, Universe.Galaxy.this, Universe.Galaxy.SolarSystem.this)); + this(name, moonsCount, ()->{ + String n = name; + StringBuffer buf = new StringBuffer(); + buf.append("This planet belongs to the galaxy " + Galaxy.this.name + " with " + starsCount + " stars\n"); + buf.append("This planet belongs to the galaxy " + Universe.Galaxy.this.name + " with " + starsCount() + " stars\n"); + buf.append("This planet belongs to the galaxy " + Galaxy.this.name() + " with " + starsCount() + " stars\n"); + buf.append("This planet belongs to the galaxy " + Universe.Galaxy.this.name() + " with " + (Universe.Galaxy.this).starsCount() + " stars\n"); + buf.append("This planet belongs to the solar system " + SolarSystem.this.name + " with " + planetsCount + " planets\n"); + buf.append("This planet belongs to the solar system " + Galaxy.SolarSystem.this.name + " with " + planetsCount() + " planets\n"); + buf.append("This planet belongs to the solar system " + (SolarSystem.this).name + " with " + planetsCount + " planets\n"); + buf.append("This planet belongs to the solar system " + Universe.Galaxy.SolarSystem.this.name + " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n"); + buf.append("This planet belongs to the solar system " + Universe.Galaxy.SolarSystem.this.name.toLowerCase().toUpperCase() + " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n"); + buf.append("This planet belongs to the solar system " + copy(Universe.Galaxy.SolarSystem.this).name.toLowerCase().toUpperCase() + " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n"); + if (!buf.toString().equals(output)) throw new AssertionError("Unexpected value\n" + buf); + }); } static final String output = "This planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system SUN with 9 planets\nThis planet belongs to the solar system SUN with 9 planets\n"; public String toString() { return "Planet " + name + " with " + moonsCount + " moon(s)"; } - - /*synthetic*/ private static void lambda$new$0(/*synthetic*/ final String name, /*synthetic*/ final Universe.Galaxy Universe$Galaxy$this, /*synthetic*/ final Universe.Galaxy.SolarSystem Universe$Galaxy$SolarSystem$this) { - String n = name; - StringBuffer buf = new StringBuffer(); - buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name + " with " + Universe$Galaxy$this.starsCount + " stars\n"); - buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name + " with " + Universe$Galaxy$this.starsCount() + " stars\n"); - buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name() + " with " + Universe$Galaxy$this.starsCount() + " stars\n"); - buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name() + " with " + (Universe$Galaxy$this).starsCount() + " stars\n"); - buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n"); - buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount() + " planets\n"); - buf.append("This planet belongs to the solar system " + (Universe$Galaxy$SolarSystem$this).name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n"); - buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n"); - buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name.toLowerCase().toUpperCase() + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n"); - buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.copy(Universe$Galaxy$SolarSystem$this).name.toLowerCase().toUpperCase() + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n"); - if (!buf.toString().equals(output)) throw new AssertionError("Unexpected value\n" + buf); - } } } } From 741a0f39dd1fffc1caaa8d69bfe3662dad830452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 26 Jun 2024 09:37:22 +0000 Subject: [PATCH 053/288] 8334241: Adjust API docs side bar dimensions Reviewed-by: jjg --- .../internal/doclets/formats/html/resources/stylesheet.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 8086e0d88b3ce..4e37588f6cda5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -348,7 +348,7 @@ body.class-declaration-page .details h3 { flex-direction: row; } .main-grid main { - flex: 2.6 1 0; + flex: 3 1 0; min-width: 240px } .main-grid nav.toc { From f23295ec1dde58d239a2625c9b1645534a2bb625 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 26 Jun 2024 10:09:05 +0000 Subject: [PATCH 054/288] 8334600: TEST java/net/MulticastSocket/IPMulticastIF.java fails on linux-aarch64 Reviewed-by: alanb --- .../net/MulticastSocket/IPMulticastIF.java | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java index 566e3603fa645..3909f6d627678 100644 --- a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java +++ b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,9 +63,25 @@ public Object[][] positive() throws Exception { InetAddress.getLoopbackAddress()); List list = new ArrayList<>(); NetworkConfiguration nc = NetworkConfiguration.probe(); + // retains only network interface whose bound addresses match addrs.stream().forEach(a -> nc.multicastInterfaces(true) - .map(nif -> new Object[] { new InetSocketAddress(a, 0), nif }) - .forEach(list::add) ); + .filter(nif -> nif.inetAddresses().toList().contains(a)) + .map(nif -> new Object[] { new InetSocketAddress(a, 0), nif }) + .forEach(list::add) ); + // any network interface should work with the wildcard address + nc.multicastInterfaces(true) + .map(nif -> new Object[] {new InetSocketAddress(0), nif}) + .forEach(list::add); + return list.stream().toArray(Object[][]::new); + } + + @DataProvider(name = "interfaces") + public Object[][] interfaces() throws Exception { + List list = new ArrayList<>(); + NetworkConfiguration nc = NetworkConfiguration.probe(); + nc.multicastInterfaces(true) + .map(nif -> new Object[] {nif}) + .forEach(list::add); return list.stream().toArray(Object[][]::new); } @@ -82,8 +98,8 @@ public void testSetGetInterfaceBound(InetSocketAddress bindAddr, NetworkInterfac } } - @Test(dataProvider = "scenarios") - public void testSetGetInterfaceUnbound(InetSocketAddress ignore, NetworkInterface nif) + @Test(dataProvider = "interfaces") + public void testSetGetInterfaceUnbound(NetworkInterface nif) throws Exception { out.println(format("\n\n--- testSetGetInterfaceUnbound nif=[%s]", nif)); @@ -106,8 +122,8 @@ public void testSetGetOptionBound(InetSocketAddress bindAddr, NetworkInterface n } } - @Test(dataProvider = "scenarios") - public void testSetGetOptionUnbound(InetSocketAddress ignore, NetworkInterface nif) + @Test(dataProvider = "interfaces") + public void testSetGetOptionUnbound(NetworkInterface nif) throws Exception { out.println(format("\n\n--- testSetGetOptionUnbound nif=[%s]", nif)); @@ -139,8 +155,8 @@ public void testGetInterfaceBound(InetSocketAddress bindAddr) } @Test - public void testGettInterfaceUnbound() throws Exception { - out.println("\n\n--- testGettInterfaceUnbound "); + public void testGetInterfaceUnbound() throws Exception { + out.println("\n\n--- testGetInterfaceUnbound "); try (MulticastSocket ms = new MulticastSocket()) { assertPlaceHolder(ms.getNetworkInterface()); } From b2ac7259c96f154ba0ca54fd47b37caaa8c8647b Mon Sep 17 00:00:00 2001 From: Kangcheng Xu Date: Wed, 26 Jun 2024 13:19:34 +0000 Subject: [PATCH 055/288] 8327380: Add tests for Shenandoah barrier expansion optimization Reviewed-by: roland, shade --- .../TestShenandoahBarrierExpansion.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java b/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java new file mode 100644 index 0000000000000..84a34695092dd --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestShenandoahBarrierExpansion.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.gcbarriers; + +import compiler.lib.ir_framework.CompilePhase; +import compiler.lib.ir_framework.DontInline; +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; + +/** + * @test + * @bug 8231569 + * @summary Test that Shenandoah barriers are expanded correctly + * @library /test/lib / + * @requires vm.gc.Shenandoah + * @run main compiler.gcbarriers.TestShenandoahBarrierExpansion + */ +public class TestShenandoahBarrierExpansion { + public static void main(String[] args) { + TestFramework test = new TestFramework(TestShenandoahBarrierExpansion.class); + test.addFlags("-XX:+UseShenandoahGC"); + test.start(); + } + + private static Object staticField; + @Test + @IR(failOn = IRNode.IF, phase = CompilePhase.AFTER_PARSING) + @IR(counts = { IRNode.IF, "2" }, phase = CompilePhase.BARRIER_EXPANSION) + public Object testLoadFieldObject() { + return staticField; + } + + private static A staticField2 = new A(); + @Test + @IR(counts = { IRNode.IF, "1" }, phase = CompilePhase.AFTER_PARSING) + @IR(counts = { IRNode.IF, "3" }, phase = CompilePhase.BARRIER_EXPANSION) + private static int testLoadObjectFieldWithNullCheck() { + return staticField2.intField; + } + + private static A staticField3 = new A(); + @Test + @IR(counts = { IRNode.IF, "2" }, phase = CompilePhase.AFTER_PARSING) + @IR(counts = { IRNode.IF, "6" }, phase = CompilePhase.BARRIER_EXPANSION) + private static int testLoadTwoObjectFieldsWithNullCheck() { + return staticField2.intField + staticField3.intField; + } + + @Test + @IR(failOn = IRNode.IF, phase = CompilePhase.AFTER_PARSING) + @IR(counts = { IRNode.IF, "3" }, phase = CompilePhase.BARRIER_EXPANSION) + private static void testLoadTwoFieldObjectAndEscape() { + final A field2 = staticField2; + final A field3 = staticField3; + notInlined(field2, field3); + } + + @DontInline + private static void notInlined(A field2, A field3) { + // noop + } + + private static class A { + public int intField; + } +} From efb905e57ab7a5299952419fa9961316541056c2 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 26 Jun 2024 13:37:58 +0000 Subject: [PATCH 056/288] 8334618: ubsan: support setting additional ubsan check options Reviewed-by: stuefe, lucy --- make/autoconf/jdk-options.m4 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index b5c679d2a8ef9..0dca5d133131f 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -496,9 +496,15 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_LEAK_SANITIZER], # AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER], [ + UTIL_ARG_WITH(NAME: additional-ubsan-checks, TYPE: string, + DEFAULT: [], + DESC: [Customizes the ubsan checks], + OPTIONAL: true) + # GCC reports lots of likely false positives for stringop-truncation and format-overflow. # Silence them for now. - UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment" + UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment \ + $ADDITIONAL_UBSAN_CHECKS" UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-stringop-truncation -Wno-format-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER" UBSAN_LDFLAGS="$UBSAN_CHECKS" UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED, From 4ffc5e60776353b03e9a557c39148e378b1690e2 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Wed, 26 Jun 2024 13:58:22 +0000 Subject: [PATCH 057/288] 8326705: Test CertMsgCheck.java fails to find alert certificate_required Reviewed-by: ssahoo, rhalade --- test/jdk/ProblemList.txt | 1 - .../net/ssl/SSLSession/CertMsgCheck.java | 29 +++++++++++-------- test/jdk/javax/net/ssl/templates/TLSBase.java | 24 ++++++++------- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 2bf83e8ea81e0..790b3de0f969c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -616,7 +616,6 @@ com/sun/security/sasl/gsskerb/ConfSecurityLayer.java 8039280 generic- com/sun/security/sasl/gsskerb/NoSecurityLayer.java 8039280 generic-all sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 generic-all sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all -javax/net/ssl/SSLSession/CertMsgCheck.java 8326705 generic-all sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183,8333317 generic-all diff --git a/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java b/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java index 37c252bc6f090..498c17672b213 100644 --- a/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java +++ b/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java @@ -40,20 +40,25 @@ public static void main(String[] args) throws Exception { // Initial client session TLSBase.Client client1 = new TLSBase.Client(true, false); - if (server.getSession(client1).getSessionContext() == null) { - for (Exception e : server.getExceptionList()) { - System.out.println("Looking at " + e.getClass() + " " + - e.getMessage()); - if (e.getMessage().contains(args[0])) { - System.out.println("Found correct exception: " + args[0] + + + server.getSession(client1).getSessionContext(); + server.done(); + + var eList = server.getExceptionList(); + System.out.println("Exception list size is " + eList.size()); + + for (Exception e : eList) { + System.out.println("Looking at " + e.getClass() + " " + + e.getMessage()); + if (e.getMessage().contains(args[0])) { + System.out.println("Found correct exception: " + args[0] + " in " + e.getMessage()); - return; - } else { - System.out.println("No \"" + args[0] + "\" found."); - } + return; + } else { + System.out.println("No \"" + args[0] + "\" found."); } - - throw new Exception("Failed to find expected alert: " + args[0]); } + + throw new Exception("Failed to find expected alert: " + args[0]); } } diff --git a/test/jdk/javax/net/ssl/templates/TLSBase.java b/test/jdk/javax/net/ssl/templates/TLSBase.java index 812aea09fea11..5c95253e6f024 100644 --- a/test/jdk/javax/net/ssl/templates/TLSBase.java +++ b/test/jdk/javax/net/ssl/templates/TLSBase.java @@ -97,8 +97,8 @@ public void write(SSLSocket sock, byte[] data) throws Exception { private static KeyManager[] getKeyManager(boolean empty) throws Exception { FileInputStream fis = null; if (!empty) { - fis = new FileInputStream(System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile); + fis = new FileInputStream(System.getProperty("test.src", "./") + + "/" + pathToStores + "/" + keyStoreFile); } // Load the keystore char[] pwd = passwd.toCharArray(); @@ -113,8 +113,8 @@ private static KeyManager[] getKeyManager(boolean empty) throws Exception { private static TrustManager[] getTrustManager(boolean empty) throws Exception { FileInputStream fis = null; if (!empty) { - fis = new FileInputStream(System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile); + fis = new FileInputStream(System.getProperty("test.src", "./") + + "/" + pathToStores + "/" + trustStoreFile); } // Load the keystore KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -148,7 +148,6 @@ static class Server extends TLSBase { // Clients sockets are kept in a hash table with the port as the key. ConcurrentHashMap clientMap = new ConcurrentHashMap<>(); - boolean exit = false; Thread t; List exceptionList = new ArrayList<>(); @@ -157,13 +156,14 @@ static class Server extends TLSBase { name = "server"; try { sslContext = SSLContext.getInstance("TLS"); - sslContext.init(TLSBase.getKeyManager(builder.km), TLSBase.getTrustManager(builder.tm), null); + sslContext.init(TLSBase.getKeyManager(builder.km), + TLSBase.getTrustManager(builder.tm), null); fac = sslContext.getServerSocketFactory(); ssock = (SSLServerSocket) fac.createServerSocket(0); ssock.setNeedClientAuth(builder.clientauth); serverPort = ssock.getLocalPort(); } catch (Exception e) { - System.err.println(e.getMessage()); + System.err.println("Failure during server initialization"); e.printStackTrace(); } @@ -178,6 +178,7 @@ static class Server extends TLSBase { try { write(c, read(c)); } catch (Exception e) { + System.out.println("Caught " + e.getMessage()); e.printStackTrace(); exceptionList.add(e); } @@ -203,13 +204,14 @@ static class Server extends TLSBase { name = "server"; try { sslContext = SSLContext.getInstance("TLS"); - sslContext.init(TLSBase.getKeyManager(km), TLSBase.getTrustManager(tm), null); + sslContext.init(TLSBase.getKeyManager(km), + TLSBase.getTrustManager(tm), null); fac = sslContext.getServerSocketFactory(); ssock = (SSLServerSocket) fac.createServerSocket(0); ssock.setNeedClientAuth(true); serverPort = ssock.getLocalPort(); } catch (Exception e) { - System.err.println(e.getMessage()); + System.err.println("Failure during server initialization"); e.printStackTrace(); } @@ -224,7 +226,9 @@ static class Server extends TLSBase { try { write(c, read(c)); } catch (Exception e) { + System.out.println("Caught " + e.getMessage()); e.printStackTrace(); + exceptionList.add(e); } } } catch (Exception ex) { @@ -239,7 +243,7 @@ static class Server extends TLSBase { // test or the test will never end. void done() { try { - t.interrupt(); + t.join(5000); ssock.close(); } catch (Exception e) { System.err.println(e.getMessage()); From 8374d16504503c7441346c99045736b7ac72233f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 26 Jun 2024 14:12:44 +0000 Subject: [PATCH 058/288] 8335006: C2 SuperWord: add JMH benchmark VectorLoadToStoreForwarding.java Reviewed-by: shade, kvn, sviswanathan --- .../compiler/VectorLoadToStoreForwarding.java | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java b/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java new file mode 100644 index 0000000000000..efbf99c6ce5e1 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorLoadToStoreForwarding.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1) +public abstract class VectorLoadToStoreForwarding { + @Param({"2048"}) + public int SIZE; + + private int[] aI; + + @Param("0") + private int seed; + private Random r = new Random(seed); + + @Setup + public void init() { + aI = new int[SIZE]; + + for (int i = 0; i < SIZE; i++) { + aI[i] = r.nextInt(); + } + } + + @Benchmark + public void benchmark_00() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 0] + 1; + } + } + + @Benchmark + public void benchmark_01() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 1] + 1; + } + } + + @Benchmark + public void benchmark_02() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 2] + 1; + } + } + + @Benchmark + public void benchmark_03() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 3] + 1; + } + } + + @Benchmark + public void benchmark_04() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 4] + 1; + } + } + + @Benchmark + public void benchmark_05() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 5] + 1; + } + } + + @Benchmark + public void benchmark_06() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 6] + 1; + } + } + + @Benchmark + public void benchmark_07() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 7] + 1; + } + } + + @Benchmark + public void benchmark_08() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 8] + 1; + } + } + + @Benchmark + public void benchmark_09() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 9] + 1; + } + } + + @Benchmark + public void benchmark_10() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 10] + 1; + } + } + + @Benchmark + public void benchmark_11() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 11] + 1; + } + } + + @Benchmark + public void benchmark_12() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 12] + 1; + } + } + + @Benchmark + public void benchmark_13() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 13] + 1; + } + } + + @Benchmark + public void benchmark_14() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 14] + 1; + } + } + + @Benchmark + public void benchmark_15() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 15] + 1; + } + } + + @Benchmark + public void benchmark_16() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 16] + 1; + } + } + + @Benchmark + public void benchmark_17() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 17] + 1; + } + } + + @Benchmark + public void benchmark_18() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 18] + 1; + } + } + + @Benchmark + public void benchmark_19() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 19] + 1; + } + } + + @Benchmark + public void benchmark_20() { + for (int i = 20; i < SIZE; i++) { + aI[i] = aI[i - 20] + 1; + } + } + + @Fork(value = 1, jvmArgsPrepend = { + "-XX:+UseSuperWord" + }) + public static class VectorLoadToStoreForwardingSuperWord extends VectorLoadToStoreForwarding {} + + @Fork(value = 1, jvmArgsPrepend = { + "-XX:-UseSuperWord" + }) + public static class VectorLoadToStoreForwardingNoSuperWord extends VectorLoadToStoreForwarding {} +} From 8591eff78dbc9770b8d0a16e05040ac35c99881a Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 26 Jun 2024 14:39:21 +0000 Subject: [PATCH 059/288] 8332103: since-checker - Add missing @ since tags to java.desktop Reviewed-by: tr, aivanov --- .../share/classes/java/awt/geom/Path2D.java | 8 +++++++- .../share/classes/java/beans/package-info.java | 4 +++- .../classes/javax/swing/DefaultComboBoxModel.java | 6 +++++- .../share/classes/javax/swing/DefaultListModel.java | 6 +++++- .../share/classes/javax/swing/JSlider.java | 10 +++++++++- .../share/classes/javax/swing/package-info.java | 4 +++- .../classes/javax/swing/plaf/basic/BasicSliderUI.java | 2 ++ .../classes/javax/swing/plaf/synth/package-info.java | 4 +++- .../classes/javax/swing/text/DefaultEditorKit.java | 6 +++++- 9 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/geom/Path2D.java b/src/java.desktop/share/classes/java/awt/geom/Path2D.java index ad91b44911e4f..8b14846b117ad 100644 --- a/src/java.desktop/share/classes/java/awt/geom/Path2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/Path2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -292,6 +292,9 @@ public Float(Shape s, AffineTransform at) { } } + /** + * @since 10 + */ @Override public final void trimToSize() { // trim arrays: @@ -1178,6 +1181,9 @@ public Double(Shape s, AffineTransform at) { } } + /** + * @since 10 + */ @Override public final void trimToSize() { // trim arrays: diff --git a/src/java.desktop/share/classes/java/beans/package-info.java b/src/java.desktop/share/classes/java/beans/package-info.java index fefe400e6bf4d..dfa226f7014d5 100644 --- a/src/java.desktop/share/classes/java/beans/package-info.java +++ b/src/java.desktop/share/classes/java/beans/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,5 +108,7 @@ * Long-Term Persistence, an article in * The Swing Connection. * + * + * @since 1.1 */ package java.beans; diff --git a/src/java.desktop/share/classes/javax/swing/DefaultComboBoxModel.java b/src/java.desktop/share/classes/javax/swing/DefaultComboBoxModel.java index 382eba1946fda..e2257abf704a2 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultComboBoxModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultComboBoxModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,6 +183,8 @@ public void removeAllElements() { * * @param c the collection which contains the elements to add * @throws NullPointerException if {@code c} is null + * + * @since 11 */ public void addAll(Collection c) { if (c.isEmpty()) { @@ -205,6 +207,8 @@ public void addAll(Collection c) { * @throws ArrayIndexOutOfBoundsException if {@code index} does not * fall within the range of number of elements currently held * @throws NullPointerException if {@code c} is null + * + * @since 11 */ public void addAll(int index, Collection c) { if (index < 0 || index > getSize()) { diff --git a/src/java.desktop/share/classes/javax/swing/DefaultListModel.java b/src/java.desktop/share/classes/javax/swing/DefaultListModel.java index 9d519927b6774..c66f0f0f7b274 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultListModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultListModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -530,6 +530,8 @@ public void removeRange(int fromIndex, int toIndex) { * * @param c the collection which contains the elements to add * @throws NullPointerException if {@code c} is null + * + * @since 11 */ public void addAll(Collection c) { if (c.isEmpty()) { @@ -552,6 +554,8 @@ public void addAll(Collection c) { * @throws ArrayIndexOutOfBoundsException if {@code index} does not * fall within the range of number of elements currently held * @throws NullPointerException if {@code c} is null + * + * @since 11 */ public void addAll(int index, Collection c) { if (index < 0 || index > getSize()) { diff --git a/src/java.desktop/share/classes/javax/swing/JSlider.java b/src/java.desktop/share/classes/javax/swing/JSlider.java index a9c9cbe887b7e..a61f7fe851b86 100644 --- a/src/java.desktop/share/classes/javax/swing/JSlider.java +++ b/src/java.desktop/share/classes/javax/swing/JSlider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1461,6 +1461,8 @@ public AccessibleStateSet getAccessibleStateSet() { * * @param e a {@code ChangeEvent} object. Must not be {@code null} * @throws NullPointerException if the parameter is {@code null} + * + * @since 16 */ public void stateChanged(ChangeEvent e) { if (e == null) { @@ -1561,6 +1563,8 @@ public AccessibleAction getAccessibleAction() { * which decrements the slider value * * @return the zero-based number of Actions in this object + * + * @since 17 */ public int getAccessibleActionCount() { return 2; @@ -1572,6 +1576,8 @@ public int getAccessibleActionCount() { * @param i zero-based index of the actions * @return a String description of the action * @see #getAccessibleActionCount + * + * @since 17 */ public String getAccessibleActionDescription(int i) { if (i == 0) { @@ -1590,6 +1596,8 @@ public String getAccessibleActionDescription(int i) { * action (index 1) is AccessibleAction.DECREMENT. * @return true if the action was performed, otherwise false * @see #getAccessibleActionCount + * + * @since 17 */ public boolean doAccessibleAction(int i) { if (i < 0 || i > 1) { diff --git a/src/java.desktop/share/classes/javax/swing/package-info.java b/src/java.desktop/share/classes/javax/swing/package-info.java index 95be24d606fad..3723c5a66e969 100644 --- a/src/java.desktop/share/classes/javax/swing/package-info.java +++ b/src/java.desktop/share/classes/javax/swing/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -149,5 +149,7 @@ * * * @serial exclude + * + * @since 1.2 */ package javax.swing; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java index ad5cb9c9ab9d8..f945f7eac63ad 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSliderUI.java @@ -150,6 +150,8 @@ public class BasicSliderUI extends SliderUI{ /** * Constructs a {@code BasicSliderUI}. + * + * @since 16 * @deprecated This constructor was exposed erroneously and will be removed in a future release. * Use {@link #BasicSliderUI(JSlider)} instead. */ diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/package-info.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/package-info.java index 41cb23989151e..10b03fa83d71e 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/package-info.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,5 +139,7 @@ * * * } + * + * @since 1.5 */ package javax.swing.plaf.synth; diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java index b71d30656db68..33fe7300df918 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -648,6 +648,8 @@ public void write(Writer out, Document doc, int pos, int len) * beginning of the previous line if the caret is * already at the beginning of the line. * @see #getActions + * + * @since 20 */ public static final String beginLineUpAction = "caret-begin-line-and-up"; @@ -657,6 +659,8 @@ public void write(Writer out, Document doc, int pos, int len) * end of the next line if the caret is already * at the end of the line. * @see #getActions + * + * @since 20 */ public static final String endLineDownAction = "caret-end-line-and-down"; From 5883a20b822bb8acb719076e4f7abee8403061cb Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 26 Jun 2024 14:46:17 +0000 Subject: [PATCH 060/288] 8334437: De-duplicate ProxyMethod list creation Reviewed-by: asotona, liach --- .../classes/java/lang/reflect/ProxyGenerator.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index 6c82a6ecb6f61..2e56d03c6ad89 100644 --- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -508,8 +508,7 @@ private void addProxyMethod(Method m, Class fromClass) { Class[] exceptionTypes = m.getSharedExceptionTypes(); String sig = m.toShortSignature(); - List sigmethods = proxyMethods.computeIfAbsent(sig, - _ -> new ArrayList<>(3)); + List sigmethods = proxyMethodsFor(sig); for (ProxyMethod pm : sigmethods) { if (returnType == pm.returnType) { /* @@ -531,16 +530,17 @@ private void addProxyMethod(Method m, Class fromClass) { exceptionTypes, fromClass, "m" + proxyMethodCount++)); } + private List proxyMethodsFor(String sig) { + return proxyMethods.computeIfAbsent(sig, _ -> new ArrayList<>(3)); + } + /** * Add an existing ProxyMethod (hashcode, equals, toString). * * @param pm an existing ProxyMethod */ private void addProxyMethod(ProxyMethod pm) { - String sig = pm.shortSignature; - List sigmethods = proxyMethods.computeIfAbsent(sig, - _ -> new ArrayList<>(3)); - sigmethods.add(pm); + proxyMethodsFor(pm.shortSignature).add(pm); } /** From b5d589623c174757e946011495f771718318f1cc Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Wed, 26 Jun 2024 16:20:15 +0000 Subject: [PATCH 061/288] 8335108: Build error after JDK-8333658 due to class templates Reviewed-by: jwaters, jsjolen --- src/hotspot/share/nmt/arrayWithFreeList.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/nmt/arrayWithFreeList.hpp b/src/hotspot/share/nmt/arrayWithFreeList.hpp index 90c348bbf7ccc..13aa1045fe7cb 100644 --- a/src/hotspot/share/nmt/arrayWithFreeList.hpp +++ b/src/hotspot/share/nmt/arrayWithFreeList.hpp @@ -60,7 +60,7 @@ class ArrayWithFreeList { } public: - NONCOPYABLE(ArrayWithFreeList); + NONCOPYABLE(ArrayWithFreeList); ArrayWithFreeList(int initial_capacity = 8) : _backing_storage(initial_capacity), From bffc8484c32ad6c3205f7cebe4e262a2dc9de57e Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 26 Jun 2024 17:10:09 +0000 Subject: [PATCH 062/288] 8333755: NumberFormat integer only parsing breaks when format has suffix Reviewed-by: naoto --- .../java/text/CompactNumberFormat.java | 24 +--- .../classes/java/text/DecimalFormat.java | 80 +++++++---- .../share/classes/java/text/NumberFormat.java | 9 +- .../Format/NumberFormat/BigDecimalParse.java | 28 ++-- .../Format/NumberFormat/StrictParseTest.java | 131 +++++++++++++----- 5 files changed, 170 insertions(+), 102 deletions(-) diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index cb1a9546b12cd..25fd9923b064a 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -1724,7 +1724,7 @@ public Number parse(String text, ParsePosition pos) { // Call DecimalFormat.subparseNumber() method to parse the // number part of the input text position = decimalFormat.subparseNumber(text, position, - digitList, false, false, status); + digitList, false, false, status).fullPos(); if (position == -1) { // Unable to parse the number successfully @@ -1732,26 +1732,6 @@ public Number parse(String text, ParsePosition pos) { pos.errorIndex = oldStart; return null; } - - // If parse integer only is true and the parsing is broken at - // decimal point, then pass/ignore all digits and move pointer - // at the start of suffix, to process the suffix part - if (isParseIntegerOnly() && position < text.length() - && text.charAt(position) == symbols.getDecimalSeparator()) { - position++; // Pass decimal character - for (; position < text.length(); ++position) { - char ch = text.charAt(position); - int digit = ch - symbols.getZeroDigit(); - if (digit < 0 || digit > 9) { - digit = Character.digit(ch, 10); - // Parse all digit characters - if (!(digit >= 0 && digit <= 9)) { - break; - } - } - } - } - // Number parsed successfully; match prefix and // suffix to obtain multiplier pos.index = position; @@ -2372,6 +2352,8 @@ public void setGroupingUsed(boolean newValue) { * parsed as the value {@code 1234000} (1234 (integer part) * 1000 * (thousand)) and the fractional part would be skipped. * The exact format accepted by the parse operation is locale dependent. + * @implSpec This implementation does not set the {@code ParsePosition} index + * to the position of the decimal symbol, but rather the end of the string. * * @return {@code true} if compact numbers should be parsed as integers * only; {@code false} otherwise diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index f575e86eced6a..1f249888a28f5 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -2150,10 +2150,7 @@ private void append(StringBuffer result, String string, * #getGroupingSize()} is not adhered to *
  • {@link #isGroupingUsed()} returns {@code false}, and the grouping * symbol is found - *
  • {@link #isParseIntegerOnly()} returns {@code true}, and the decimal - * separator is found - *
  • {@link #isGroupingUsed()} returns {@code true} and {@link - * #isParseIntegerOnly()} returns {@code false}, and the grouping + *
  • {@link #isGroupingUsed()} returns {@code true} and the grouping * symbol occurs after the decimal separator *
  • Any other characters are found, that are not the expected symbols, * and are not digits that occur within the numerical portion @@ -2379,7 +2376,8 @@ private final boolean subparse(String text, ParsePosition parsePosition, // position will serve as new index when success, otherwise it will // serve as errorIndex when failure - position = subparseNumber(text, position, digits, true, isExponent, status); + NumericPosition pos = subparseNumber(text, position, digits, true, isExponent, status); + position = pos.fullPos; // First character after the prefix was un-parseable, should // fail regardless if lenient or strict. @@ -2422,9 +2420,15 @@ private final boolean subparse(String text, ParsePosition parsePosition, return false; } - // No failures, thus increment the index by the suffix - parsePosition.index = position + - (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); + // When parsing integer only, index should be int pos + // If intPos is 0, the entire value was integer + if (isParseIntegerOnly() && pos.intPos > 0) { + parsePosition.index = pos.intPos; + } else { + // increment the index by the suffix + parsePosition.index = position + + (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); + } } else { parsePosition.index = position; } @@ -2437,6 +2441,19 @@ private final boolean subparse(String text, ParsePosition parsePosition, return true; } + /** + * NumericPosition is a helper record class that stores two indices of interest. + * {@code fullPos} is either the first unparseable character or -1 in case + * of no valid number parsed. {@code intPos} reflects the position of + * a parsed decimal symbol, if one exists. When parsing with {@code isParseIntegerOnly()}, + * {@code fullPos} is used to match the suffix, and reset the {@code ParsePosition} + * index to {@code intPos}. + * + * @param fullPos an index that reflects the full traversal of the numerical String + * @param intPos an index that reflects the position of a parsed decimal symbol. + */ + record NumericPosition(int fullPos, int intPos) {} + /** * Parses a number from the given {@code text}. The text is parsed * beginning at {@code position}, until an unparseable character is seen. @@ -2449,14 +2466,15 @@ private final boolean subparse(String text, ParsePosition parsePosition, * @param status upon return contains boolean status flags indicating * whether the value is infinite and whether it is * positive - * @return returns the position of the first unparseable character or - * -1 in case of no valid number parsed + * @return returns a {@code NumericPosition} that stores both a full + * traversal index, and an int only index. */ - int subparseNumber(String text, int position, - DigitList digits, boolean checkExponent, - boolean isExponent, boolean[] status) { + NumericPosition subparseNumber(String text, int position, + DigitList digits, boolean checkExponent, + boolean isExponent, boolean[] status) { // process digits or Inf, find decimal position status[STATUS_INFINITE] = false; + int intIndex = 0; if (!isExponent && text.regionMatches(position, symbols.getInfinity(), 0, symbols.getInfinity().length())) { position += symbols.getInfinity().length(); @@ -2516,7 +2534,7 @@ int subparseNumber(String text, int position, if (parseStrict && isGroupingUsed() && position == startPos + groupingSize && prevSeparatorIndex == -groupingSize && !sawDecimal && digit >= 0 && digit <= 9) { - return position; + return new NumericPosition(position, intIndex); } if (digit == 0) { @@ -2538,37 +2556,44 @@ int subparseNumber(String text, int position, --digits.decimalAt; } else { ++digitCount; - digits.append((char)(digit + '0')); + if (!sawDecimal || !isParseIntegerOnly()) { + digits.append((char)(digit + '0')); + } } } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above sawDigit = true; ++digitCount; - digits.append((char)(digit + '0')); + if (!sawDecimal || !isParseIntegerOnly()) { + digits.append((char) (digit + '0')); + } // Cancel out backup setting (see grouping handler below) backup = -1; } else if (!isExponent && ch == decimal) { // Check grouping size on decimal separator if (parseStrict && isGroupingViolation(position, prevSeparatorIndex)) { - return groupingViolationIndex(position, prevSeparatorIndex); + return new NumericPosition( + groupingViolationIndex(position, prevSeparatorIndex), intIndex); } // If we're only parsing integers, or if we ALREADY saw the // decimal, then don't parse this one. - if (isParseIntegerOnly() || sawDecimal) { + if (sawDecimal) { break; } + intIndex = position; digits.decimalAt = digitCount; // Not digits.count! sawDecimal = true; } else if (!isExponent && ch == grouping && isGroupingUsed()) { if (parseStrict) { // text should not start with grouping when strict if (position == startPos) { - return startPos; + return new NumericPosition(startPos, intIndex); } // when strict, fail if grouping occurs after decimal OR // current group violates grouping size if (sawDecimal || (isGroupingViolation(position, prevSeparatorIndex))) { - return groupingViolationIndex(position, prevSeparatorIndex); + return new NumericPosition( + groupingViolationIndex(position, prevSeparatorIndex), intIndex); } prevSeparatorIndex = position; // track previous } else { @@ -2621,7 +2646,8 @@ int subparseNumber(String text, int position, // "1,234%" and "1,234" both end with pos = 5, since '%' breaks // the loop before incrementing position. In both cases, check // should be done at pos = 4 - return groupingViolationIndex(position - 1, prevSeparatorIndex); + return new NumericPosition( + groupingViolationIndex(position - 1, prevSeparatorIndex), intIndex); } } @@ -2636,8 +2662,9 @@ int subparseNumber(String text, int position, digits.decimalAt = digitCount; // Not digits.count! } - // Adjust for exponent, if any - if (exponent != 0) { + // If parsing integer only, adjust exponent if it occurs + // in integer portion, otherwise ignore it + if (!sawDecimal || !isParseIntegerOnly()) { digits.decimalAt = shiftDecimalAt(digits.decimalAt, exponent); } @@ -2646,10 +2673,10 @@ int subparseNumber(String text, int position, // parse "$" with pattern "$#0.00". (return index 0 and error // index 1). if (!sawDigit && digitCount == 0) { - return -1; + return new NumericPosition(-1, intIndex); } } - return position; + return new NumericPosition(position, intIndex); } // Calculate the final decimal position based off the exponent value @@ -2917,7 +2944,8 @@ public int getMultiplier () { * have '{@code U+2030}'. * *

    Example: with multiplier 100, 1.23 is formatted as "123", and - * "123" is parsed into 1.23. + * "123" is parsed into 1.23. If {@code isParseIntegerOnly()} returns {@code true}, + * "123" is parsed into 1. * * @param newValue the new multiplier * @see #getMultiplier diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 0409efc2da08a..28f116042e9da 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -468,12 +468,11 @@ public Number parse(String source) throws ParseException { } /** - * Returns true if this format will parse numbers as integers only. + * Returns {@code true} if this format will parse numbers as integers only. + * The {@code ParsePosition} index will be set to the position of the decimal + * symbol. The exact format accepted by the parse operation is locale dependent. * For example in the English locale, with ParseIntegerOnly true, the - * string "1234." would be parsed as the integer value 1234 and parsing - * would stop at the "." character. Of course, the exact format accepted - * by the parse operation is locale dependent and determined by sub-classes - * of NumberFormat. + * string "123.45" would be parsed as the integer value 123. * * @return {@code true} if numbers should be parsed as integers only; * {@code false} otherwise diff --git a/test/jdk/java/text/Format/NumberFormat/BigDecimalParse.java b/test/jdk/java/text/Format/NumberFormat/BigDecimalParse.java index 771ae761a3aba..1d8168cd0544a 100644 --- a/test/jdk/java/text/Format/NumberFormat/BigDecimalParse.java +++ b/test/jdk/java/text/Format/NumberFormat/BigDecimalParse.java @@ -23,14 +23,18 @@ /* * @test - * @bug 4018937 8008577 8174269 + * @bug 4018937 8008577 8174269 8333755 * @summary Confirm that methods which are newly added to support BigDecimal and BigInteger work as expected. * @run junit/othervm BigDecimalParse */ import java.math.BigDecimal; -import java.text.*; -import java.util.*; +import java.text.DecimalFormat; +import java.text.Format; +import java.text.MessageFormat; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; @@ -543,23 +547,23 @@ public void test_Parse_in_MessageFormat_NotParseIntegerOnly() { static final int[][] parsePosition2 = { // {errorIndex, index} /* * Should keep in mind that the expected result is different from - * DecimalFormat.parse() for some cases. + * DecimalFormat.parse() for some cases. This is because parsing integer + * only will return a successful parse for the subformat, but since the index + * returned is not equal to the length, at the MessageFormat level, this + * will be interpreted as a failed parse, and so the DecimalFormat index + * should be reflected as the MessageFormat errorIndex. */ {28, 0}, // parsing stopped at '.' {29, 0}, // parsing stopped at '.' {29, 0}, // parsing stopped at '.' - {2, 0}, // parsing stopped at '(' because cannot find ')' - {2, 0}, // parsing stopped at the first numeric - // because cannot find '%' - {2, 0}, // parsing stopped at the first numeric - // because cannot find '%' + {30, 0}, // parsing stopped at '.' + {31, 0}, // parsing stopped at '.' + {32, 0}, // parsing stopped at '.' {28, 0}, // parsing stopped at '.' {29, 0}, // parsing stopped at '.' - {-1, 57}, {-1, 58}, {-1, 59}, {-1, 61}, {56, 0}, // parsing stopped at '.' - // because cannot find '%' - {2, 0}, // parsing stopped at '(' because cannot find ')' + {57, 0}, // parsing stopped at '.' {-1, 60}, {-1, 61}, {28, 0}, // parsing stopped at '.' {-1, 88}, diff --git a/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java b/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java index d62a867e573be..333bc1b050637 100644 --- a/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java +++ b/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8327640 8331485 + * @bug 8327640 8331485 8333755 * @summary Test suite for NumberFormat parsing with strict leniency * @run junit/othervm -Duser.language=en -Duser.country=US StrictParseTest * @run junit/othervm -Duser.language=ja -Duser.country=JP StrictParseTest @@ -34,6 +34,7 @@ * @run junit/othervm -Duser.language=ar -Duser.country=AR StrictParseTest */ +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.params.ParameterizedTest; @@ -72,17 +73,18 @@ public class StrictParseTest { private static final CompactNumberFormat cmpctFmt = (CompactNumberFormat) NumberFormat.getCompactNumberInstance(Locale.getDefault(), NumberFormat.Style.SHORT); - - - // All NumberFormats should parse strictly - static { - dFmt.setStrict(true); - pFmt.setStrict(true); - cFmt.setStrict(true); - cmpctFmt.setStrict(true); - // To effectively test strict compactNumberFormat parsing - cmpctFmt.setParseIntegerOnly(false); - cmpctFmt.setGroupingUsed(true); + private static final NumberFormat[] FORMATS = new NumberFormat[]{dFmt, cFmt, pFmt, cmpctFmt}; + + // Restore defaults before runs + @BeforeEach + void beforeEach() { + for (NumberFormat fmt : FORMATS) { + fmt.setStrict(true); + fmt.setParseIntegerOnly(false); + fmt.setGroupingUsed(true); + } + // Grouping Size is not defined at NumberFormat level + // Compact needs to manually init grouping size cmpctFmt.setGroupingSize(3); } @@ -114,6 +116,20 @@ public void uniqueCaseNumberFormatTest() { failParse(nonLocalizedDFmt, "a123456,7890b", 6); } + + // 8333755: Check that parsing with integer only against a suffix value works + @Test // Non-localized, run once + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void integerOnlyParseWithSuffixTest() { + // Some pattern with a suffix + DecimalFormat fmt = new DecimalFormat("0.00b"); + fmt.setParseIntegerOnly(true); + assertEquals(5d, successParse(fmt, "5.55b", 1)); + assertEquals(5d, successParse(fmt, "5b", 2)); + assertEquals(5555d, successParse(fmt, "5,555.55b", 5)); + assertEquals(5d, successParse(fmt, "5.55E55b", 1)); + } + @Test // Non-localized, only run once @EnabledIfSystemProperty(named = "user.language", matches = "en") public void badExponentParseNumberFormatTest() { @@ -170,24 +186,30 @@ public void numFmtStrictGroupingNotUsed(String toParse) { } else { successParse(dFmt, toParse); } - dFmt.setGroupingUsed(true); } - // Exception should be thrown if decimal separator occurs anywhere - // Don't pass badParseStrings for same reason as previous method. + // 8333755: Parsing behavior should follow normal strict behavior + // However the index returned, should be before decimal point + // and the value parsed equal to the integer portion @ParameterizedTest - @MethodSource({"validParseStrings", "integerOnlyParseStrings"}) - public void numFmtStrictIntegerOnlyUsed(String toParse) { - // When integer only is true, if a decimal separator is found, - // a failure should occur + @MethodSource("validIntegerOnlyParseStrings") + public void numFmtStrictIntegerOnlyUsedTest(String toParse, Number expVal) { dFmt.setParseIntegerOnly(true); - int failIndex = toParse.indexOf(dfs.getDecimalSeparator()); - if (failIndex > -1) { - failParse(dFmt, toParse, failIndex); + int expectedIndex = toParse.indexOf(dfs.getDecimalSeparator()); + if (expectedIndex > -1) { + assertEquals(successParse(dFmt, toParse, expectedIndex), expVal); } else { - successParse(dFmt, toParse); + assertEquals(successParse(dFmt, toParse), expVal); } - dFmt.setParseIntegerOnly(false); + } + + // 8333755: Parsing behavior should follow normal strict behavior + // when it comes to failures. + @ParameterizedTest + @MethodSource("badParseStrings") + public void numFmtStrictIntegerOnlyUsedFailTest(String toParse, int expectedErrorIndex) { + dFmt.setParseIntegerOnly(true); + failParse(dFmt, toParse, expectedErrorIndex); } // ---- CurrencyFormat tests ---- @@ -270,6 +292,18 @@ public void compactFmtEdgeParseTest() { failParse(cnf, "c1bb", 2); } + @ParameterizedTest + @MethodSource({"validIntegerOnlyParseStrings", "compactValidIntegerOnlyParseStrings"}) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void compactFmtSuccessParseIntOnlyTest(String toParse, double expectedValue) { + // compact does not accept exponents + if (toParse.indexOf('E') > -1) { + return; + } + cmpctFmt.setParseIntegerOnly(true); + assertEquals(expectedValue, successParse(cmpctFmt, toParse, toParse.length())); + } + // Ensure that on failure, the original index of the PP remains the same @Test public void parsePositionIndexTest() { @@ -279,7 +313,13 @@ public void parsePositionIndexTest() { // ---- Helper test methods ---- // Should parse entire String successfully, and return correctly parsed value. - private double successParse(NumberFormat fmt, String toParse) { + private Number successParse(NumberFormat fmt, String toParse) { + return successParse(fmt, toParse, toParse.length()); + } + + // Overloaded method that allows for an expected ParsePosition index value + // that is not the string length. + private Number successParse(NumberFormat fmt, String toParse, int expectedIndex) { // For Strings that don't have grouping separators, we test them with // grouping off so that they do not fail under the expectation that // grouping symbols should occur @@ -292,7 +332,7 @@ private double successParse(NumberFormat fmt, String toParse) { assertDoesNotThrow(() -> fmt.parse(toParse, pp)); assertEquals(-1, pp.getErrorIndex(), "ParsePosition ErrorIndex is not in correct location"); - assertEquals(toParse.length(), pp.getIndex(), + assertEquals(expectedIndex, pp.getIndex(), "ParsePosition Index is not in correct location"); fmt.setGroupingUsed(true); return parsedValue.doubleValue(); @@ -388,7 +428,9 @@ private static Stream badParseStrings() { Arguments.of("1.a", 2), Arguments.of(".22a", 3), Arguments.of(".1a1", 2), - Arguments.of("1,234,a", 5)) + Arguments.of("1,234,a", 5), + // Double decimal + Arguments.of("1,234..5", 5)) .map(args -> Arguments.of( localizeText(String.valueOf(args.get()[0])), args.get()[1])); } @@ -397,6 +439,8 @@ private static Stream badParseStrings() { // Given as Arguments private static Stream validParseStrings() { return Stream.of( + Arguments.of("1,234.55", 1234.55d), + Arguments.of("1,234.5", 1234.5d), Arguments.of("1,234.00", 1234d), Arguments.of("1,234.0", 1234d), Arguments.of("1,234.", 1234d), @@ -414,17 +458,19 @@ private static Stream validParseStrings() { localizeText(String.valueOf(args.get()[0])), args.get()[1])); } - // Separate test data set for integer only. Can not use "badParseStrings", as - // there is test data where the failure may occur from some other issue, - // not related to grouping - private static Stream integerOnlyParseStrings() { + // Separate test data set for integer only. + // Valid parse strings, that would parse successfully for integer/non-integer parse + private static Stream validIntegerOnlyParseStrings() { return Stream.of( - Arguments.of("234.a"), - Arguments.of("234.a1"), - Arguments.of("234.1"), - Arguments.of("234.1a"), - Arguments.of("234.")) - .map(args -> Arguments.of(localizeText(String.valueOf(args.get()[0])))); + Arguments.of("234", 234d), + Arguments.of("234.", 234d), + Arguments.of("234.1", 234d), + Arguments.of("1,234.1", 1234d), + Arguments.of("234.12345", 234d), + Arguments.of("234.543E23", 234d), + Arguments.of("234,000.55E22", 234000d), + Arguments.of("234E22", 234E22)) + .map(args -> Arguments.of(localizeText(String.valueOf(args.get()[0])), args.get()[1])); } // Separate test data set for no grouping. Can not use "badParseStrings", as @@ -514,6 +560,12 @@ private static Stream compactValidParseStrings() { ); } + private static Stream compactValidIntegerOnlyParseStrings() { + return validIntegerOnlyParseStrings().map(args -> Arguments.of( + args.get()[0] + "K", (double) args.get()[1] * 1000) + ); + } + // Replace the grouping and decimal separators with localized variants // Used during localization of data private static String localizeText(String text) { @@ -526,7 +578,10 @@ private static String localizeText(String text) { sb.append(dfs.getGroupingSeparator()); } else if (c == '.') { sb.append(dfs.getDecimalSeparator()); - } else if (c == '0') { + } else if (c == 'E') { + sb.append(dfs.getExponentSeparator()); + } + else if (c == '0') { sb.append(dfs.getZeroDigit()); } else { sb.append(c); From 817edcb697cbb8c608c9292cdc4b99db4f5844dc Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 26 Jun 2024 19:25:37 +0000 Subject: [PATCH 063/288] 8331411: Shenandoah: Reconsider spinning duration in ShenandoahLock Reviewed-by: shade, kdnilsen, wkemper --- .../share/gc/shenandoah/shenandoahLock.cpp | 49 +++++++++++-------- .../share/gc/shenandoah/shenandoahLock.hpp | 12 +++-- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp index 349f5415cdc0b..6fc74c53e6390 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp @@ -32,40 +32,49 @@ #include "runtime/javaThread.hpp" #include "runtime/os.inline.hpp" -// These are inline variants of Thread::SpinAcquire with optional blocking in VM. - -class ShenandoahNoBlockOp : public StackObj { -public: - ShenandoahNoBlockOp(JavaThread* java_thread) { - assert(java_thread == nullptr, "Should not pass anything"); - } -}; - void ShenandoahLock::contended_lock(bool allow_block_for_safepoint) { Thread* thread = Thread::current(); if (allow_block_for_safepoint && thread->is_Java_thread()) { - contended_lock_internal(JavaThread::cast(thread)); + contended_lock_internal(JavaThread::cast(thread)); } else { - contended_lock_internal(nullptr); + contended_lock_internal(nullptr); } } -template +template void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) { - int ctr = 0; - int yields = 0; + assert(!ALLOW_BLOCK || java_thread != nullptr, "Must have a Java thread when allowing block."); + // Spin this much on multi-processor, do not spin on multi-processor. + int ctr = os::is_MP() ? 0xFF : 0; + // Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread. while (Atomic::load(&_state) == locked || Atomic::cmpxchg(&_state, unlocked, locked) != unlocked) { - if ((++ctr & 0xFFF) == 0) { - BlockOp block(java_thread); - if (yields > 5) { - os::naked_short_sleep(1); + if (ctr > 0 && !SafepointSynchronize::is_synchronizing()) { + // Lightly contended, spin a little if no safepoint is pending. + SpinPause(); + ctr--; + } else if (ALLOW_BLOCK) { + ThreadBlockInVM block(java_thread); + if (SafepointSynchronize::is_synchronizing()) { + // If safepoint is pending, we want to block and allow safepoint to proceed. + // Normally, TBIVM above would block us in its destructor. + // + // But that blocking only happens when TBIVM knows the thread poll is armed. + // There is a window between announcing a safepoint and arming the thread poll + // during which trying to continuously enter TBIVM is counter-productive. + // Under high contention, we may end up going in circles thousands of times. + // To avoid it, we wait here until local poll is armed and then proceed + // to TBVIM exit for blocking. We do not SpinPause, but yield to let + // VM thread to arm the poll sooner. + while (SafepointSynchronize::is_synchronizing() && + !SafepointMechanism::local_poll_armed(java_thread)) { + os::naked_yield(); + } } else { os::naked_yield(); - yields++; } } else { - SpinPause(); + os::naked_yield(); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp index 4412680bc8ce6..4d7eefd460c46 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp @@ -37,20 +37,22 @@ class ShenandoahLock { shenandoah_padding(0); volatile LockState _state; shenandoah_padding(1); - volatile Thread* _owner; + Thread* volatile _owner; shenandoah_padding(2); - template + template void contended_lock_internal(JavaThread* java_thread); - public: ShenandoahLock() : _state(unlocked), _owner(nullptr) {}; void lock(bool allow_block_for_safepoint) { assert(Atomic::load(&_owner) != Thread::current(), "reentrant locking attempt, would deadlock"); - // Try to lock fast, or dive into contended lock handling. - if (Atomic::cmpxchg(&_state, unlocked, locked) != unlocked) { + if ((allow_block_for_safepoint && SafepointSynchronize::is_synchronizing()) || + (Atomic::cmpxchg(&_state, unlocked, locked) != unlocked)) { + // 1. Java thread, and there is a pending safepoint. Dive into contended locking + // immediately without trying anything else, and block. + // 2. Fast lock fails, dive into contended lock handling. contended_lock(allow_block_for_safepoint); } From 4ebb77120af5a4ccbfde63b24cb50e05a3161f16 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 26 Jun 2024 20:24:29 +0000 Subject: [PATCH 064/288] 8334769: Shenandoah: Move CodeCache_lock close to its use in ShenandoahConcurrentNMethodIterator Reviewed-by: shade, wkemper, kdnilsen --- src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp | 5 +---- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 5 +---- src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp | 5 +++-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index 960927ee787a2..e61dca2bdbf6d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -102,12 +103,10 @@ class ShenandoahDisarmNMethodsTask : public WorkerTask { WorkerTask("Shenandoah Disarm NMethods"), _iterator(ShenandoahCodeRoots::table()) { assert(SafepointSynchronize::is_at_safepoint(), "Only at a safepoint"); - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _iterator.nmethods_do_begin(); } ~ShenandoahDisarmNMethodsTask() { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _iterator.nmethods_do_end(); } @@ -177,12 +176,10 @@ class ShenandoahUnlinkTask : public WorkerTask { WorkerTask("Shenandoah Unlink NMethods"), _cl(unloading_occurred), _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(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index a6b01d04a4756..44ccac467fe85 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -771,14 +772,12 @@ class ShenandoahConcurrentWeakRootsEvacUpdateTask : public WorkerTask { _nmethod_itr(ShenandoahCodeRoots::table()), _phase(phase) { if (ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _nmethod_itr.nmethods_do_begin(); } } ~ShenandoahConcurrentWeakRootsEvacUpdateTask() { if (ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _nmethod_itr.nmethods_do_end(); } // Notify runtime data structures of potentially dead oops @@ -884,14 +883,12 @@ class ShenandoahConcurrentRootsEvacUpdateTask : public WorkerTask { _cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers(), false /*heap iteration*/), _nmethod_itr(ShenandoahCodeRoots::table()) { if (!ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _nmethod_itr.nmethods_do_begin(); } } ~ShenandoahConcurrentRootsEvacUpdateTask() { if (!ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _nmethod_itr.nmethods_do_end(); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index f874f2a324944..54efd658eafdf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -478,7 +479,7 @@ ShenandoahConcurrentNMethodIterator::ShenandoahConcurrentNMethodIterator(Shenand } void ShenandoahConcurrentNMethodIterator::nmethods_do_begin() { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _table_snapshot = _table->snapshot_for_iteration(); } @@ -488,7 +489,7 @@ void ShenandoahConcurrentNMethodIterator::nmethods_do(NMethodClosure* cl) { } void ShenandoahConcurrentNMethodIterator::nmethods_do_end() { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); _table->finish_iteration(_table_snapshot); CodeCache_lock->notify_all(); } From 07bc523df85fde81bf736fedac62874d3cb11ee3 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Wed, 26 Jun 2024 22:28:33 +0000 Subject: [PATCH 065/288] 8334670: SSLSocketOutputRecord buffer miscalculation Reviewed-by: djelinski, ssahoo --- .../classes/sun/security/ssl/SSLSocketOutputRecord.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java index 3b0473d4eb0ce..a7809754ed039 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,12 +168,12 @@ void encodeHandshake(byte[] source, for (int limit = (offset + length); offset < limit;) { - int remains = (limit - offset) + (count - position); - int fragLen = Math.min(fragLimit, remains); + int remains = (limit - offset); + int fragLen = Math.min(fragLimit - count + position, remains); // use the buf of ByteArrayOutputStream write(source, offset, fragLen); - if (remains < fragLimit) { + if (remains < fragLen) { return; } From 3796fdfcedc2b2202b72cca062218f840960414c Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Wed, 26 Jun 2024 23:17:32 +0000 Subject: [PATCH 066/288] 8328536: javac - crash on unknown type referenced in yield statement Co-authored-by: Jan Lahoda Reviewed-by: jlahoda --- .../com/sun/tools/javac/comp/Attr.java | 7 +++-- test/langtools/jdk/jshell/ToolSimpleTest.java | 9 +++++- .../generics/diamond/7188968/T7188968.out | 7 ++++- .../tools/javac/lambda/MethodReference23.out | 2 +- .../MethodRefToInnerWithoutOuter.out | 2 +- .../tools/javac/recovery/AttrRecovery.java | 31 +++++++++++++++++++ 6 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 08c37fc5aa4ba..f58319496e968 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4646,9 +4646,6 @@ Type checkIdInternal(JCTree tree, Type pt, Env env, ResultInfo resultInfo) { - if (pt.isErroneous()) { - return types.createErrorType(site); - } Type owntype; // The computed type of this identifier occurrence. switch (sym.kind) { case TYP: @@ -4757,6 +4754,10 @@ else if (ownOuter.hasTag(CLASS) && site != ownOuter) { chk.checkPreview(tree.pos(), env.info.scope.owner, sym); } + if (pt.isErroneous()) { + owntype = types.createErrorType(owntype); + } + // If symbol is a variable, check that its type and // kind are compatible with the prototype and protokind. return check(tree, owntype, sym.kind.toSelector(), resultInfo); diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 222acb5291c75..60d4f36952103 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -27,7 +27,7 @@ * 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 * 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 * 8192979 8191842 8198573 8198801 8210596 8210959 8215099 8199623 8236715 - * 8239536 8247456 8246774 8238173 8292625 8306560 + * 8239536 8247456 8246774 8238173 8292625 8306560 8328536 * @summary Simple jshell tool tests * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -964,6 +964,13 @@ public void testSwitchStatementExpressionDisambiguation() { ); } + @Test + public void testSwitchExpressionYieldUnknownType() { + test(a -> assertCommandOutputContains(a, + "I m(I i, int x) { return switch (x) { default -> i; }; } ", + "created method m(I,int), however, it cannot be referenced until class I is declared")); + } + @Test public void testSelfReference() { test( diff --git a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out index 83b7b8b671d94..efceb84c8c7fb 100644 --- a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out +++ b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out @@ -1,7 +1,12 @@ T7188968.java:20:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:21:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:22:22: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:22:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo +T7188968.java:22:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:23:20: compiler.warn.unchecked.meth.invocation.applied: kindname.method, makeFoo, java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo +T7188968.java:23:21: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List 4 errors -1 warning +6 warnings diff --git a/test/langtools/tools/javac/lambda/MethodReference23.out b/test/langtools/tools/javac/lambda/MethodReference23.out index f81c0a6745e4c..456a002bd99af 100644 --- a/test/langtools/tools/javac/lambda/MethodReference23.out +++ b/test/langtools/tools/javac/lambda/MethodReference23.out @@ -1,5 +1,5 @@ MethodReference23.java:52:19: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23) -MethodReference23.java:53:16: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23) +MethodReference23.java:53:16: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23) MethodReference23.java:57:19: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23) MethodReference23.java:58:16: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23) MethodReference23.java:72:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference23.SAM21), MethodReference23, kindname.method, call3(MethodReference23.SAM22), MethodReference23 diff --git a/test/langtools/tools/javac/lambda/methodReference/MethodRefToInnerWithoutOuter.out b/test/langtools/tools/javac/lambda/methodReference/MethodRefToInnerWithoutOuter.out index bafb5d1a19359..03b3d33836905 100644 --- a/test/langtools/tools/javac/lambda/methodReference/MethodRefToInnerWithoutOuter.out +++ b/test/langtools/tools/javac/lambda/methodReference/MethodRefToInnerWithoutOuter.out @@ -1,2 +1,2 @@ -MethodRefToInnerWithoutOuter.java:22:31: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: TestString, , MethodRefToInnerBase) +MethodRefToInnerWithoutOuter.java:22:31: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: TestString, java.lang.String, MethodRefToInnerBase) 1 error diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 01cf665be1337..629cef45c6270 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -203,4 +203,35 @@ public interface FI { } } + @Test + public void testErroneousTarget() throws Exception { + String code = """ + public class C { + public Undefined g(Undefined u) { + return switch (0) { + default -> u; + }; + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL, 1) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:2:24: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:2:12: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, C, null)", + "2 errors" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } From 6682305ee21cf595ec953d95bea594734a2982a8 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 27 Jun 2024 03:34:04 +0000 Subject: [PATCH 067/288] 8334779: Test compiler/c1/CanonicalizeArrayLength.java is timing out Reviewed-by: thartmann, dlong --- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 64142a6aee5d6..affd18f937ca8 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -5142,7 +5142,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line); b = code_string(ss.as_string()); } - ExternalAddress buffer((address) b); + AddressLiteral buffer((address) b, external_word_Relocation::spec_for_immediate()); pushptr(buffer.addr(), rscratch1); // call indirectly to solve generation ordering problem @@ -5212,7 +5212,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f ss.print("verify_oop_addr: %s (%s:%d)", s, file, line); b = code_string(ss.as_string()); } - ExternalAddress buffer((address) b); + AddressLiteral buffer((address) b, external_word_Relocation::spec_for_immediate()); pushptr(buffer.addr(), rscratch1); // call indirectly to solve generation ordering problem From 9bb675f89dd1eeec423ca96cb3f96d29f5de477c Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 27 Jun 2024 04:38:32 +0000 Subject: [PATCH 068/288] 8334719: (se) Deferred close of SelectableChannel may result in a Selector doing the final close before concurrent I/O on channel has completed Co-authored-by: Alan Bateman Reviewed-by: alanb, dfuchs --- .../sun/nio/ch/DatagramChannelImpl.java | 5 + .../sun/nio/ch/ServerSocketChannelImpl.java | 3 + .../classes/sun/nio/ch/SocketChannelImpl.java | 5 + .../classes/sun/nio/ch/SinkChannelImpl.java | 3 + .../classes/sun/nio/ch/SourceChannelImpl.java | 3 + .../DeferredClose/DeferredCloseTest.java | 484 ++++++++++++++++++ .../java.base/java/net/InetSocketAddress.java | 202 ++++++++ 7 files changed, 705 insertions(+) create mode 100644 test/jdk/java/nio/channels/Selector/DeferredClose/DeferredCloseTest.java create mode 100644 test/jdk/java/nio/channels/Selector/DeferredClose/java.base/java/net/InetSocketAddress.java diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 31823cfbb871a..5c06ac7d9be02 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -1945,6 +1945,11 @@ protected void implCloseSelectableChannel() throws IOException { @Override public void kill() { + // wait for any read/write operations to complete before trying to close + readLock.lock(); + readLock.unlock(); + writeLock.lock(); + writeLock.unlock(); synchronized (stateLock) { if (state == ST_CLOSING) { tryFinishClose(); diff --git a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index c6ddad2a05c23..0bd72bacf0b08 100644 --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -654,6 +654,9 @@ protected void implCloseSelectableChannel() throws IOException { @Override public void kill() { + // wait for any accept operation to complete before trying to close + acceptLock.lock(); + acceptLock.unlock(); synchronized (stateLock) { if (state == ST_CLOSING) { tryFinishClose(); diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index f23a0aa015297..ebbf55acd9711 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1216,6 +1216,11 @@ protected void implCloseSelectableChannel() throws IOException { @Override public void kill() { + // wait for any read/write operations to complete before trying to close + readLock.lock(); + readLock.unlock(); + writeLock.lock(); + writeLock.unlock(); synchronized (stateLock) { if (state == ST_CLOSING) { tryFinishClose(); diff --git a/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java b/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java index 491e0104765e8..bc15d8d156b8f 100644 --- a/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/SinkChannelImpl.java @@ -201,6 +201,9 @@ protected void implCloseSelectableChannel() throws IOException { @Override public void kill() { + // wait for any write operation to complete before trying to close + writeLock.lock(); + writeLock.unlock(); synchronized (stateLock) { if (state == ST_CLOSING) { tryFinishClose(); diff --git a/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java b/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java index 102041dd29490..2990d35b51695 100644 --- a/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/SourceChannelImpl.java @@ -200,6 +200,9 @@ protected void implCloseSelectableChannel() throws IOException { } @Override public void kill() { + // wait for any read operation to complete before trying to close + readLock.lock(); + readLock.unlock(); synchronized (stateLock) { assert !isOpen(); if (state == ST_CLOSING) { diff --git a/test/jdk/java/nio/channels/Selector/DeferredClose/DeferredCloseTest.java b/test/jdk/java/nio/channels/Selector/DeferredClose/DeferredCloseTest.java new file mode 100644 index 0000000000000..42dd7d42f568f --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/DeferredClose/DeferredCloseTest.java @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.time.Instant; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8334719 + * @summary verifies that if a registered channel has in-progress operations, then + * the Selector during its deferred close implementation won't prematurely release + * the channel's resources + * + * @comment we use a patched java.net.InetSocketAddress to allow the test to intentionally + * craft some delays at specific locations in the implementation of InetSocketAddress + * to trigger race conditions + * @compile/module=java.base java/net/InetSocketAddress.java + * @run junit/othervm DeferredCloseTest + */ +public class DeferredCloseTest { + + private static final int NUM_ITERATIONS = 10; + private static final InetSocketAddress BIND_ADDR = new InetSocketAddress( + InetAddress.getLoopbackAddress(), 0); + + @BeforeAll + public static void beforeAll() throws Exception { + // configure our patched java.net.InetSocketAddress implementation + // to introduce delay in certain methods which get invoked + // internally from the DC.send() implementation + InetSocketAddress.enableDelay(); + } + + @AfterAll + public static void afterAll() throws Exception { + // delays in patched InetSocketAddress are no longer needed + InetSocketAddress.disableDelay(); + } + + private static Stream dcOperations() { + return Stream.of( + Arguments.of( + // repeatedly do DC.send() till there's a ClosedChannelException + "DC.send()", + null, + (Function) (dc) -> { + ByteBuffer bb = ByteBuffer.allocate(100); + try { + // We send to ourselves. Target, content and + // receipt of the Datagram isn't of importance + // in this test. + SocketAddress target = dc.getLocalAddress(); + System.out.println("DC: " + dc + " sending to " + target); + while (true) { + bb.clear(); + dc.send(bb, target); + } + } catch (ClosedChannelException _) { + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } + ), + Arguments.of( + // repeatedly do DC.receive() till there's a ClosedChannelException + "DC.receive()", + (Function) (dc) -> { + try { + SocketAddress target = dc.getLocalAddress(); + ByteBuffer sendBB = ByteBuffer.allocate(100); + // first send() a few datagrams so that subsequent + // receive() does receive them and thus triggers + // the potential race with the deferred close + for (int i = 0; i < 5; i++) { + sendBB.clear(); + dc.send(sendBB, target); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + }, + (Function) (dc) -> { + try { + ByteBuffer rcvBB = ByteBuffer.allocate(10); + while (true) { + rcvBB.clear(); + dc.receive(rcvBB); + } + } catch (ClosedChannelException _) { + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } + ) + ); + } + + /** + * Runs the test for DatagramChannel. + * + * @see #runTest(ExecutorService, SelectionKey, Callable, CountDownLatch) + */ + @ParameterizedTest + @MethodSource("dcOperations") + public void testDatagramChannel(String opName, Function preOp, + Function dcOperation) + throws Exception { + try (ExecutorService executor = Executors.newFixedThreadPool(2)) { + for (int i = 1; i <= NUM_ITERATIONS; i++) { + System.out.format("%s DatagramChannel - %d of %d ...%n", + Instant.now(), i, NUM_ITERATIONS); + try (Selector sel = Selector.open(); + DatagramChannel dc = DatagramChannel.open()) { + // create a non-blocking bound DatagramChannel + dc.bind(BIND_ADDR); + dc.configureBlocking(false); + // register the DatagramChannel with a selector + // (doesn't matter the interestOps) + SelectionKey key = dc.register(sel, SelectionKey.OP_READ); + if (preOp != null) { + preOp.apply(dc); + } + CountDownLatch opStartLatch = new CountDownLatch(1); + runTest(executor, key, () -> { + // notify that we will now start operation on the DC + opStartLatch.countDown(); + return dcOperation.apply(dc); + }, opStartLatch); + } + } + } + } + + + private static Stream scOperations() { + return Stream.of( + Arguments.of( + // repeatedly do SC.write() till there's a ClosedChannelException + "SC.write()", (Function) (sc) -> { + ByteBuffer bb = ByteBuffer.allocate(100); + try { + System.out.println("SC: " + sc + " writing"); + while (true) { + bb.clear(); + sc.write(bb); + } + } catch (ClosedChannelException _) { + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + return null; + } + ), + Arguments.of( + // repeatedly do SC.read() till there's a ClosedChannelException + "SC.read()", (Function) (sc) -> { + ByteBuffer bb = ByteBuffer.allocate(100); + try { + System.out.println("SC: " + sc + " reading"); + while (true) { + bb.clear(); + sc.read(bb); + } + } catch (ClosedChannelException _) { + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + return null; + } + ) + ); + } + + /** + * Runs the test for SocketChannel + * + * @see #runTest(ExecutorService, SelectionKey, Callable, CountDownLatch) + */ + @ParameterizedTest + @MethodSource("scOperations") + public void testSocketChannel(String opName, Function scOperation) + throws Exception { + try (ExecutorService executor = Executors.newFixedThreadPool(3)) { + for (int i = 1; i <= NUM_ITERATIONS; i++) { + System.out.format("%s SocketChannel - %d of %d ...%n", + Instant.now(), i, NUM_ITERATIONS); + try (Selector sel = Selector.open(); + SocketChannel sc = SocketChannel.open()) { + // create and bind a SocketChannel + sc.bind(BIND_ADDR); + // stay in blocking mode till the SocketChannel is connected + sc.configureBlocking(true); + Future acceptedChannel; + SocketChannel conn; + // create a remote server and connect to it + try (ServerSocketChannel server = ServerSocketChannel.open()) { + server.bind(BIND_ADDR); + SocketAddress remoteAddr = server.getLocalAddress(); + acceptedChannel = executor.submit(new ConnAcceptor(server)); + System.out.println("connecting to " + remoteAddr); + sc.connect(remoteAddr); + conn = acceptedChannel.get(); + } + try (conn) { + // switch to non-blocking + sc.configureBlocking(false); + System.out.println("switched to non-blocking: " + sc); + // register the SocketChannel with a selector + // (doesn't matter the interestOps) + SelectionKey key = sc.register(sel, SelectionKey.OP_READ); + CountDownLatch opStartLatch = new CountDownLatch(1); + runTest(executor, key, () -> { + // notify that we will now start operation on the SC + opStartLatch.countDown(); + return scOperation.apply(sc); + }, opStartLatch); + } + } + } + } + } + + /** + * Runs the test for ServerSocketChannel + * + * @see #runTest(ExecutorService, SelectionKey, Callable, CountDownLatch) + */ + @Test + public void testServerSocketChannel() throws Exception { + try (ExecutorService executor = Executors.newFixedThreadPool(2)) { + for (int i = 1; i <= NUM_ITERATIONS; i++) { + System.out.format("%s ServerSocketChannel - %d of %d ...%n", + Instant.now(), i, NUM_ITERATIONS); + try (Selector sel = Selector.open(); + ServerSocketChannel ssc = ServerSocketChannel.open()) { + // create and bind a ServerSocketChannel + ssc.bind(BIND_ADDR); + ssc.configureBlocking(false); + // register the ServerSocketChannel with a selector + SelectionKey key = ssc.register(sel, SelectionKey.OP_ACCEPT); + CountDownLatch opStartLatch = new CountDownLatch(1); + runTest(executor, key, () -> { + // notify that we will now start accept()ing + opStartLatch.countDown(); + // repeatedly do SSC.accept() till there's a ClosedChannelException + try { + while (true) { + ssc.accept(); + } + } catch (ClosedChannelException _) { + } + return null; + }, opStartLatch); + } + } + } + } + + /** + * Runs the test for SinkChannel + * + * @see #runTest(ExecutorService, SelectionKey, Callable, CountDownLatch) + */ + @Test + public void testSinkChannel() throws Exception { + try (ExecutorService executor = Executors.newFixedThreadPool(2)) { + for (int i = 1; i <= NUM_ITERATIONS; i++) { + System.out.format("%s SinkChannel - %d of %d ...%n", + Instant.now(), i, NUM_ITERATIONS); + Pipe pipe = Pipe.open(); + try (Selector sel = Selector.open(); + Pipe.SinkChannel sink = pipe.sink()) { + sink.configureBlocking(false); + SelectionKey key = sink.register(sel, SelectionKey.OP_WRITE); + CountDownLatch opStartLatch = new CountDownLatch(1); + runTest(executor, key, () -> { + // notify that we will now start write()ing + opStartLatch.countDown(); + // repeatedly do SC.write() till there's a ClosedChannelException + ByteBuffer bb = ByteBuffer.allocate(100); + try { + while (true) { + bb.clear(); + sink.write(bb); + } + } catch (ClosedChannelException _) { + } + return null; + }, opStartLatch); + } + } + } + } + + /** + * Runs the test for SourceChannel + * + * @see #runTest(ExecutorService, SelectionKey, Callable, CountDownLatch) + */ + @Test + public void testSourceChannel() throws Exception { + try (ExecutorService executor = Executors.newFixedThreadPool(2)) { + for (int i = 1; i <= NUM_ITERATIONS; i++) { + System.out.format("%s SourceChannel - %d of %d ...%n", + Instant.now(), i, NUM_ITERATIONS); + Pipe pipe = Pipe.open(); + try (Selector sel = Selector.open(); + Pipe.SourceChannel source = pipe.source()) { + source.configureBlocking(false); + SelectionKey key = source.register(sel, SelectionKey.OP_READ); + CountDownLatch opStartLatch = new CountDownLatch(1); + runTest(executor, key, () -> { + // notify that we will now start read()ing + opStartLatch.countDown(); + // repeatedly do SC.read() till there's a ClosedChannelException + ByteBuffer bb = ByteBuffer.allocate(100); + try { + while (true) { + bb.clear(); + source.read(bb); + } + } catch (ClosedChannelException _) { + } + return null; + }, opStartLatch); + } + } + } + } + + /** + * SelectableChannel implementations internally have a deferred close implementation. When a + * channel is registered with a Selector and close() is invoked on the channel from a certain + * thread, then the implementation of close() defers the actual close if the channel has + * in-progress operations (for example, read/write/send/receive and such) in some other thread. + * A subsequent operation through the Selector (like Selector.select()) then completes the + * deferred close (waiting for any in-progress operations to complete). This test method + * verifies that the deferred close implementation doesn't prematurely close and release + * the resources used by the channel, while there are in-progress operations. + *

    + * Launches 2 threads, T1 and T2. When T1 and T2 are in progress, this method closes the + * channel that is registered with the Selector. + * T1 is running the channelOperation (which keeps running operations on the channel). + * T2 is running a task which keeps invoking Selector.select(), until the channel is closed. + * When T2 notices that the channel is closed, it cancels the selectionKey and then + * invokes one last Selector.select() operation to finish the deferred close of the channel. + */ + private static void runTest(ExecutorService executor, SelectionKey selectionKey, + Callable channelOperation, CountDownLatch chanOpStartLatch) + throws Exception { + + SelectableChannel channel = selectionKey.channel(); + assertFalse(channel.isBlocking(), "channel isn't non-blocking: " + channel); + selectionKey.selector().selectNow(); + // run the channel operations + Future channelOpResult = executor.submit(channelOperation); + CountDownLatch selectorTaskStartLatch = new CountDownLatch(1); + // run the Selector.select() task + Future selectorTaskResult = executor.submit( + new SelectorTask(selectionKey, selectorTaskStartLatch)); + // await for the channel operation task and the selector task to start + chanOpStartLatch.await(); + selectorTaskStartLatch.await(); + // close the channel while it's still registered with the Selector, + // so that the close is deferred by the channel implementations. + System.out.println("closing channel: " + channel); + assertTrue(channel.isOpen(), "channel already closed: " + channel); + assertTrue(channel.isRegistered(), "channel isn't registered: " + channel); + channel.close(); + // wait for the operation on the channel and the selector task to complete + channelOpResult.get(); + selectorTaskResult.get(); + } + + /* + * Keeps invoking Selector.select() until the channel is closed, after which + * it cancels the SelectionKey and does one last Selector.select() to finish + * the deferred close. + */ + private static final class SelectorTask implements Callable { + private final SelectionKey selectionKey; + private final CountDownLatch startedLatch; + + private SelectorTask(SelectionKey selectionKey, CountDownLatch startedLatch) { + this.selectionKey = Objects.requireNonNull(selectionKey); + this.startedLatch = startedLatch; + } + + @Override + public Void call() throws Exception { + try { + Selector selector = selectionKey.selector(); + SelectableChannel channel = selectionKey.channel(); + // notify that the task has started + startedLatch.countDown(); + while (true) { + selector.select(10); + if (!channel.isOpen()) { + // the channel is (defer) closed, cancel the registration and then + // issue a select() so that the Selector finishes the deferred + // close of the channel. + System.out.println("channel: " + channel + " isn't open," + + " now cancelling key: " + selectionKey); + selectionKey.cancel(); + System.out.println("initiating select after key cancelled: " + selectionKey); + selector.select(5); + break; + } + } + } catch (ClosedSelectorException _) { + } + return null; + } + } + + private static final class ConnAcceptor implements Callable { + private final ServerSocketChannel serverSocketChannel; + + private ConnAcceptor(ServerSocketChannel serverSocketChannel) { + this.serverSocketChannel = serverSocketChannel; + } + + @Override + public SocketChannel call() throws Exception { + SocketChannel accepted = serverSocketChannel.accept(); + System.out.println("Accepted connection: " + accepted); + return accepted; + } + } +} diff --git a/test/jdk/java/nio/channels/Selector/DeferredClose/java.base/java/net/InetSocketAddress.java b/test/jdk/java/nio/channels/Selector/DeferredClose/java.base/java/net/InetSocketAddress.java new file mode 100644 index 0000000000000..5994e9268a12f --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/DeferredClose/java.base/java/net/InetSocketAddress.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.net; + + +import java.util.Locale; + +// Patched implementation only meant to be used in certain tests +public class InetSocketAddress extends SocketAddress { + + @java.io.Serial + private static final long serialVersionUID = 5076001401234631237L; + + private static boolean enableDelay; + + static { + System.out.println("patched InetSocketAddress class in use"); + } + + private final String hostname; + private final InetAddress addr; + private final int port; + + public InetSocketAddress(int port) { + this(InetAddress.anyLocalAddress(), port); + } + + public InetSocketAddress(InetAddress addr, int port) { + this(null, + addr == null ? InetAddress.anyLocalAddress() : addr, + checkPort(port)); + } + + public InetSocketAddress(String hostname, int port) { + checkHost(hostname); + InetAddress addr = null; + String host = null; + try { + addr = InetAddress.getByName(hostname); + } catch (UnknownHostException e) { + host = hostname; + } + this.hostname = host; + this.addr = addr; + this.port = checkPort(port); + } + + public static InetSocketAddress createUnresolved(String host, int port) { + return new InetSocketAddress(checkHost(host), null, checkPort(port)); + } + + public static void enableDelay() { + enableDelay = true; + } + + public static void disableDelay() { + enableDelay = false; + } + + private InetSocketAddress(String hostname, InetAddress addr, int port) { + this.hostname = hostname; + this.addr = addr; + this.port = port; + if (enableDelay) { + doDelay(); + } + } + + /** + * Gets the port number. + * + * @return the port number. + */ + public final int getPort() { + if (enableDelay) { + doDelay(); + } + return this.port; + } + + /** + * Gets the {@code InetAddress}. + * + * @return the InetAddress or {@code null} if it is unresolved. + */ + public final InetAddress getAddress() { + return this.addr; + } + + public final String getHostName() { + if (hostname != null) { + return hostname; + } + if (addr != null) { + return addr.getHostName(); + } + return null; + } + + public final String getHostString() { + if (hostname != null) { + return hostname; + } + if (addr != null) { + if (addr.holder().getHostName() != null) { + return addr.holder().getHostName(); + } else { + return addr.getHostAddress(); + } + } + return null; + } + + public final boolean isUnresolved() { + return addr == null; + } + + @Override + public String toString() { + String formatted; + if (isUnresolved()) { + formatted = hostname + "/"; + } else { + formatted = addr.toString(); + if (addr instanceof Inet6Address) { + int i = formatted.lastIndexOf("/"); + formatted = formatted.substring(0, i + 1) + + "[" + formatted.substring(i + 1) + "]"; + } + } + return formatted + ":" + port; + } + + @Override + public final boolean equals(Object other) { + if (!(other instanceof InetSocketAddress that)) { + return false; + } + boolean sameIP; + if (addr != null) { + sameIP = addr.equals(that.addr); + } else if (hostname != null) { + sameIP = (that.addr == null) && + hostname.equalsIgnoreCase(that.hostname); + } else { + sameIP = (that.addr == null) && (that.hostname == null); + } + return sameIP && (port == that.port); + } + + @Override + public final int hashCode() { + if (addr != null) { + return addr.hashCode() + port; + } + if (hostname != null) { + return hostname.toLowerCase(Locale.ROOT).hashCode() + port; + } + return port; + } + + private static int checkPort(int port) { + if (port < 0 || port > 0xFFFF) + throw new IllegalArgumentException("port out of range:" + port); + return port; + } + + private static String checkHost(String hostname) { + if (hostname == null) + throw new IllegalArgumentException("hostname can't be null"); + return hostname; + } + + private static void doDelay() { + System.out.println("intentional delay injected in InetSocketAddress"); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} From 9d20b58f40275002afa0348d94d5592a26894e88 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 27 Jun 2024 05:13:30 +0000 Subject: [PATCH 069/288] 8334328: Reduce object allocation for FloatToDecimal and DoubleToDecimal Reviewed-by: redestad, rgiulietti --- .../java/lang/AbstractStringBuilder.java | 19 +- .../jdk/internal/math/DoubleToDecimal.java | 256 ++++++------------ .../jdk/internal/math/FloatToDecimal.java | 241 ++++++----------- .../classes/jdk/internal/math/ToDecimal.java | 163 +++++++++++ .../bench/java/lang/StringBuilders.java | 71 ++++- 5 files changed, 401 insertions(+), 349 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/math/ToDecimal.java diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 187e041e6745a..7e5056a539b8c 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -885,13 +885,10 @@ public AbstractStringBuilder append(long l) { * @return a reference to this object. */ public AbstractStringBuilder append(float f) { - try { - FloatToDecimal.appendTo(f, this); - } catch (IOException e) { - throw new AssertionError(e); - } + ensureCapacityInternal(count + FloatToDecimal.MAX_CHARS); + FloatToDecimal toDecimal = isLatin1() ? FloatToDecimal.LATIN1 : FloatToDecimal.UTF16; + count = toDecimal.putDecimal(value, count, f); return this; - } /** @@ -907,11 +904,9 @@ public AbstractStringBuilder append(float f) { * @return a reference to this object. */ public AbstractStringBuilder append(double d) { - try { - DoubleToDecimal.appendTo(d, this); - } catch (IOException e) { - throw new AssertionError(e); - } + ensureCapacityInternal(count + DoubleToDecimal.MAX_CHARS); + DoubleToDecimal toDecimal = isLatin1() ? DoubleToDecimal.LATIN1 : DoubleToDecimal.UTF16; + count = toDecimal.putDecimal(value, count, d); return this; } diff --git a/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java b/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java index e3472d559b2c1..441137db4862b 100644 --- a/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * 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,10 +33,24 @@ import static java.lang.Math.multiplyHigh; import static jdk.internal.math.MathUtils.*; +import sun.nio.cs.ISO_8859_1; + /** * This class exposes a method to render a {@code double} as a string. */ -public final class DoubleToDecimal { +public final class DoubleToDecimal extends ToDecimal { + /** + * Use LATIN1 encoding to process the in-out byte[] str + * + */ + public static final DoubleToDecimal LATIN1 = new DoubleToDecimal(true); + + /** + * Use UTF16 encoding to process the in-out byte[] str + * + */ + public static final DoubleToDecimal UTF16 = new DoubleToDecimal(false); + /* * For full details about this code see the following references: * @@ -91,16 +106,6 @@ public final class DoubleToDecimal { /* Used in rop() */ private static final long MASK_63 = (1L << 63) - 1; - /* Used for left-to-tight digit extraction */ - private static final int MASK_28 = (1 << 28) - 1; - - private static final int NON_SPECIAL = 0; - private static final int PLUS_ZERO = 1; - private static final int MINUS_ZERO = 2; - private static final int PLUS_INF = 3; - private static final int MINUS_INF = 4; - private static final int NAN = 5; - /* * Room for the longer of the forms * -ddddd.dddddddddddd H + 2 characters @@ -110,13 +115,8 @@ public final class DoubleToDecimal { */ public static final int MAX_CHARS = H + 7; - private final byte[] bytes; - - /* Index into bytes of rightmost valid character */ - private int index; - - private DoubleToDecimal(boolean noChars) { - bytes = noChars ? null : new byte[MAX_CHARS]; + private DoubleToDecimal(boolean latin1) { + super(latin1); } /** @@ -128,7 +128,14 @@ private DoubleToDecimal(boolean noChars) { * @see Double#toString(double) */ public static String toString(double v) { - return new DoubleToDecimal(false).toDecimalString(v); + byte[] str = new byte[MAX_CHARS]; + int pair = LATIN1.toDecimal(str, 0, v, null); + int type = pair & 0xFF00; + if (type == NON_SPECIAL) { + int size = pair & 0xFF; + return new String(str, 0, size, ISO_8859_1.INSTANCE); + } + return special(type); } /** @@ -149,71 +156,42 @@ public static String toString(double v) { * @param fd the object that will carry f, e, and n. */ public static void split(double v, FormattedFPDecimal fd) { - new DoubleToDecimal(true).toDecimal(v, fd); + byte[] str = new byte[MAX_CHARS]; + LATIN1.toDecimal(str, 0, v, fd); } /** - * Appends the rendering of the {@code v} to {@code app}. + * Appends the rendering of the {@code v} to {@code str}. * *

    The outcome is the same as if {@code v} were first * {@link #toString(double) rendered} and the resulting string were then - * {@link Appendable#append(CharSequence) appended} to {@code app}. * - * @param v the {@code double} whose rendering is appended. - * @param app the {@link Appendable} to append to. + * @param str the String byte array to append to + * @param index the index into str + * @param v the {@code double} whose rendering is into str. * @throws IOException If an I/O error occurs */ - public static Appendable appendTo(double v, Appendable app) - throws IOException { - return new DoubleToDecimal(false).appendDecimalTo(v, app); - } + public int putDecimal(byte[] str, int index, double v) { + assert 0 <= index && index <= length(str) - MAX_CHARS : "Trusted caller missed bounds check"; - private String toDecimalString(double v) { - return switch (toDecimal(v, null)) { - case NON_SPECIAL -> charsToString(); - case PLUS_ZERO -> "0.0"; - case MINUS_ZERO -> "-0.0"; - case PLUS_INF -> "Infinity"; - case MINUS_INF -> "-Infinity"; - default -> "NaN"; - }; - } - - private Appendable appendDecimalTo(double v, Appendable app) - throws IOException { - switch (toDecimal(v, null)) { - case NON_SPECIAL: - char[] chars = new char[index + 1]; - for (int i = 0; i < chars.length; ++i) { - chars[i] = (char) bytes[i]; - } - if (app instanceof StringBuilder builder) { - return builder.append(chars); - } - if (app instanceof StringBuffer buffer) { - return buffer.append(chars); - } - for (char c : chars) { - app.append(c); - } - return app; - case PLUS_ZERO: return app.append("0.0"); - case MINUS_ZERO: return app.append("-0.0"); - case PLUS_INF: return app.append("Infinity"); - case MINUS_INF: return app.append("-Infinity"); - default: return app.append("NaN"); + int pair = toDecimal(str, index, v, null); + int type = pair & 0xFF00; + if (type == NON_SPECIAL) { + return index + (pair & 0xFF); } + return putSpecial(str, index, type); } /* - * Returns + * Returns size in the lower byte, type in the high byte, where type is * PLUS_ZERO iff v is 0.0 * MINUS_ZERO iff v is -0.0 * PLUS_INF iff v is POSITIVE_INFINITY * MINUS_INF iff v is NEGATIVE_INFINITY * NAN iff v is NaN + * otherwise NON_SPECIAL */ - private int toDecimal(double v, FormattedFPDecimal fd) { + private int toDecimal(byte[] str, int index, double v, FormattedFPDecimal fd) { /* * For full details see references [2] and [1]. * @@ -227,13 +205,13 @@ private int toDecimal(double v, FormattedFPDecimal fd) { long t = bits & T_MASK; int bq = (int) (bits >>> P - 1) & BQ_MASK; if (bq < BQ_MASK) { - index = -1; + int start = index; if (bits < 0) { /* - * fd != null implies bytes == null and bits >= 0 + * fd != null implies str == null and bits >= 0 * Thus, when fd != null, control never reaches here. */ - append('-'); + index = putChar(str, index, '-'); } if (bq != 0) { /* normal value. Here mq = -q */ @@ -243,16 +221,16 @@ private int toDecimal(double v, FormattedFPDecimal fd) { if (0 < mq & mq < P) { long f = c >> mq; if (f << mq == c) { - return toChars(f, 0, fd); + return toChars(str, index, f, 0, fd) - start; } } - return toDecimal(-mq, c, 0, fd); + return toDecimal(str, index, -mq, c, 0, fd) - start; } if (t != 0) { /* subnormal value */ - return t < C_TINY - ? toDecimal(Q_MIN, 10 * t, -1, fd) - : toDecimal(Q_MIN, t, 0, fd); + return (t < C_TINY + ? toDecimal(str, index, Q_MIN, 10 * t, -1, fd) + : toDecimal(str, index, Q_MIN, t, 0, fd)) - start; } return bits == 0 ? PLUS_ZERO : MINUS_ZERO; } @@ -262,7 +240,7 @@ private int toDecimal(double v, FormattedFPDecimal fd) { return bits > 0 ? PLUS_INF : MINUS_INF; } - private int toDecimal(int q, long c, int dk, FormattedFPDecimal fd) { + private int toDecimal(byte[] str, int index, int q, long c, int dk, FormattedFPDecimal fd) { /* * The skeleton corresponds to figure 7 of [1]. * The efficient computations are those summarized in figure 9. @@ -327,7 +305,7 @@ private int toDecimal(int q, long c, int dk, FormattedFPDecimal fd) { boolean upin = vbl + out <= sp10 << 2; boolean wpin = (tp10 << 2) + out <= vbr; if (upin != wpin) { - return toChars(upin ? sp10 : tp10, k, fd); + return toChars(str, index, upin ? sp10 : tp10, k, fd); } } @@ -342,14 +320,14 @@ private int toDecimal(int q, long c, int dk, FormattedFPDecimal fd) { boolean win = (t << 2) + out <= vbr; if (uin != win) { /* Exactly one of u or w lies in Rv */ - return toChars(uin ? s : t, k + dk, fd); + return toChars(str, index, uin ? s : t, k + dk, fd); } /* * Both u and w lie in Rv: determine the one closest to v. * See section 9.3 of [1]. */ long cmp = vb - (s + t << 1); - return toChars(cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk, fd); + return toChars(str, index, cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk, fd); } /* @@ -368,7 +346,7 @@ private static long rop(long g1, long g0, long cp) { /* * Formats the decimal f 10^e. */ - private int toChars(long f, int e, FormattedFPDecimal fd) { + private int toChars(byte[] str, int index, long f, int e, FormattedFPDecimal fd) { /* * For details not discussed here see section 10 of [1]. * @@ -381,7 +359,7 @@ private int toChars(long f, int e, FormattedFPDecimal fd) { } if (fd != null) { fd.set(f, e, len); - return NON_SPECIAL; + return index; } /* @@ -413,115 +391,74 @@ private int toChars(long f, int e, FormattedFPDecimal fd) { int m = (int) (hm - 100_000_000 * h); if (0 < e && e <= 7) { - return toChars1(h, m, l, e); + return toChars1(str, index, h, m, l, e); } if (-3 < e && e <= 0) { - return toChars2(h, m, l, e); + return toChars2(str, index, h, m, l, e); } - return toChars3(h, m, l, e); + return toChars3(str, index, h, m, l, e); } - private int toChars1(int h, int m, int l, int e) { + private int toChars1(byte[] str, int index, int h, int m, int l, int e) { /* * 0 < e <= 7: plain format without leading zeroes. * Left-to-right digits extraction: * algorithm 1 in [3], with b = 10, k = 8, n = 28. */ - appendDigit(h); + index = putDigit(str, index, h); int y = y(m); int t; int i = 1; for (; i < e; ++i) { t = 10 * y; - appendDigit(t >>> 28); + index = putDigit(str, index, t >>> 28); y = t & MASK_28; } - append('.'); + index = putChar(str, index, '.'); for (; i <= 8; ++i) { t = 10 * y; - appendDigit(t >>> 28); + index = putDigit(str, index, t >>> 28); y = t & MASK_28; } - lowDigits(l); - return NON_SPECIAL; + return lowDigits(str, index, l); } - private int toChars2(int h, int m, int l, int e) { + private int toChars2(byte[] str, int index, int h, int m, int l, int e) { /* -3 < e <= 0: plain format with leading zeroes */ - appendDigit(0); - append('.'); + index = putDigit(str, index, 0); + index = putChar(str, index, '.'); for (; e < 0; ++e) { - appendDigit(0); + index = putDigit(str, index, 0); } - appendDigit(h); - append8Digits(m); - lowDigits(l); - return NON_SPECIAL; + index = putDigit(str, index, h); + index = put8Digits(str, index, m); + return lowDigits(str, index, l); } - private int toChars3(int h, int m, int l, int e) { + private int toChars3(byte[] str, int index, int h, int m, int l, int e) { /* -3 >= e | e > 7: computerized scientific notation */ - appendDigit(h); - append('.'); - append8Digits(m); - lowDigits(l); - exponent(e - 1); - return NON_SPECIAL; + index = putDigit(str, index, h); + index = putChar(str, index, '.'); + index = put8Digits(str, index, m); + index = lowDigits(str, index, l); + return exponent(str, index, e - 1); } - private void lowDigits(int l) { + private int lowDigits(byte[] str, int index, int l) { if (l != 0) { - append8Digits(l); + index = put8Digits(str, index, l); } - removeTrailingZeroes(); + return removeTrailingZeroes(str, index); } - private void append8Digits(int m) { - /* - * Left-to-right digits extraction: - * algorithm 1 in [3], with b = 10, k = 8, n = 28. - */ - int y = y(m); - for (int i = 0; i < 8; ++i) { - int t = 10 * y; - appendDigit(t >>> 28); - y = t & MASK_28; - } - } - - private void removeTrailingZeroes() { - while (bytes[index] == '0') { - --index; - } - /* ... but do not remove the one directly to the right of '.' */ - if (bytes[index] == '.') { - ++index; - } - } - - private int y(int a) { - /* - * Algorithm 1 in [3] needs computation of - * floor((a + 1) 2^n / b^k) - 1 - * with a < 10^8, b = 10, k = 8, n = 28. - * Noting that - * (a + 1) 2^n <= 10^8 2^28 < 10^17 - * For n = 17, m = 8 the table in section 10 of [1] leads to: - */ - return (int) (multiplyHigh( - (long) (a + 1) << 28, - 193_428_131_138_340_668L) >>> 20) - 1; - } - - private void exponent(int e) { - append('E'); + private int exponent(byte[] str, int index, int e) { + index = putChar(str, index, 'E'); if (e < 0) { - append('-'); + index = putChar(str, index, '-'); e = -e; } if (e < 10) { - appendDigit(e); - return; + return putDigit(str, index, e); } int d; if (e >= 100) { @@ -530,7 +467,7 @@ private void exponent(int e) { * floor(e / 100) = floor(1_311 e / 2^17) */ d = e * 1_311 >>> 17; - appendDigit(d); + index = putDigit(str, index, d); e -= 100 * d; } /* @@ -538,22 +475,7 @@ private void exponent(int e) { * floor(e / 10) = floor(103 e / 2^10) */ d = e * 103 >>> 10; - appendDigit(d); - appendDigit(e - 10 * d); - } - - private void append(int c) { - bytes[++index] = (byte) c; + index = putDigit(str, index, d); + return putDigit(str, index, e - 10 * d); } - - private void appendDigit(int d) { - bytes[++index] = (byte) ('0' + d); - } - - /* Using the deprecated constructor enhances performance */ - @SuppressWarnings("deprecation") - private String charsToString() { - return new String(bytes, 0, 0, index + 1); - } - } diff --git a/src/java.base/share/classes/jdk/internal/math/FloatToDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatToDecimal.java index 56382767f754c..1ca68a000d965 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatToDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatToDecimal.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * 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,10 +33,24 @@ import static java.lang.Math.multiplyHigh; import static jdk.internal.math.MathUtils.*; +import sun.nio.cs.ISO_8859_1; + /** * This class exposes a method to render a {@code float} as a string. */ -public final class FloatToDecimal { +public final class FloatToDecimal extends ToDecimal { + /** + * Use LATIN1 encoding to process the in-out byte[] str + * + */ + public static final FloatToDecimal LATIN1 = new FloatToDecimal(true); + + /** + * Use UTF16 encoding to process the in-out byte[] str + * + */ + public static final FloatToDecimal UTF16 = new FloatToDecimal(false); + /* * For full details about this code see the following references: * @@ -91,16 +106,6 @@ public final class FloatToDecimal { /* Used in rop() */ private static final long MASK_32 = (1L << 32) - 1; - /* Used for left-to-tight digit extraction */ - private static final int MASK_28 = (1 << 28) - 1; - - private static final int NON_SPECIAL = 0; - private static final int PLUS_ZERO = 1; - private static final int MINUS_ZERO = 2; - private static final int PLUS_INF = 3; - private static final int MINUS_INF = 4; - private static final int NAN = 5; - /* * Room for the longer of the forms * -ddddd.dddd H + 2 characters @@ -110,12 +115,8 @@ public final class FloatToDecimal { */ public static final int MAX_CHARS = H + 6; - private final byte[] bytes = new byte[MAX_CHARS]; - - /* Index into bytes of rightmost valid character */ - private int index; - - private FloatToDecimal() { + private FloatToDecimal(boolean latin1) { + super(latin1); } /** @@ -127,71 +128,49 @@ private FloatToDecimal() { * @see Float#toString(float) */ public static String toString(float v) { - return new FloatToDecimal().toDecimalString(v); + byte[] str = new byte[MAX_CHARS]; + int pair = LATIN1.toDecimal(str, 0, v); + int type = pair & 0xFF00; + if (type == NON_SPECIAL) { + int size = pair & 0xFF; + return new String(str, 0, size, ISO_8859_1.INSTANCE); + } + return special(type); } /** - * Appends the rendering of the {@code v} to {@code app}. + * Appends the rendering of the {@code v} to {@code str}. * *

    The outcome is the same as if {@code v} were first - * {@link #toString(float) rendered} and the resulting string were then - * {@link Appendable#append(CharSequence) appended} to {@code app}. + * {@link #toString(double) rendered} and the resulting string were then * - * @param v the {@code float} whose rendering is appended. - * @param app the {@link Appendable} to append to. + * @param str the String byte array to append to + * @param index the index into str + * @param v the {@code float} whose rendering is into str. * @throws IOException If an I/O error occurs */ - public static Appendable appendTo(float v, Appendable app) - throws IOException { - return new FloatToDecimal().appendDecimalTo(v, app); - } + public int putDecimal(byte[] str, int index, float v) { + assert 0 <= index && index <= length(str) - MAX_CHARS : "Trusted caller missed bounds check"; - private String toDecimalString(float v) { - return switch (toDecimal(v)) { - case NON_SPECIAL -> charsToString(); - case PLUS_ZERO -> "0.0"; - case MINUS_ZERO -> "-0.0"; - case PLUS_INF -> "Infinity"; - case MINUS_INF -> "-Infinity"; - default -> "NaN"; - }; - } - - private Appendable appendDecimalTo(float v, Appendable app) - throws IOException { - switch (toDecimal(v)) { - case NON_SPECIAL: - char[] chars = new char[index + 1]; - for (int i = 0; i < chars.length; ++i) { - chars[i] = (char) bytes[i]; - } - if (app instanceof StringBuilder builder) { - return builder.append(chars); - } - if (app instanceof StringBuffer buffer) { - return buffer.append(chars); - } - for (char c : chars) { - app.append(c); - } - return app; - case PLUS_ZERO: return app.append("0.0"); - case MINUS_ZERO: return app.append("-0.0"); - case PLUS_INF: return app.append("Infinity"); - case MINUS_INF: return app.append("-Infinity"); - default: return app.append("NaN"); + int pair = toDecimal(str, index, v); + int type = pair & 0xFF00; + if (type == NON_SPECIAL) { + return index + (pair & 0xFF); } + return putSpecial(str, index, type); } /* * Returns + * Combine type and size, the first byte is size, the second byte is type + * * PLUS_ZERO iff v is 0.0 * MINUS_ZERO iff v is -0.0 * PLUS_INF iff v is POSITIVE_INFINITY * MINUS_INF iff v is NEGATIVE_INFINITY * NAN iff v is NaN */ - private int toDecimal(float v) { + private int toDecimal(byte[] str, int index, float v) { /* * For full details see references [2] and [1]. * @@ -205,9 +184,9 @@ private int toDecimal(float v) { int t = bits & T_MASK; int bq = (bits >>> P - 1) & BQ_MASK; if (bq < BQ_MASK) { - index = -1; + int start = index; if (bits < 0) { - append('-'); + index = putChar(str, index, '-'); } if (bq != 0) { /* normal value. Here mq = -q */ @@ -217,16 +196,16 @@ private int toDecimal(float v) { if (0 < mq & mq < P) { int f = c >> mq; if (f << mq == c) { - return toChars(f, 0); + return toChars(str, index, f, 0) - start; } } - return toDecimal(-mq, c, 0); + return toDecimal(str, index, -mq, c, 0) - start; } if (t != 0) { /* subnormal value */ - return t < C_TINY - ? toDecimal(Q_MIN, 10 * t, -1) - : toDecimal(Q_MIN, t, 0); + return (t < C_TINY + ? toDecimal(str, index, Q_MIN, 10 * t, -1) + : toDecimal(str, index, Q_MIN, t, 0)) - start; } return bits == 0 ? PLUS_ZERO : MINUS_ZERO; } @@ -236,7 +215,7 @@ private int toDecimal(float v) { return bits > 0 ? PLUS_INF : MINUS_INF; } - private int toDecimal(int q, int c, int dk) { + private int toDecimal(byte[] str, int index, int q, int c, int dk) { /* * The skeleton corresponds to figure 7 of [1]. * The efficient computations are those summarized in figure 9. @@ -300,7 +279,7 @@ private int toDecimal(int q, int c, int dk) { boolean upin = vbl + out <= sp10 << 2; boolean wpin = (tp10 << 2) + out <= vbr; if (upin != wpin) { - return toChars(upin ? sp10 : tp10, k); + return toChars(str, index, upin ? sp10 : tp10, k); } } @@ -315,14 +294,14 @@ private int toDecimal(int q, int c, int dk) { boolean win = (t << 2) + out <= vbr; if (uin != win) { /* Exactly one of u or w lies in Rv */ - return toChars(uin ? s : t, k + dk); + return toChars(str, index, uin ? s : t, k + dk); } /* * Both u and w lie in Rv: determine the one closest to v. * See section 9.3 of [1]. */ int cmp = vb - (s + t << 1); - return toChars(cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk); + return toChars(str, index, cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk); } /* @@ -338,7 +317,7 @@ private static int rop(long g, long cp) { /* * Formats the decimal f 10^e. */ - private int toChars(int f, int e) { + private int toChars(byte[] str, int index, int f, int e) { /* * For details not discussed here see section 10 of [1]. * @@ -373,130 +352,74 @@ private int toChars(int f, int e) { int l = f - 100_000_000 * h; if (0 < e && e <= 7) { - return toChars1(h, l, e); + return toChars1(str, index, h, l, e); } if (-3 < e && e <= 0) { - return toChars2(h, l, e); + return toChars2(str, index, h, l, e); } - return toChars3(h, l, e); + return toChars3(str, index, h, l, e); } - private int toChars1(int h, int l, int e) { + private int toChars1(byte[] str, int index, int h, int l, int e) { /* * 0 < e <= 7: plain format without leading zeroes. * Left-to-right digits extraction: * algorithm 1 in [3], with b = 10, k = 8, n = 28. */ - appendDigit(h); + index = putDigit(str, index, h); int y = y(l); int t; int i = 1; for (; i < e; ++i) { t = 10 * y; - appendDigit(t >>> 28); + index = putDigit(str, index, t >>> 28); y = t & MASK_28; } - append('.'); + index = putChar(str, index, '.'); for (; i <= 8; ++i) { t = 10 * y; - appendDigit(t >>> 28); + index = putDigit(str, index, t >>> 28); y = t & MASK_28; } - removeTrailingZeroes(); - return NON_SPECIAL; + return removeTrailingZeroes(str, index); } - private int toChars2(int h, int l, int e) { + private int toChars2(byte[] str, int index, int h, int l, int e) { /* -3 < e <= 0: plain format with leading zeroes */ - appendDigit(0); - append('.'); + index = putDigit(str, index, 0); + index = putChar(str, index, '.'); for (; e < 0; ++e) { - appendDigit(0); + index = putDigit(str, index, 0); } - appendDigit(h); - append8Digits(l); - removeTrailingZeroes(); - return NON_SPECIAL; + index = putDigit(str, index, h); + index = put8Digits(str, index, l); + return removeTrailingZeroes(str, index); } - private int toChars3(int h, int l, int e) { + private int toChars3(byte[] str, int index, int h, int l, int e) { /* -3 >= e | e > 7: computerized scientific notation */ - appendDigit(h); - append('.'); - append8Digits(l); - removeTrailingZeroes(); - exponent(e - 1); - return NON_SPECIAL; + index = putDigit(str, index, h); + index = putChar(str, index, '.'); + index = put8Digits(str, index, l); + index = removeTrailingZeroes(str, index); + return exponent(str, index, e - 1); } - private void append8Digits(int m) { - /* - * Left-to-right digits extraction: - * algorithm 1 in [3], with b = 10, k = 8, n = 28. - */ - int y = y(m); - for (int i = 0; i < 8; ++i) { - int t = 10 * y; - appendDigit(t >>> 28); - y = t & MASK_28; - } - } - - private void removeTrailingZeroes() { - while (bytes[index] == '0') { - --index; - } - /* ... but do not remove the one directly to the right of '.' */ - if (bytes[index] == '.') { - ++index; - } - } - - private int y(int a) { - /* - * Algorithm 1 in [3] needs computation of - * floor((a + 1) 2^n / b^k) - 1 - * with a < 10^8, b = 10, k = 8, n = 28. - * Noting that - * (a + 1) 2^n <= 10^8 2^28 < 10^17 - * For n = 17, m = 8 the table in section 10 of [1] leads to: - */ - return (int) (multiplyHigh( - (long) (a + 1) << 28, - 193_428_131_138_340_668L) >>> 20) - 1; - } - - private void exponent(int e) { - append('E'); + private int exponent(byte[] str, int index, int e) { + index = putChar(str, index, 'E'); if (e < 0) { - append('-'); + index = putChar(str, index, '-'); e = -e; } if (e < 10) { - appendDigit(e); - return; + return putDigit(str, index, e); } /* * For n = 2, m = 1 the table in section 10 of [1] shows * floor(e / 10) = floor(103 e / 2^10) */ int d = e * 103 >>> 10; - appendDigit(d); - appendDigit(e - 10 * d); - } - - private void append(int c) { - bytes[++index] = (byte) c; + index = putDigit(str, index, d); + return putDigit(str, index, e - 10 * d); } - - private void appendDigit(int d) { - bytes[++index] = (byte) ('0' + d); - } - - /* Using the deprecated constructor enhances performance */ - @SuppressWarnings("deprecation") - private String charsToString() { - return new String(bytes, 0, 0, index + 1); - } - } diff --git a/src/java.base/share/classes/jdk/internal/math/ToDecimal.java b/src/java.base/share/classes/jdk/internal/math/ToDecimal.java new file mode 100644 index 0000000000000..45d4da25323c4 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/math/ToDecimal.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * 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.internal.math; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +import static java.lang.Math.multiplyHigh; + +abstract sealed class ToDecimal permits DoubleToDecimal, FloatToDecimal { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + /* Used for left-to-tight digit extraction */ + static final int MASK_28 = (1 << 28) - 1; + + static final int NON_SPECIAL = 0 << 8; + static final int PLUS_ZERO = 1 << 8; + static final int MINUS_ZERO = 2 << 8; + static final int PLUS_INF = 3 << 8; + static final int MINUS_INF = 4 << 8; + static final int NAN = 5 << 8; + + /** + * The identifier of the encoding used to encode the bytes. If latin1 is true, the encoding is LATIN1, false is UTF16 + * + */ + private final boolean latin1; + + ToDecimal(boolean latin1) { + this.latin1 = latin1; + } + + final int putChar(byte[] str, int index, int c) { + if (latin1) { + str[index] = (byte) c; + } else { + JLA.putCharUTF16(str, index, (char) c); + } + return index + 1; + } + + final int putDigit(byte[] str, int index, int d) { + return putChar(str, index, (byte) ('0' + d)); + } + + final int put8Digits(byte[] str, int index, int m) { + /* + * Left-to-right digits extraction: + * algorithm 1 in [3], with b = 10, k = 8, n = 28. + */ + if (latin1) { + put8DigitsLatin1(str, index, m); + } else { + put8DigitsUTF16 (str, index, m); + } + return index + 8; + } + + private static void put8DigitsLatin1(byte[] str, int index, int m) { + int y = y(m); + for (int i = 0; i < 8; ++i) { + int t = 10 * y; + str[index + i] = (byte) ('0' + (t >>> 28)); + y = t & MASK_28; + } + } + + private static void put8DigitsUTF16(byte[] str, int index, int m) { + int y = y(m); + for (int i = 0; i < 8; ++i) { + int t = 10 * y; + JLA.putCharUTF16(str, index + i, '0' + (t >>> 28)); + y = t & MASK_28; + } + } + + static int y(int a) { + /* + * Algorithm 1 in [3] needs computation of + * floor((a + 1) 2^n / b^k) - 1 + * with a < 10^8, b = 10, k = 8, n = 28. + * Noting that + * (a + 1) 2^n <= 10^8 2^28 < 10^17 + * For n = 17, m = 8 the table in section 10 of [1] leads to: + */ + return (int) (multiplyHigh( + (long) (a + 1) << 28, + 193_428_131_138_340_668L) >>> 20) - 1; + } + + final int removeTrailingZeroes(byte[] str, int index) { + if (latin1) { + while (str[index - 1] == '0') { + --index; + } + /* ... but do not remove the one directly to the right of '.' */ + if (str[index - 1] == '.') { + ++index; + } + } else { + while (JLA.getUTF16Char(str, index - 1) == '0') { + --index; + } + /* ... but do not remove the one directly to the right of '.' */ + if (JLA.getUTF16Char(str, index - 1) == '.') { + ++index; + } + } + return index; + } + + @SuppressWarnings("deprecation") + final int putSpecial(byte[] str, int index, int type) { + String s = special(type); + int length = s.length(); + if (latin1) { + s.getBytes(0, length, str, index); + } else { + for (int i = 0; i < length; ++i) { + putChar(str, index + i, s.charAt(i)); + } + } + return index + length; + } + + final int length(byte[] str) { + return str.length >> (latin1 ? 0 : 1); + } + + static String special(int type) { + return switch (type) { + case PLUS_ZERO -> "0.0"; + case MINUS_ZERO -> "-0.0"; + case PLUS_INF -> "Infinity"; + case MINUS_INF -> "-Infinity"; + default -> "NaN"; + }; + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index 29827b7f03a2f..e7579d72ecb84 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -241,17 +241,66 @@ public String toStringCharWithBool8() { @Benchmark - public String toStringCharWithFloat8() { - StringBuilder result = new StringBuilder(); - result.append(113.110F); - result.append(156456.36435637F); - result.append(65436434.64632F); - result.append(42654634.64540F); - result.append(63464351.64537F); - result.append(634564.645711F); - result.append(64547.64311F); - result.append(4763456341.64531F); - return result.toString(); + public int appendWithFloat8Latin1() { + StringBuilder buf = sbLatin1; + buf.setLength(0); + buf.append(113.110F); + buf.append(156456.36435637F); + buf.append(65436434.64632F); + buf.append(42654634.64540F); + buf.append(63464351.64537F); + buf.append(634564.645711F); + buf.append(64547.64311F); + buf.append(4763456341.64531F); + return buf.length(); + } + + + @Benchmark + public int appendWithFloat8Utf16() { + StringBuilder buf = sbUtf16; + buf.setLength(0); + buf.append(113.110F); + buf.append(156456.36435637F); + buf.append(65436434.64632F); + buf.append(42654634.64540F); + buf.append(63464351.64537F); + buf.append(634564.645711F); + buf.append(64547.64311F); + buf.append(4763456341.64531F); + return buf.length(); + } + + + @Benchmark + public int appendWithDouble8Latin1() { + StringBuilder buf = sbLatin1; + buf.setLength(0); + buf.append(0.3005216476500575D); + buf.append(0.39727691577802204D); + buf.append(0.9869700323149287D); + buf.append(42654634.645403256D); + buf.append(63464351.645371353D); + buf.append(634564.645711246D); + buf.append(64547.6431172363D); + buf.append(4763456341.64531675D); + return buf.length(); + } + + + @Benchmark + public int appendWithDouble8Utf16() { + StringBuilder buf = sbUtf16; + buf.setLength(0); + buf.append(0.3005216476500575D); + buf.append(0.39727691577802204D); + buf.append(0.9869700323149287D); + buf.append(42654634.645403256D); + buf.append(63464351.645371353D); + buf.append(634564.645711246D); + buf.append(64547.6431172363D); + buf.append(4763456341.64531675D); + return buf.length(); } @Benchmark From 0fc5b2711fbdde972c40bfef2977dd9d70e09581 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 27 Jun 2024 06:22:17 +0000 Subject: [PATCH 070/288] 8332014: since-checker - Fix @ since tags in jdk.jshell Reviewed-by: jlahoda --- src/jdk.jshell/share/classes/jdk/jshell/Snippet.java | 2 +- .../share/classes/jdk/jshell/SourceCodeAnalysis.java | 4 +++- .../share/classes/jdk/jshell/tool/JavaShellToolBuilder.java | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java b/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java index a86ea2a863d43..b0f20a84ec67a 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java @@ -249,8 +249,8 @@ public enum SubKind { * A record declaration. * A {@code SubKind} of {@link Kind#TYPE_DECL}. * @jls 8.10 Record Types - * @since 14 * + * @since 17 */ RECORD_SUBKIND(Kind.TYPE_DECL), diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java index 7a78c04f5a860..99bfd870f37c3 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -158,6 +158,8 @@ public abstract class SourceCodeAnalysis { * @param input The input String to convert * @return usually a singleton list of Snippet, but may be empty or multiple * @throws IllegalStateException if the {@code JShell} instance is closed. + * + * @since 10 */ public abstract List sourceToSnippets(String input); diff --git a/src/jdk.jshell/share/classes/jdk/jshell/tool/JavaShellToolBuilder.java b/src/jdk.jshell/share/classes/jdk/jshell/tool/JavaShellToolBuilder.java index 06dd4d8ce1c62..e28a6cefb6afd 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/tool/JavaShellToolBuilder.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/tool/JavaShellToolBuilder.java @@ -250,6 +250,8 @@ default JavaShellToolBuilder windowSize(int columns, int rows) { * @throws Exception an unexpected fatal exception * @return the exit status with which the tool explicitly exited (if any), * otherwise 0 for success or 1 for failure + * + * @since 10 */ default int start(String... arguments) throws Exception { run(arguments); From 46b817b7499e74ba8812d38bcce93147ebf93b25 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 27 Jun 2024 06:53:03 +0000 Subject: [PATCH 071/288] 8333363: ubsan: instanceKlass.cpp: runtime error: member call on null pointer of type 'struct AnnotationArray' Reviewed-by: coleenp, stefank --- src/hotspot/share/oops/instanceKlass.cpp | 35 +++++++----------------- src/hotspot/share/oops/metadata.hpp | 9 ++++++ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 328c2edbb9fb5..aa8f47f62df2f 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3539,9 +3539,7 @@ void InstanceKlass::print_on(outputStream* st) const { } } } - if (default_vtable_indices() != nullptr) { - st->print(BULLET"default vtable indices: "); default_vtable_indices()->print_value_on(st); st->cr(); - } + print_on_maybe_null(st, BULLET"default vtable indices: ", default_vtable_indices()); st->print(BULLET"local interfaces: "); local_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr(); @@ -3568,25 +3566,18 @@ void InstanceKlass::print_on(outputStream* st) const { } } st->print(BULLET"constants: "); constants()->print_value_on(st); st->cr(); - if (class_loader_data() != nullptr) { - st->print(BULLET"class loader data: "); - class_loader_data()->print_value_on(st); - st->cr(); - } - if (source_file_name() != nullptr) { - st->print(BULLET"source file: "); - source_file_name()->print_value_on(st); - st->cr(); - } + + print_on_maybe_null(st, BULLET"class loader data: ", class_loader_data()); + print_on_maybe_null(st, BULLET"source file: ", source_file_name()); if (source_debug_extension() != nullptr) { st->print(BULLET"source debug extension: "); st->print("%s", source_debug_extension()); st->cr(); } - st->print(BULLET"class annotations: "); class_annotations()->print_value_on(st); st->cr(); - st->print(BULLET"class type annotations: "); class_type_annotations()->print_value_on(st); st->cr(); - st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr(); - st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); + print_on_maybe_null(st, BULLET"class annotations: ", class_annotations()); + print_on_maybe_null(st, BULLET"class type annotations: ", class_type_annotations()); + print_on_maybe_null(st, BULLET"field annotations: ", fields_annotations()); + print_on_maybe_null(st, BULLET"field type annotations: ", fields_type_annotations()); { bool have_pv = false; // previous versions are linked together through the InstanceKlass @@ -3601,16 +3592,10 @@ void InstanceKlass::print_on(outputStream* st) const { if (have_pv) st->cr(); } - if (generic_signature() != nullptr) { - st->print(BULLET"generic signature: "); - generic_signature()->print_value_on(st); - st->cr(); - } + print_on_maybe_null(st, BULLET"generic signature: ", generic_signature()); st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr(); st->print(BULLET"nest members: "); nest_members()->print_value_on(st); st->cr(); - if (record_components() != nullptr) { - st->print(BULLET"record components: "); record_components()->print_value_on(st); st->cr(); - } + print_on_maybe_null(st, BULLET"record components: ", record_components()); st->print(BULLET"permitted subclasses: "); permitted_subclasses()->print_value_on(st); st->cr(); if (java_mirror() != nullptr) { st->print(BULLET"java mirror: "); diff --git a/src/hotspot/share/oops/metadata.hpp b/src/hotspot/share/oops/metadata.hpp index c118ade8586e1..f5aee34c80da7 100644 --- a/src/hotspot/share/oops/metadata.hpp +++ b/src/hotspot/share/oops/metadata.hpp @@ -76,4 +76,13 @@ class Metadata : public MetaspaceObj { static void mark_on_stack(Metadata* m) { m->set_on_stack(true); } }; +template +static void print_on_maybe_null(outputStream* st, const char* str, const M* m) { + if (nullptr != m) { + st->print_raw(str); + m->print_value_on(st); + st->cr(); + } +} + #endif // SHARE_OOPS_METADATA_HPP From f3b69da55a1ec4857fff1537a80ab1fefee93dac Mon Sep 17 00:00:00 2001 From: Evemose <124714317+Evemose@users.noreply.github.com> Date: Thu, 27 Jun 2024 07:45:18 +0000 Subject: [PATCH 072/288] 8335136: Underscore as parameter name in one-parameter functional types fails to compile Reviewed-by: jlahoda --- .../sun/tools/javac/parser/JavacParser.java | 2 +- .../ExpressionSwitchUnderscoreAfterYield.java | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index ce484e14b0553..ef2d71831dc59 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -2920,7 +2920,7 @@ List blockStatement() { case PLUS: case SUB: case STRINGLITERAL: case CHARLITERAL: case STRINGFRAGMENT: case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL: - case NULL: case IDENTIFIER: case TRUE: case FALSE: + case NULL: case IDENTIFIER: case UNDERSCORE: case TRUE: case FALSE: case NEW: case SWITCH: case THIS: case SUPER: case BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, VOID, BOOLEAN: isYieldStatement = true; diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java new file mode 100644 index 0000000000000..14f609cc71e1b --- /dev/null +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnderscoreAfterYield.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8335136 + * @summary Underscore as parameter name in one-parameter functional types fails to compile in yield statement if not enclosed in parentheses + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.JavacTask toolbox.ToolBox toolbox.Task + * @run main ExpressionSwitchUnderscoreAfterYield + */ + +import toolbox.*; + +import java.nio.file.Path; +import java.util.List; + +public class ExpressionSwitchUnderscoreAfterYield extends TestRunner { + + private final ToolBox tb = new ToolBox(); + + private final Path ROOT = Path.of("."); + + public ExpressionSwitchUnderscoreAfterYield() { + super(System.err); + } + + public static void main(String[] args) throws Exception { + new ExpressionSwitchUnderscoreAfterYield().runTests(); + } + + protected void runTests() throws Exception { + runTests(f -> { + if (f.getName().endsWith("_ShouldFailToCompile")) { + return new Object[]{ + List.of( + FailParams.UNDERSCORE_YIELDED, + FailParams.ASSIGNMENT_TO_UNDERSCORE_IN_YIELD + ) + }; + } + return new Object[0]; + }); + } + + @Test + public void testUnderscoreAsParameterNameInLambda_ShouldCompileFine() throws Exception { + var code = """ + import java.util.function.*; + \s + public class Test { + public static void main(String[] args) { + Consumer result = switch (1) { + case 1 -> { + yield _ -> {}; + } + default -> null; + }; + } + } + """; + tb.writeJavaFiles(ROOT, code); + new toolbox.JavacTask(tb) + .files(tb.findJavaFiles(ROOT)) + .run(Task.Expect.SUCCESS); + } + + public record FailParams(String code, List expectedDiagnosticMessage) { + public static FailParams UNDERSCORE_YIELDED = new FailParams( + """ + public class Test { + public static void main(String[] args) { + Object result = switch (1) { + case 1 -> { + yield _; + } + default -> null; + }; + } + } + """, + List.of("Test.java:5:23: compiler.err.use.of.underscore.not.allowed.non.variable", "1 error") + ); + + public static FailParams ASSIGNMENT_TO_UNDERSCORE_IN_YIELD = new FailParams( + """ + public class Test { + public static void main(String[] args) { + Object result = switch (1) { + case 1 -> { + yield _ = 1; + } + default -> null; + }; + } + } + """, + List.of("Test.java:5:23: compiler.err.use.of.underscore.not.allowed.non.variable", "1 error") + ); + } + + @Test + public void testUnderscoreAsParameterNameInLambda_ShouldFailToCompile(List params) throws Exception { + for (var param : params) { + tb.writeJavaFiles(ROOT, param.code); + Task.Result result = new JavacTask(tb) + .options("-XDrawDiagnostics") + .files(tb.findJavaFiles(ROOT)) + .run(Task.Expect.FAIL); + tb.checkEqual(param.expectedDiagnosticMessage, result.getOutputLines(Task.OutputKind.DIRECT)); + } + } + +} From 37e7698c29b8673b904945d397f0698ccd16d27b Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 27 Jun 2024 07:54:35 +0000 Subject: [PATCH 073/288] 8335154: jcmd VM.classes -verbose=false does not set verbose to false Reviewed-by: dholmes, stuefe --- src/hotspot/share/services/diagnosticCommand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index faabe74a2ff0b..4b8eae8a4138e 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -992,7 +992,7 @@ class VM_PrintClasses : public VM_Operation { }; void ClassesDCmd::execute(DCmdSource source, TRAPS) { - VM_PrintClasses vmop(output(), _verbose.is_set()); + VM_PrintClasses vmop(output(), _verbose.value()); VMThread::execute(&vmop); } From 79a23017fc7154738c375fbb12a997525c3bf9e7 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 27 Jun 2024 10:23:55 +0000 Subject: [PATCH 074/288] 8322859: Parallel: Move transform_stack_chunk Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index f01d1a852997c..390dea4976d19 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -249,10 +249,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, // Copy obj Copy::aligned_disjoint_words(cast_from_oop(o), cast_from_oop(new_obj), new_obj_size); - // Parallel GC claims with a release - so other threads might access this object - // after claiming and they should see the "completed" object. - ContinuationGCSupport::transform_stack_chunk(new_obj); - // Now we have to CAS in the header. // Because the forwarding is done with memory_order_relaxed there is no // ordering with the above copy. Clients that get the forwardee must not @@ -271,6 +267,8 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, assert(young_space()->contains(new_obj), "Attempt to push non-promoted obj"); } + ContinuationGCSupport::transform_stack_chunk(new_obj); + // Do the size comparison first with new_obj_size, which we // already have. Hopefully, only a few objects are larger than // _min_array_size_for_chunking, and most of them will be arrays. From 50dd962b0d0fe36634d96dbbd9d94fbc34d9ff7f Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 27 Jun 2024 12:56:26 +0000 Subject: [PATCH 075/288] 8335007: Inline OopMapCache table Reviewed-by: stefank, coleenp, shade --- src/hotspot/share/interpreter/oopMapCache.cpp | 20 ++++++++----------- src/hotspot/share/interpreter/oopMapCache.hpp | 9 ++++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 7b60e4869e368..a10f8c439eaa4 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -445,29 +445,25 @@ inline unsigned int OopMapCache::hash_value_for(const methodHandle& method, int OopMapCacheEntry* volatile OopMapCache::_old_entries = nullptr; OopMapCache::OopMapCache() { - _array = NEW_C_HEAP_ARRAY(OopMapCacheEntry*, _size, mtClass); - for(int i = 0; i < _size; i++) _array[i] = nullptr; + for(int i = 0; i < size; i++) _array[i] = nullptr; } OopMapCache::~OopMapCache() { - assert(_array != nullptr, "sanity check"); // Deallocate oop maps that are allocated out-of-line flush(); - // Deallocate array - FREE_C_HEAP_ARRAY(OopMapCacheEntry*, _array); } OopMapCacheEntry* OopMapCache::entry_at(int i) const { - return Atomic::load_acquire(&(_array[i % _size])); + return Atomic::load_acquire(&(_array[i % size])); } bool OopMapCache::put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old) { - return Atomic::cmpxchg(&_array[i % _size], old, entry) == old; + return Atomic::cmpxchg(&_array[i % size], old, entry) == old; } void OopMapCache::flush() { - for (int i = 0; i < _size; i++) { + for (int i = 0; i < size; i++) { OopMapCacheEntry* entry = _array[i]; if (entry != nullptr) { _array[i] = nullptr; // no barrier, only called in OopMapCache destructor @@ -478,7 +474,7 @@ void OopMapCache::flush() { void OopMapCache::flush_obsolete_entries() { assert(SafepointSynchronize::is_at_safepoint(), "called by RedefineClasses in a safepoint"); - for (int i = 0; i < _size; i++) { + for (int i = 0; i < size; i++) { OopMapCacheEntry* entry = _array[i]; if (entry != nullptr && !entry->is_empty() && entry->method()->is_old()) { // Cache entry is occupied by an old redefined method and we don't want @@ -513,7 +509,7 @@ void OopMapCache::lookup(const methodHandle& method, // Need a critical section to avoid race against concurrent reclamation. { GlobalCounter::CriticalSection cs(Thread::current()); - for (int i = 0; i < _probe_depth; i++) { + for (int i = 0; i < probe_depth; i++) { OopMapCacheEntry *entry = entry_at(probe + i); if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { entry_for->resource_copy(entry); @@ -542,7 +538,7 @@ void OopMapCache::lookup(const methodHandle& method, } // First search for an empty slot - for (int i = 0; i < _probe_depth; i++) { + for (int i = 0; i < probe_depth; i++) { OopMapCacheEntry* entry = entry_at(probe + i); if (entry == nullptr) { if (put_at(probe + i, tmp, nullptr)) { diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 46c85f6e87985..a3f5c395f589a 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,11 +152,10 @@ class InterpreterOopMap: ResourceObj { class OopMapCache : public CHeapObj { static OopMapCacheEntry* volatile _old_entries; private: - enum { _size = 32, // Use fixed size for now - _probe_depth = 3 // probe depth in case of collisions - }; + static constexpr int size = 32; // Use fixed size for now + static constexpr int probe_depth = 3; // probe depth in case of collisions - OopMapCacheEntry* volatile * _array; + OopMapCacheEntry* volatile _array[size]; unsigned int hash_value_for(const methodHandle& method, int bci) const; OopMapCacheEntry* entry_at(int i) const; From 6b961acb87c29027f2158c6b7a764f1276a0bf52 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 27 Jun 2024 13:03:21 +0000 Subject: [PATCH 076/288] 8333786: Serial: Remove SerialHeap::_incremental_collection_failed Reviewed-by: tschatzl, iwalulya --- .../share/gc/serial/defNewGeneration.cpp | 86 +------------------ .../share/gc/serial/defNewGeneration.hpp | 1 - src/hotspot/share/gc/serial/serialHeap.cpp | 4 +- src/hotspot/share/gc/serial/serialHeap.hpp | 29 ------- 4 files changed, 2 insertions(+), 118 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index be104dce571b9..b66681170c63c 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -578,33 +578,6 @@ HeapWord* DefNewGeneration::block_start(const void* p) const { return block_start_const(to(), p); } -// The last collection bailed out, we are running out of heap space, -// so we try to allocate the from-space, too. -HeapWord* DefNewGeneration::allocate_from_space(size_t size) { - bool should_try_alloc = should_allocate_from_space() || GCLocker::is_active_and_needs_gc(); - - // If the Heap_lock is not locked by this thread, this will be called - // again later with the Heap_lock held. - bool do_alloc = should_try_alloc && (Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread())); - - HeapWord* result = nullptr; - if (do_alloc) { - result = from()->allocate(size); - } - - log_trace(gc, alloc)("DefNewGeneration::allocate_from_space(" SIZE_FORMAT "): will_fail: %s heap_lock: %s free: " SIZE_FORMAT "%s%s returns %s", - size, - SerialHeap::heap()->incremental_collection_will_fail(false /* don't consult_young */) ? - "true" : "false", - Heap_lock->is_locked() ? "locked" : "unlocked", - from()->free(), - should_try_alloc ? "" : " should_allocate_from_space: NOT", - do_alloc ? " Heap_lock is not owned by self" : "", - result == nullptr ? "null" : "object"); - - return result; -} - HeapWord* DefNewGeneration::expand_and_allocate(size_t size, bool is_tlab) { // We don't attempt to expand the young generation (but perhaps we should.) return allocate(size, is_tlab); @@ -707,21 +680,12 @@ bool DefNewGeneration::collect(bool clear_all_soft_refs) { assert(to()->is_empty(), "to space should be empty now"); adjust_desired_tenuring_threshold(); - - assert(!heap->incremental_collection_failed(), "Should be clear"); } else { assert(_promo_failure_scan_stack.is_empty(), "post condition"); _promo_failure_scan_stack.clear(true); // Clear cached segments. remove_forwarding_pointers(); log_info(gc, promotion)("Promotion failed"); - // Add to-space to the list of space to compact - // when a promotion failure has occurred. In that - // case there can be live objects in to-space - // as a result of a partial evacuation of eden - // and from-space. - swap_spaces(); // For uniformity wrt ParNewGeneration. - heap->set_incremental_collection_failed(); _gc_tracer->report_promotion_failed(_promotion_failed_info); @@ -883,51 +847,10 @@ bool DefNewGeneration::collection_attempt_is_safe() { } void DefNewGeneration::gc_epilogue(bool full) { - DEBUG_ONLY(static bool seen_incremental_collection_failed = false;) - assert(!GCLocker::is_active(), "We should not be executing here"); - // Check if the heap is approaching full after a collection has - // been done. Generally the young generation is empty at - // a minimum at the end of a collection. If it is not, then - // the heap is approaching full. - SerialHeap* gch = SerialHeap::heap(); - if (full) { - DEBUG_ONLY(seen_incremental_collection_failed = false;) - if (!collection_attempt_is_safe() && !_eden_space->is_empty()) { - log_trace(gc)("DefNewEpilogue: cause(%s), full, not safe, set_failed, set_alloc_from, clear_seen", - GCCause::to_string(gch->gc_cause())); - gch->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state - set_should_allocate_from_space(); // we seem to be running out of space - } else { - log_trace(gc)("DefNewEpilogue: cause(%s), full, safe, clear_failed, clear_alloc_from, clear_seen", - GCCause::to_string(gch->gc_cause())); - gch->clear_incremental_collection_failed(); // We just did a full collection - clear_should_allocate_from_space(); // if set - } - } else { -#ifdef ASSERT - // It is possible that incremental_collection_failed() == true - // here, because an attempted scavenge did not succeed. The policy - // is normally expected to cause a full collection which should - // clear that condition, so we should not be here twice in a row - // with incremental_collection_failed() == true without having done - // a full collection in between. - if (!seen_incremental_collection_failed && - gch->incremental_collection_failed()) { - log_trace(gc)("DefNewEpilogue: cause(%s), not full, not_seen_failed, failed, set_seen_failed", - GCCause::to_string(gch->gc_cause())); - seen_incremental_collection_failed = true; - } else if (seen_incremental_collection_failed) { - log_trace(gc)("DefNewEpilogue: cause(%s), not full, seen_failed, will_clear_seen_failed", - GCCause::to_string(gch->gc_cause())); - seen_incremental_collection_failed = false; - } -#endif // ASSERT - } - // update the generation and space performance counters update_counters(); - gch->counters()->update_counters(); + SerialHeap::heap()->counters()->update_counters(); } void DefNewGeneration::update_counters() { @@ -967,13 +890,6 @@ HeapWord* DefNewGeneration::allocate(size_t word_size, bool is_tlab) { // Note that since DefNewGeneration supports lock-free allocation, we // have to use it here, as well. HeapWord* result = eden()->par_allocate(word_size); - if (result == nullptr) { - // If the eden is full and the last collection bailed out, we are running - // out of heap space, and we try to allocate the from-space, too. - // allocate_from_space can't be inlined because that would introduce a - // circular dependency at compile time. - result = allocate_from_space(word_size); - } return result; } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index baf565e28629b..0cf2545421f72 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -225,7 +225,6 @@ class DefNewGeneration: public Generation { } HeapWord* allocate(size_t word_size, bool is_tlab); - HeapWord* allocate_from_space(size_t word_size); HeapWord* par_allocate(size_t word_size, bool is_tlab); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 8dd8a9c0e6766..c1fdc1eba1a32 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -92,7 +92,6 @@ SerialHeap::SerialHeap() : _old_gen(nullptr), _rem_set(nullptr), _gc_policy_counters(new GCPolicyCounters("Copy:MSC", 2, 2)), - _incremental_collection_failed(false), _young_manager(nullptr), _old_manager(nullptr), _eden_pool(nullptr), @@ -287,8 +286,7 @@ size_t SerialHeap::max_capacity() const { bool SerialHeap::should_try_older_generation_allocation(size_t word_size) const { size_t young_capacity = _young_gen->capacity_before_gc(); return (word_size > heap_word_size(young_capacity)) - || GCLocker::is_active_and_needs_gc() - || incremental_collection_failed(); + || GCLocker::is_active_and_needs_gc(); } HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 0817c6e9eb37d..14e0d737c1a4e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -91,11 +91,6 @@ class SerialHeap : public CollectedHeap { GCPolicyCounters* _gc_policy_counters; - // Indicates that the most recent previous incremental collection failed. - // The flag is cleared when an action is taken that might clear the - // condition that caused that incremental collection to fail. - bool _incremental_collection_failed; - bool do_young_collection(bool clear_soft_refs); // Reserve aligned space for the heap as needed by the contained generations. @@ -255,29 +250,6 @@ class SerialHeap : public CollectedHeap { // in other generations, it should call this method. void save_marks(); - // Returns true if an incremental collection is likely to fail. - // We optionally consult the young gen, if asked to do so; - // otherwise we base our answer on whether the previous incremental - // collection attempt failed with no corrective action as of yet. - bool incremental_collection_will_fail(bool consult_young) { - // The first disjunct remembers if an incremental collection failed, even - // when we thought (second disjunct) that it would not. - return incremental_collection_failed() || - (consult_young && !_young_gen->collection_attempt_is_safe()); - } - - // If a generation bails out of an incremental collection, - // it sets this flag. - bool incremental_collection_failed() const { - return _incremental_collection_failed; - } - void set_incremental_collection_failed() { - _incremental_collection_failed = true; - } - void clear_incremental_collection_failed() { - _incremental_collection_failed = false; - } - private: // Return true if an allocation should be attempted in the older generation // if it fails in the younger generation. Return false, otherwise. @@ -289,7 +261,6 @@ class SerialHeap : public CollectedHeap { HeapWord* mem_allocate_work(size_t size, bool is_tlab); -private: MemoryPool* _eden_pool; MemoryPool* _survivor_pool; MemoryPool* _old_pool; From d5375c7db658de491c1f5bad053040d21b82941e Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Thu, 27 Jun 2024 13:22:04 +0000 Subject: [PATCH 077/288] 8333308: javap --system handling doesn't work on internal class names Reviewed-by: liach, stuefe --- src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java index d8fa59c2dd0e7..b797ef73522c2 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java @@ -867,7 +867,7 @@ private JavaFileObject getClassFileObject(String className) throws IOException { if (moduleLocation != null) { fo = fileManager.getJavaFileForInput(moduleLocation, className, JavaFileObject.Kind.CLASS); } else { - if (className.indexOf('.') > 0) { + if (className.indexOf('.') > 0 || className.indexOf('/') > 0) { //search for classes with a named package in the JDK modules specifed by --system option first try { for (Set locations: fileManager.listLocationsForModules(StandardLocation.SYSTEM_MODULES)) { From 5909d54147355dd7da5786ff39ead4c15816705c Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 27 Jun 2024 14:21:34 +0000 Subject: [PATCH 078/288] 8326820: Metadata artificially kept alive Reviewed-by: eosterlund, stefank, coleenp --- .../share/classfile/classLoaderDataGraph.cpp | 83 ++++++++++--------- .../share/classfile/classLoaderDataGraph.hpp | 13 ++- .../share/classfile/classLoaderStats.cpp | 2 +- .../share/classfile/systemDictionary.hpp | 2 +- src/hotspot/share/prims/jvmtiEnvBase.cpp | 2 +- .../share/prims/jvmtiGetLoadedClasses.cpp | 2 +- 6 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index 2046286651eae..adec6dbdeeeaa 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -241,9 +241,14 @@ LockedClassesDo::~LockedClassesDo() { // Iterating over the CLDG needs to be locked because -// unloading can remove entries concurrently soon. -template -class ClassLoaderDataGraphIteratorBase : public StackObj { +// unloading can remove entries concurrently. +// This iterator does not keep the CLD alive. +// Any CLD OopHandles (modules, mirrors, resolved refs) +// resolved must be treated as no keepalive. And requires +// that its CLD's holder is kept alive if they escape the +// caller's safepoint or ClassLoaderDataGraph_lock +// critical section. +class ClassLoaderDataGraph::ClassLoaderDataGraphIterator : public StackObj { ClassLoaderData* _next; Thread* _thread; HandleMark _hm; // clean up handles when this is done. @@ -251,12 +256,8 @@ class ClassLoaderDataGraphIteratorBase : public StackObj { // unless verifying at a safepoint. public: - ClassLoaderDataGraphIteratorBase() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) { - if (keep_alive) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - } else { - assert_at_safepoint(); - } + ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); } ClassLoaderData* get_next() { @@ -266,10 +267,6 @@ class ClassLoaderDataGraphIteratorBase : public StackObj { cld = cld->next(); } if (cld != nullptr) { - if (keep_alive) { - // Keep cld that is being returned alive. - Handle(_thread, cld->holder()); - } _next = cld->next(); } else { _next = nullptr; @@ -278,9 +275,6 @@ class ClassLoaderDataGraphIteratorBase : public StackObj { } }; -using ClassLoaderDataGraphIterator = ClassLoaderDataGraphIteratorBase; -using ClassLoaderDataGraphIteratorNoKeepAlive = ClassLoaderDataGraphIteratorBase; - void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) { ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { @@ -288,13 +282,6 @@ void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) { } } -void ClassLoaderDataGraph::loaded_cld_do_no_keepalive(CLDClosure* cl) { - ClassLoaderDataGraphIteratorNoKeepAlive iter; - while (ClassLoaderData* cld = iter.get_next()) { - cl->do_cld(cld); - } -} - // These functions assume that the caller has locked the ClassLoaderDataGraph_lock // if they are not calling the function from a safepoint. void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) { @@ -318,6 +305,16 @@ void ClassLoaderDataGraph::methods_do(void f(Method*)) { } } +void ClassLoaderDataGraph::modules_do_keepalive(void f(ModuleEntry*)) { + assert_locked_or_safepoint(Module_lock); + ClassLoaderDataGraphIterator iter; + while (ClassLoaderData* cld = iter.get_next()) { + // Keep the holder alive. + (void)cld->holder(); + cld->modules_do(f); + } +} + void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) { assert_locked_or_safepoint(Module_lock); ClassLoaderDataGraphIterator iter; @@ -334,9 +331,11 @@ void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { } } -void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { +void ClassLoaderDataGraph::loaded_classes_do_keepalive(KlassClosure* klass_closure) { ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { + // Keep the holder alive. + (void)cld->holder(); cld->loaded_classes_do(klass_closure); } } @@ -346,7 +345,7 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { } void ClassLoaderDataGraph::verify_dictionary() { - ClassLoaderDataGraphIteratorNoKeepAlive iter; + ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { if (cld->dictionary() != nullptr) { cld->dictionary()->verify(); @@ -354,26 +353,28 @@ void ClassLoaderDataGraph::verify_dictionary() { } } -#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \ - while (ClassLoaderData* X = iter.get_next()) \ - if (X->dictionary() != nullptr) - void ClassLoaderDataGraph::print_dictionary(outputStream* st) { - FOR_ALL_DICTIONARY(cld) { - st->print("Dictionary for "); - cld->print_value_on(st); - st->cr(); - cld->dictionary()->print_on(st); - st->cr(); + ClassLoaderDataGraphIterator iter; + while (ClassLoaderData *cld = iter.get_next()) { + if (cld->dictionary() != nullptr) { + st->print("Dictionary for "); + cld->print_value_on(st); + st->cr(); + cld->dictionary()->print_on(st); + st->cr(); + } } } void ClassLoaderDataGraph::print_table_statistics(outputStream* st) { - FOR_ALL_DICTIONARY(cld) { - ResourceMark rm; // loader_name_and_id - stringStream tempst; - tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); - cld->dictionary()->print_table_statistics(st, tempst.freeze()); + ClassLoaderDataGraphIterator iter; + while (ClassLoaderData *cld = iter.get_next()) { + if (cld->dictionary() != nullptr) { + ResourceMark rm; // loader_name_and_id + stringStream tempst; + tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); + cld->dictionary()->print_table_statistics(st, tempst.freeze()); + } } } @@ -550,7 +551,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { } void ClassLoaderDataGraph::verify() { - ClassLoaderDataGraphIteratorNoKeepAlive iter; + ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { cld->verify(); } diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp index 3de2c10850e1a..a79c6e21089e5 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp @@ -37,10 +37,10 @@ class ClassLoaderDataGraph : public AllStatic { friend class ClassLoaderDataGraphMetaspaceIterator; friend class ClassLoaderDataGraphKlassIteratorAtomic; friend class ClassLoaderDataGraphKlassIteratorStatic; - template - friend class ClassLoaderDataGraphIteratorBase; friend class VMStructs; private: + class ClassLoaderDataGraphIterator; + // All CLDs (except unlinked CLDs) can be reached by walking _head->_next->... static ClassLoaderData* volatile _head; @@ -71,8 +71,12 @@ class ClassLoaderDataGraph : public AllStatic { static void roots_cld_do(CLDClosure* strong, CLDClosure* weak); static void always_strong_cld_do(CLDClosure* cl); // Iteration through CLDG not by GC. + // All the do suffixed functions do not keep the CLD alive. Any CLD OopHandles + // (modules, mirrors, resolved refs) resolved must be treated as no keepalive. + // And requires that its CLD's holder is kept alive if they escape the + // caller's safepoint or ClassLoaderDataGraph_lock critical section. + // The do_keepalive suffixed functions will keep all CLDs alive. static void loaded_cld_do(CLDClosure* cl); - static void loaded_cld_do_no_keepalive(CLDClosure* cl); // klass do // Walking classes through the ClassLoaderDataGraph include array classes. It also includes // classes that are allocated but not loaded, classes that have errors, and scratch classes @@ -81,9 +85,10 @@ class ClassLoaderDataGraph : public AllStatic { static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); static void methods_do(void f(Method*)); + static void modules_do_keepalive(void f(ModuleEntry*)); static void modules_do(void f(ModuleEntry*)); static void packages_do(void f(PackageEntry*)); - static void loaded_classes_do(KlassClosure* klass_closure); + static void loaded_classes_do_keepalive(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(); diff --git a/src/hotspot/share/classfile/classLoaderStats.cpp b/src/hotspot/share/classfile/classLoaderStats.cpp index f09d99681375c..6bb49c3a85377 100644 --- a/src/hotspot/share/classfile/classLoaderStats.cpp +++ b/src/hotspot/share/classfile/classLoaderStats.cpp @@ -165,7 +165,7 @@ void ClassLoaderStatsClosure::addEmptyParents(oop cl) { void ClassLoaderStatsVMOperation::doit() { ClassLoaderStatsClosure clsc (_out); - ClassLoaderDataGraph::loaded_cld_do_no_keepalive(&clsc); + ClassLoaderDataGraph::loaded_cld_do(&clsc); clsc.print(); } diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 9f65cb593d39a..6355de9c4ceb5 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -177,7 +177,7 @@ class SystemDictionary : AllStatic { static void classes_do(MetaspaceClosure* it); // Iterate over all methods in all klasses - + // Will not keep metadata alive. See ClassLoaderDataGraph::methods_do. static void methods_do(void f(Method*)); // Garbage collection support diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index dc02e8e5cf0ee..1a6aec4e438f6 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -2339,7 +2339,7 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje } // Iterate over all the modules loaded to the system. - ClassLoaderDataGraph::modules_do(&do_module); + ClassLoaderDataGraph::modules_do_keepalive(&do_module); jint len = _tbl->length(); guarantee(len > 0, "at least one module must be present"); diff --git a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp index 8d6a0736afeb9..c2e970bae7310 100644 --- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp +++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp @@ -105,7 +105,7 @@ JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jcla // Iterate through all classes in ClassLoaderDataGraph // and collect them using the LoadedClassesClosure MutexLocker mcld(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::loaded_classes_do(&closure); + ClassLoaderDataGraph::loaded_classes_do_keepalive(&closure); } return closure.get_result(env, classCountPtr, classesPtr); From 4ab7e98c79a1a0b7aba1ca74a8316820c906e70e Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Thu, 27 Jun 2024 15:07:00 +0000 Subject: [PATCH 079/288] 8330842: Support AES CBC with Ciphertext Stealing (CTS) in SunPKCS11 Co-authored-by: Francisco Ferrari Bihurriet Co-authored-by: Martin Balao Reviewed-by: valeriep --- .../classes/sun/security/pkcs11/Config.java | 22 ++ .../sun/security/pkcs11/P11Cipher.java | 318 +++++++++++++++--- .../sun/security/pkcs11/SunPKCS11.java | 17 +- .../classes/sun/security/pkcs11/Token.java | 19 +- .../TestCipherTextStealingMultipart.java | 255 ++++++++++++++ .../pkcs11/Cipher/TestSymmCiphers.java | 41 +-- .../pkcs11/Cipher/TestSymmCiphersNoPad.java | 17 +- 7 files changed, 597 insertions(+), 92 deletions(-) create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java index 20726bb8d4721..18ccda542a002 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java @@ -164,6 +164,11 @@ public List run() { // Secmod.Module.getProvider() method. private String functionList = null; + // CTS mode variant used by the token, as described in Addendum to NIST + // Special Publication 800-38A, "Recommendation for Block Cipher Modes + // of Operation: Three Variants of Ciphertext Stealing for CBC Mode". + private Token.CTSVariant ctsVariant = null; + // whether to use NSS secmod mode. Implicitly set if nssLibraryDirectory, // nssSecmodDirectory, or nssModule is specified. private boolean nssUseSecmod; @@ -321,6 +326,10 @@ String getFunctionList() { return functionList; } + Token.CTSVariant getCTSVariant() { + return ctsVariant; + } + boolean getNssUseSecmod() { return nssUseSecmod; } @@ -472,6 +481,8 @@ private void parse() throws IOException { allowSingleThreadedModules = parseBooleanEntry(st.sval); case "functionList"-> functionList = parseStringEntry(st.sval); + case "cipherTextStealingVariant"-> + ctsVariant = parseEnumEntry(Token.CTSVariant.class, st.sval); case "nssUseSecmod"-> nssUseSecmod = parseBooleanEntry(st.sval); case "nssLibraryDirectory"-> { @@ -627,6 +638,17 @@ private int parseIntegerEntry(String keyword) throws IOException { return value; } + private > E parseEnumEntry(Class enumClass, + String keyword) throws IOException { + String value = parseStringEntry(keyword); + try { + return Enum.valueOf(enumClass, value); + } catch (IllegalArgumentException ignored) { + throw excToken(keyword + " must be one of " + + Arrays.toString(enumClass.getEnumConstants()) + ", read:"); + } + } + private boolean parseBoolean() throws IOException { String val = parseWord(); return switch (val) { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java index c65c2185a3eea..faf1aa9237f26 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * Cipher implementation class. This class currently supports * DES, DESede, AES, ARCFOUR, and Blowfish. * - * This class is designed to support ECB, CBC, CTR with NoPadding + * This class is designed to support ECB, CBC, CTR, CTS with NoPadding * and ECB, CBC with PKCS5Padding. It will use its own padding impl * if the native mechanism does not support padding. * @@ -60,17 +60,9 @@ final class P11Cipher extends CipherSpi { private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); - // mode constant for ECB mode - private static final int MODE_ECB = 3; - // mode constant for CBC mode - private static final int MODE_CBC = 4; - // mode constant for CTR mode - private static final int MODE_CTR = 5; - - // padding constant for NoPadding - private static final int PAD_NONE = 5; - // padding constant for PKCS5Padding - private static final int PAD_PKCS5 = 6; + // mode and padding constants + private enum Mode {ECB /* or stream ciphers */, CBC, CTR, CTS} + private enum Pad {NONE, PKCS5} private static interface Padding { // ENC: format the specified buffer with padding bytes and return the @@ -146,14 +138,14 @@ public int unpad(byte[] paddedData, int len) // flag indicating encrypt or decrypt mode private boolean encrypt; - // mode, one of MODE_* above (MODE_ECB for stream ciphers) - private int blockMode; + // mode, Mode.ECB for stream ciphers + private final Mode blockMode; // block size, 0 for stream ciphers private final int blockSize; - // padding type, on of PAD_* above (PAD_NONE for stream ciphers) - private int paddingType; + // padding type, Pad.NONE for stream ciphers + private Pad paddingType; // when the padding is requested but unsupported by the native mechanism, // we use the following to do padding and necessary data buffering. @@ -163,7 +155,7 @@ public int unpad(byte[] paddedData, int len) private byte[] padBuffer; private int padBufferLen; - // original IV, if in MODE_CBC or MODE_CTR + // original IV, if in Mode.CBC, Mode.CTR or Mode.CTS private byte[] iv; // number of bytes buffered internally by the native mechanism and padBuffer @@ -208,8 +200,7 @@ public int unpad(byte[] paddedData, int len) blockSize = 8; } } - this.blockMode = - (algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB); + blockMode = algoParts.length > 1 ? parseMode(algoParts[1]) : Mode.ECB; String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding"); String paddingStr = (algoParts.length > 2 ? algoParts[2] : defPadding); @@ -227,20 +218,19 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } - private int parseMode(String mode) throws NoSuchAlgorithmException { + private Mode parseMode(String mode) throws NoSuchAlgorithmException { mode = mode.toUpperCase(Locale.ENGLISH); - return switch (mode) { - case "ECB" -> MODE_ECB; - case "CBC" -> { - if (blockSize == 0) { - throw new NoSuchAlgorithmException - ("CBC mode not supported with stream ciphers"); - } - yield MODE_CBC; - } - case "CTR" -> MODE_CTR; - default -> throw new NoSuchAlgorithmException("Unsupported mode " + mode); - }; + Mode result; + try { + result = Mode.valueOf(mode); + } catch (IllegalArgumentException ignored) { + throw new NoSuchAlgorithmException("Unsupported mode " + mode); + } + if (blockSize == 0 && result != Mode.ECB) { + throw new NoSuchAlgorithmException( + result + " mode not supported with stream ciphers"); + } + return result; } // see JCE spec @@ -250,13 +240,22 @@ protected void engineSetPadding(String padding) padBuffer = null; padding = padding.toUpperCase(Locale.ENGLISH); if (padding.equals("NOPADDING")) { - paddingType = PAD_NONE; + paddingType = Pad.NONE; + if (blockMode == Mode.CTS) { + // Buffer at least two blocks (where the last one may be + // partial). When using NSS, buffer one more block to avoid + // NSS Bug 1823875: "AES CTS decryption does not update + // its own context's IV on full blocks input" + // https://bugzilla.mozilla.org/show_bug.cgi?id=1823875#c2 + int bufferedBlocks = P11Util.isNSS(token) ? 3 : 2; + padBuffer = new byte[bufferedBlocks * blockSize]; + } } else if (padding.equals("PKCS5PADDING")) { - if (this.blockMode == MODE_CTR) { - throw new NoSuchPaddingException - ("PKCS#5 padding not supported with CTR mode"); + if (blockMode == Mode.CTR || blockMode == Mode.CTS) { + throw new NoSuchPaddingException("PKCS#5 padding not " + + "supported with " + blockMode + " mode"); } - paddingType = PAD_PKCS5; + paddingType = Pad.PKCS5; if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD && mechanism != CKM_AES_CBC_PAD) { // no native padding support; use our own padding impl @@ -371,7 +370,7 @@ private void implInit(int opmode, Key key, byte[] iv, // should never happen; checked by Cipher.init() throw new AssertionError("Unknown mode: " + opmode); }; - if (blockMode == MODE_ECB) { // ECB or stream cipher + if (blockMode == Mode.ECB) { // ECB or stream cipher if (iv != null) { if (blockSize == 0) { throw new InvalidAlgorithmParameterException @@ -381,14 +380,12 @@ private void implInit(int opmode, Key key, byte[] iv, ("IV not used in ECB mode"); } } - } else { // MODE_CBC or MODE_CTR + } else { // Mode.CBC, Mode.CTR or Mode.CTS if (iv == null) { if (!encrypt) { - String exMsg = - (blockMode == MODE_CBC ? - "IV must be specified for decryption in CBC mode" : - "IV must be specified for decryption in CTR mode"); - throw new InvalidAlgorithmParameterException(exMsg); + throw new InvalidAlgorithmParameterException( + "IV must be specified for decryption in " + + blockMode + " mode"); } // generate random IV if (random == null) { @@ -433,6 +430,9 @@ private void reset(boolean doCancel) { session = token.releaseSession(session); bytesBuffered = 0; padBufferLen = 0; + if (padBuffer != null) { + Arrays.fill(padBuffer, (byte) 0); + } } } @@ -487,7 +487,7 @@ private void initialize() throws PKCS11Exception { if (session == null) { session = token.getOpSession(); } - CK_MECHANISM mechParams = (blockMode == MODE_CTR ? + CK_MECHANISM mechParams = (blockMode == Mode.CTR ? new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) : new CK_MECHANISM(mechanism, iv)); if (encrypt) { @@ -512,7 +512,9 @@ private int updateLength(int inLen) { } int result = inLen + bytesBuffered; - if (blockSize != 0 && blockMode != MODE_CTR) { + if (blockMode == Mode.CTS) { + result -= getCTSMustBeBuffered(result); + } else if (blockSize != 0 && blockMode != Mode.CTR) { // minus the number of bytes in the last incomplete block. result -= (result & (blockSize - 1)); } @@ -526,7 +528,7 @@ private int doFinalLength(int inLen) { } int result = inLen + bytesBuffered; - if (blockSize != 0 && encrypt && paddingType != PAD_NONE) { + if (blockSize != 0 && encrypt && paddingType != Pad.NONE) { // add the number of bytes to make the last block complete. result += (blockSize - (result & (blockSize - 1))); } @@ -604,7 +606,56 @@ private int implUpdate(byte[] in, int inOfs, int inLen, ensureInitialized(); int k = 0; int newPadBufferLen = 0; - if (paddingObj != null && (!encrypt || reqBlockUpdates)) { + if (blockMode == Mode.CTS) { + // decide how to split the total data (totalInLen) between + // the token (dataForP11Update) and padBuffer + // (newPadBufferLen) + int totalInLen = padBufferLen + inLen; + newPadBufferLen = getCTSMustBeBuffered(totalInLen); + int dataForP11Update = totalInLen - newPadBufferLen; + if (dataForP11Update > 0 && padBufferLen > 0) { + // there is data for the token and part of it is in + // padBuffer + int flushFromPadBuffer; + int fillLen = getBytesToCompleteBlock(padBufferLen); + if (dataForP11Update >= padBufferLen + fillLen) { + // flush the whole padBuffer + if (fillLen > 0) { + // complete the last padBuffer block from the + // input + bufferInputBytes(in, inOfs, fillLen); + inOfs += fillLen; + inLen -= fillLen; + } + flushFromPadBuffer = padBufferLen; + } else { + // There is not enough input data available to + // complete the padBuffer to a multiple of block + // size. Flush part of the padBuffer (up to a + // multiple of blockSize) now. Shift the remaining + // padBuffer data and buffer more up to completing + // newPadBufferLen later. + flushFromPadBuffer = dataForP11Update; + } + if (encrypt) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + 0, out, outOfs, outLen); + } else { + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + 0, out, outOfs, outLen); + } + padBufferLen -= flushFromPadBuffer; + if (padBufferLen > 0) { + // shift remaining data to the padBuffer start + System.arraycopy(padBuffer, flushFromPadBuffer, + padBuffer, 0, padBufferLen); + } + } + newPadBufferLen -= padBufferLen; + inLen -= newPadBufferLen; + } else if (paddingObj != null && (!encrypt || reqBlockUpdates)) { if (padBufferLen != 0) { if (padBufferLen != padBuffer.length) { int bufCapacity = padBuffer.length - padBufferLen; @@ -649,7 +700,8 @@ private int implUpdate(byte[] in, int inOfs, int inLen, } } // update 'padBuffer' if using our own padding impl. - if (paddingObj != null && newPadBufferLen > 0) { + if ((blockMode == Mode.CTS || paddingObj != null) && + newPadBufferLen > 0) { bufferInputBytes(in, inOfs + inLen, newPadBufferLen); } bytesBuffered += (inLen - k); @@ -715,7 +767,56 @@ private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) int k = 0; int newPadBufferLen = 0; - if (paddingObj != null && (!encrypt || reqBlockUpdates)) { + if (blockMode == Mode.CTS) { + // decide how to split the total data (totalInLen) between + // the token (dataForP11Update) and padBuffer + // (newPadBufferLen) + int totalInLen = padBufferLen + inLen; + newPadBufferLen = getCTSMustBeBuffered(totalInLen); + int dataForP11Update = totalInLen - newPadBufferLen; + if (dataForP11Update > 0 && padBufferLen > 0) { + // there is data for the token and part of it is in + // padBuffer + int flushFromPadBuffer; + int fillLen = getBytesToCompleteBlock(padBufferLen); + if (dataForP11Update >= padBufferLen + fillLen) { + // flush the whole padBuffer + if (fillLen > 0) { + // complete the last padBuffer block from the + // input + bufferInputBytes(inBuffer, fillLen); + inOfs += fillLen; + inLen -= fillLen; + } + flushFromPadBuffer = padBufferLen; + } else { + // There is not enough input data available to + // complete the padBuffer to a multiple of block + // size. Flush part of the padBuffer (up to a + // multiple of blockSize) now. Shift the remaining + // padBuffer data and buffer more up to completing + // newPadBufferLen later. + flushFromPadBuffer = dataForP11Update; + } + if (encrypt) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + outAddr, outArray, outOfs, outLen); + } else { + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, flushFromPadBuffer, + outAddr, outArray, outOfs, outLen); + } + padBufferLen -= flushFromPadBuffer; + if (padBufferLen > 0) { + // shift remaining data to the padBuffer start + System.arraycopy(padBuffer, flushFromPadBuffer, + padBuffer, 0, padBufferLen); + } + } + newPadBufferLen -= padBufferLen; + inLen -= newPadBufferLen; + } else if (paddingObj != null && (!encrypt || reqBlockUpdates)) { if (padBufferLen != 0) { if (padBufferLen != padBuffer.length) { int bufCapacity = padBuffer.length - padBufferLen; @@ -768,7 +869,8 @@ private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer) } } // update 'padBuffer' if using our own padding impl. - if (paddingObj != null && newPadBufferLen > 0) { + if ((blockMode == Mode.CTS || paddingObj != null) && + newPadBufferLen > 0) { bufferInputBytes(inBuffer, newPadBufferLen); } bytesBuffered += (inLen - k); @@ -830,6 +932,10 @@ private int implDoFinal(byte[] out, int outOfs, int outLen) k += token.p11.C_EncryptUpdate(session.id(), 0, padBuffer, 0, startOff + actualPadLen, 0, out, outOfs + k, outLen - k); + } else if (blockMode == Mode.CTS) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); } // Some implementations such as the NSS Software Token do not // cancel the operation upon a C_EncryptUpdate failure (as @@ -839,6 +945,9 @@ private int implDoFinal(byte[] out, int outOfs, int outLen) doCancel = false; k += token.p11.C_EncryptFinal(session.id(), 0, out, (outOfs + k), (outLen - k)); + if (blockMode == Mode.CTS) { + convertCTSVariant(null, out, outOfs + k); + } } else { // Special handling to match SunJCE provider behavior if (bytesBuffered == 0 && padBufferLen == 0) { @@ -863,8 +972,16 @@ private int implDoFinal(byte[] out, int outOfs, int outLen) k -= actualPadLen; System.arraycopy(padBuffer, 0, out, outOfs, k); } else { + if (blockMode == Mode.CTS) { + convertCTSVariant(null, padBuffer, padBufferLen); + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + 0, out, outOfs, outLen); + outOfs += k; + outLen -= k; + } doCancel = false; - k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, + k += token.p11.C_DecryptFinal(session.id(), 0, out, outOfs, outLen); } } @@ -928,6 +1045,10 @@ private int implDoFinal(ByteBuffer outBuffer) k += token.p11.C_EncryptUpdate(session.id(), 0, padBuffer, 0, startOff + actualPadLen, outAddr, outArray, outOfs + k, outLen - k); + } else if (blockMode == Mode.CTS) { + k = token.p11.C_EncryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + outAddr, outArray, outOfs, outLen); } // Some implementations such as the NSS Software Token do not // cancel the operation upon a C_EncryptUpdate failure (as @@ -937,12 +1058,14 @@ private int implDoFinal(ByteBuffer outBuffer) doCancel = false; k += token.p11.C_EncryptFinal(session.id(), outAddr, outArray, (outOfs + k), (outLen - k)); + if (blockMode == Mode.CTS) { + convertCTSVariant(outBuffer, outArray, outOfs + k); + } } else { // Special handling to match SunJCE provider behavior if (bytesBuffered == 0 && padBufferLen == 0) { return 0; } - if (paddingObj != null) { if (padBufferLen != 0) { k = token.p11.C_DecryptUpdate(session.id(), @@ -964,8 +1087,16 @@ private int implDoFinal(ByteBuffer outBuffer) outArray = padBuffer; outOfs = 0; } else { + if (blockMode == Mode.CTS) { + convertCTSVariant(null, padBuffer, padBufferLen); + k = token.p11.C_DecryptUpdate(session.id(), + 0, padBuffer, 0, padBufferLen, + outAddr, outArray, outOfs, outLen); + outOfs += k; + outLen -= k; + } doCancel = false; - k = token.p11.C_DecryptFinal(session.id(), + k += token.p11.C_DecryptFinal(session.id(), outAddr, outArray, outOfs, outLen); } } @@ -988,6 +1119,83 @@ private int implDoFinal(ByteBuffer outBuffer) } } + private int getBytesToCompleteBlock(int availableBytes) { + int partBlock = availableBytes & (blockSize - 1); + return partBlock == 0 ? 0 : blockSize - partBlock; + } + + private int getCTSMustBeBuffered(int availableBytes) { + return Math.min(availableBytes, + padBuffer.length - getBytesToCompleteBlock(availableBytes)); + } + + /** + * The ciphertext ordering for the three variants can be depicted as + * follows, where 'p' is the penultimate block (which may be partial + * or full), and 'f' the full final block: + * + * 'p' is a partial block 'p' is a full block + * ------------------------ --------------------- + * CS1 (NIST) | .... pp ffff | .... pppp ffff + * CS2 (Schneier) | .... ffff pp | .... pppp ffff + * CS3 (Kerberos) | .... ffff pp | .... ffff pppp + * + * After encryption, we get the ciphertext from the token formatted as + * specified in the SunPKCS11 'cipherTextStealingVariant' configuration + * property. Conversely, before decryption, the ciphertext has to be passed + * to the token according to the previous formatting. This method converts + * the ciphertext between the format used by the token and the one used by + * SunJCE's "AES/CTS/NoPadding" implementation (CS3 as described by RFC + * 2040, section 8). + */ + private void convertCTSVariant(ByteBuffer ciphertextBuf, + byte[] ciphertextArr, int ciphertextEnd) { + if (padBufferLen == blockSize) { + // No reordering needed for a single block + return; + } + assert token.ctsVariant != null : "CTS algorithms should not be " + + "registered if the CTS variant of the token is unknown"; + if (token.ctsVariant == Token.CTSVariant.CS3) { + // Already CS3 + return; + } + int pad = padBufferLen % blockSize; + if (token.ctsVariant == Token.CTSVariant.CS2 && pad != 0) { + // CS2 and 'p' is a partial block, equal to CS3 + return; + } + if (ciphertextArr != null) { + ciphertextBuf = ByteBuffer.wrap(ciphertextArr); + } + if (ciphertextBuf != null) { + // No assumptions should be made about the current ciphertextBuf + // position. Additionally, if ciphertextBuf was not created here, + // the position should not be altered. To ensure this, use offsets + // to read and write bytes from the last two blocks (i.e. absolute + // ByteBuffer operations). Other blocks should not be modified. + pad = pad == 0 ? blockSize : pad; + if (encrypt) { + // .... pp[pp] ffff -> .... ffff pp[pp] + swapLastTwoBlocks(ciphertextBuf, ciphertextEnd, pad, blockSize); + } else { + // .... ffff pp[pp] -> .... pp[pp] ffff + swapLastTwoBlocks(ciphertextBuf, ciphertextEnd, blockSize, pad); + } + } + } + + private static void swapLastTwoBlocks(ByteBuffer ciphertextBuf, + int ciphertextEnd, int prevBlockLen, int lastBlockLen) { + // .... prevBlock lastBlock -> .... lastBlock prevBlock + int prevBlockStart = ciphertextEnd - prevBlockLen - lastBlockLen; + byte[] prevBlockBackup = new byte[prevBlockLen]; + ciphertextBuf.get(prevBlockStart, prevBlockBackup); + ciphertextBuf.put(prevBlockStart, ciphertextBuf, + ciphertextEnd - lastBlockLen, lastBlockLen); + ciphertextBuf.put(ciphertextEnd - prevBlockLen, prevBlockBackup); + } + private void handleException(PKCS11Exception e) throws ShortBufferException, IllegalBlockSizeException { if (e.match(CKR_BUFFER_TOO_SMALL)) { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index 07aaa1037ea54..4d10584fa09ba 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -860,6 +860,15 @@ private static void register(Descriptor d) { dA(CIP, "AES_256/KWP/NoPadding", P11KeyWrapCipher, m(CKM_AES_KEY_WRAP_KWP)); + d(CIP, "AES/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES_128/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES_192/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES_256/CTS/NoPadding", P11Cipher, + m(CKM_AES_CTS)); + d(CIP, "AES/GCM/NoPadding", P11AEADCipher, m(CKM_AES_GCM)); dA(CIP, "AES_128/GCM/NoPadding", P11AEADCipher, @@ -1290,7 +1299,13 @@ private void initToken(CK_SLOT_INFO slotInfo) throws PKCS11Exception { } continue; } - + if (longMech == CKM_AES_CTS && token.ctsVariant == null) { + if (showInfo) { + System.out.println("DISABLED due to an unspecified " + + "cipherTextStealingVariant in configuration"); + } + continue; + } if (brokenMechanisms.contains(longMech)) { if (showInfo) { System.out.println("DISABLED due to known issue with NSS"); diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java index a6f5f0a8764bb..b9937b7f0b1ed 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ * @since 1.5 */ final class Token implements Serializable { + public enum CTSVariant {CS1, CS2, CS3} // need to be serializable to allow SecureRandom to be serialized @Serial @@ -65,6 +66,8 @@ final class Token implements Serializable { @SuppressWarnings("serial") // Type of field is not Serializable final Config config; + final transient CTSVariant ctsVariant; + @SuppressWarnings("serial") // Type of field is not Serializable final CK_TOKEN_INFO tokenInfo; @@ -146,6 +149,7 @@ final class Token implements Serializable { config = provider.config; tokenInfo = p11.C_GetTokenInfo(provider.slotID); writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0; + ctsVariant = getCTSVariant(); // create session manager and open a test session SessionManager sessionManager; try { @@ -412,6 +416,19 @@ CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception { return result; } + private CTSVariant getCTSVariant() { + CTSVariant ctsVariant = config.getCTSVariant(); + if (ctsVariant != null) { + return ctsVariant; + } + // 'cipherTextStealingVariant' needs an explicit value for the + // CKM_AES_CTS mechanism to be enabled. In the case of NSS we know + // that this value is 'CS1', so we can set it for the user. See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=373108#c7 + // https://github.com/nss-dev/nss/blob/NSS_3_99_RTM/lib/freebl/cts.c#L65 + return P11Util.isNSS(this) ? CTSVariant.CS1 : null; + } + private synchronized byte[] getTokenId() { if (tokenId == null) { SecureRandom random = JCAUtil.getSecureRandom(); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java b/test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java new file mode 100644 index 0000000000000..87eeb2519f692 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCipherTextStealingMultipart.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.security.Provider; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.stream.IntStream; + +/* + * @test + * @bug 8330842 + * @summary test AES CTS multipart operations with SunPKCS11 + * @library /test/lib .. + * @run main/othervm/timeout=120 TestCipherTextStealingMultipart + */ + +public class TestCipherTextStealingMultipart extends PKCS11Test { + private static final String LF = System.lineSeparator(); + private static final String ALGORITHM = "AES/CTS/NoPadding"; + private static final int BLOCK_SIZE = 16; + private static final Key KEY = + new SecretKeySpec("AbCdEfGhIjKlMnOp".getBytes(), "AES"); + private static final IvParameterSpec IV = + new IvParameterSpec("1234567890aBcDeF".getBytes()); + + private static final StringBuilder chunksDesc = new StringBuilder(); + private static Provider sunPKCS11; + private static Cipher sunJCECipher; + + private static byte[][] generateChunks(int totalLength, int[] chunkSizes) { + chunksDesc.setLength(0); + chunksDesc.append("Testing with ").append(totalLength) + .append(" bytes distributed in ").append(chunkSizes.length) + .append(" multipart updates:").append(LF); + int byteIdx = 0; + byte[][] plaintextChunks = new byte[chunkSizes.length][]; + for (int chunkIdx = 0; chunkIdx < chunkSizes.length; chunkIdx++) { + byte[] chunk = new byte[chunkSizes[chunkIdx]]; + for (int i = 0; i < chunk.length; i++) { + chunk[i] = (byte) ('A' + byteIdx++ / BLOCK_SIZE); + } + chunksDesc.append(" ").append(repr(chunk)).append(LF); + plaintextChunks[chunkIdx] = chunk; + } + return plaintextChunks; + } + + private static byte[] computeExpected(byte[] jointPlaintext) + throws Exception { + byte[] ciphertext = sunJCECipher.doFinal(jointPlaintext); + if (ciphertext.length != jointPlaintext.length) { + throw new Exception("In CTS mode, ciphertext and plaintext should" + + " have the same length. However, SunJCE's CTS cipher " + + "returned a ciphertext of " + ciphertext.length + " bytes" + + " and plaintext has " + jointPlaintext.length + " bytes."); + } + return ciphertext; + } + + private static byte[] join(byte[][] inputChunks, int totalLength) { + ByteBuffer outputBuf = ByteBuffer.allocate(totalLength); + for (byte[] inputChunk : inputChunks) { + outputBuf.put(inputChunk); + } + return outputBuf.array(); + } + + private static byte[][] split(byte[] input, int[] chunkSizes) { + ByteBuffer inputBuf = ByteBuffer.wrap(input); + byte[][] outputChunks = new byte[chunkSizes.length][]; + for (int chunkIdx = 0; chunkIdx < chunkSizes.length; chunkIdx++) { + byte[] chunk = new byte[chunkSizes[chunkIdx]]; + inputBuf.get(chunk); + outputChunks[chunkIdx] = chunk; + } + return outputChunks; + } + + private enum CheckType {CIPHERTEXT, PLAINTEXT} + + private enum OutputType {BYTE_ARRAY, DIRECT_BYTE_BUFFER} + + private static void check(CheckType checkType, OutputType outputType, + byte[] expected, ByteBuffer actualBuf) throws Exception { + byte[] actual; + if (actualBuf.hasArray()) { + actual = actualBuf.array(); + } else { + actual = new byte[actualBuf.position()]; + actualBuf.position(0).get(actual); + } + if (!Arrays.equals(actual, expected)) { + throw new Exception("After " + switch (checkType) { + case CIPHERTEXT -> "encrypting"; + case PLAINTEXT -> "decrypting"; + } + " into a " + switch (outputType) { + case BYTE_ARRAY -> "byte[]"; + case DIRECT_BYTE_BUFFER -> "direct ByteBuffer"; + } + ", " + checkType.name().toLowerCase() + "s don't match:" + LF + + " Expected: " + repr(expected) + LF + + " Actual: " + repr(actual)); + } + } + + private static ByteBuffer encryptOrDecryptMultipart(int operation, + OutputType outputType, byte[][] inputChunks, int totalLength) + throws Exception { + Cipher cipher = Cipher.getInstance(ALGORITHM, sunPKCS11); + cipher.init(operation, KEY, IV); + ByteBuffer output = null; + int outOfs = 1; + switch (outputType) { + case BYTE_ARRAY -> { + output = ByteBuffer.allocate(totalLength); + for (byte[] inputChunk : inputChunks) { + output.put(cipher.update(inputChunk)); + } + // Check that the output array offset does not affect the + // penultimate block length calculation. + byte[] tmpOut = new byte[cipher.getOutputSize(0) + outOfs]; + cipher.doFinal(tmpOut, outOfs); + output.put(tmpOut, outOfs, tmpOut.length - outOfs); + } + case DIRECT_BYTE_BUFFER -> { + output = ByteBuffer.allocateDirect(totalLength); + for (byte[] inputChunk : inputChunks) { + cipher.update(ByteBuffer.wrap(inputChunk), output); + } + // Check that the output array offset does not affect the + // penultimate block length calculation. + ByteBuffer tmpOut = ByteBuffer.allocateDirect( + cipher.getOutputSize(0) + outOfs); + tmpOut.position(outOfs); + cipher.doFinal(ByteBuffer.allocate(0), tmpOut); + tmpOut.position(outOfs); + output.put(tmpOut); + } + } + return output; + } + + private static void doMultipart(int... chunkSizes) throws Exception { + int totalLength = IntStream.of(chunkSizes).sum(); + byte[][] plaintextChunks = generateChunks(totalLength, chunkSizes); + byte[] jointPlaintext = join(plaintextChunks, totalLength); + byte[] expectedCiphertext = computeExpected(jointPlaintext); + byte[][] ciphertextChunks = split(expectedCiphertext, chunkSizes); + + for (OutputType outputType : OutputType.values()) { + // Encryption test + check(CheckType.CIPHERTEXT, outputType, expectedCiphertext, + encryptOrDecryptMultipart(Cipher.ENCRYPT_MODE, outputType, + plaintextChunks, totalLength)); + // Decryption test + check(CheckType.PLAINTEXT, outputType, jointPlaintext, + encryptOrDecryptMultipart(Cipher.DECRYPT_MODE, outputType, + ciphertextChunks, totalLength)); + } + } + + private static String repr(byte[] data) { + if (data == null) { + return ""; + } + if (data.length == 0) { + return ""; + } + String lenRepr = " (" + data.length + " bytes)"; + for (byte b : data) { + if (b < 32 || b > 126) { + return HexFormat.ofDelimiter(":").formatHex(data) + lenRepr; + } + } + return new String(data, StandardCharsets.US_ASCII) + lenRepr; + } + + private static void initialize() throws Exception { + sunJCECipher = Cipher.getInstance(ALGORITHM, "SunJCE"); + sunJCECipher.init(Cipher.ENCRYPT_MODE, KEY, IV); + } + + public static void main(String[] args) throws Exception { + initialize(); + main(new TestCipherTextStealingMultipart(), args); + } + + @Override + public void main(Provider p) throws Exception { + sunPKCS11 = p; + try { + // Test relevant combinations for 2, 3, and 4 update operations + int aesBSize = 16; + int[] points = new int[]{1, aesBSize - 1, aesBSize, aesBSize + 1}; + for (int size1 : points) { + for (int size2 : points) { + if (size1 + size2 >= aesBSize) { + doMultipart(size1, size2); + } + for (int size3 : points) { + if (size1 + size2 + size3 >= aesBSize) { + doMultipart(size1, size2, size3); + } + for (int size4 : points) { + if (size1 + size2 + size3 + size4 >= aesBSize) { + doMultipart(size1, size2, size3, size4); + } + } + } + } + } + doMultipart(17, 17, 17, 17, 17); + doMultipart(4, 2, 7, 1, 6, 12); + doMultipart(2, 15, 21, 26, 31, 26, 5, 30); + doMultipart(7, 12, 26, 8, 15, 2, 17, 16, 21, 2, 32, 29); + doMultipart(6, 7, 6, 1, 5, 16, 14, 1, 10, 16, 17, 8, 1, 13, 12); + doMultipart(16, 125, 19, 32, 32, 16, 17, + 31, 19, 13, 16, 16, 32, 16, 16); + doMultipart(5, 30, 11, 9, 6, 14, 20, 6, + 5, 18, 31, 33, 15, 29, 7, 9); + doMultipart(105, 8, 21, 27, 30, 101, 15, 20, + 23, 33, 26, 6, 8, 2, 13, 17); + } catch (Exception e) { + System.out.print(chunksDesc); + throw e; + } + System.out.println("TEST PASS - OK"); + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java index 2127256b5ec07..e0a7d53e1c1a6 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * 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 4898461 6604496 + * @bug 4898461 6604496 8330842 * @summary basic test for symmetric ciphers with padding * @author Valerie Peng * @library /test/lib .. @@ -80,10 +80,11 @@ private static class CI { // class for holding Cipher Information new CI("DESede", "DESede", 408), new CI("AES", "AES", 128), - new CI("AES/CTR/NoPadding", "AES", 3200) + new CI("AES/CTR/NoPadding", "AES", 3200), + new CI("AES/CTS/NoPadding", "AES", 3200), }; - private static StringBuffer debugBuf = new StringBuffer(); + private static final StringBuffer debugBuf = new StringBuffer(); @Override public void main(Provider p) throws Exception { @@ -128,10 +129,7 @@ public void main(Provider p) throws Exception { } } catch (Exception ex) { // print out debug info when exception is encountered - if (debugBuf != null) { - System.out.println(debugBuf.toString()); - debugBuf = new StringBuffer(); - } + System.out.println(debugBuf); throw ex; } } @@ -171,8 +169,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, } byte[] testOut1 = baos.toByteArray(); endTime = System.nanoTime(); - perfOut("stream InBuf + stream OutBuf: " + - (endTime - startTime)); + perfOut("stream InBuf + stream OutBuf", endTime - startTime); match(testOut1, answer); // test#2: Non-direct Buffer in + non-direct Buffer out @@ -184,8 +181,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inBuf, outBuf); cipher.doFinal(inBuf, outBuf); endTime = System.nanoTime(); - perfOut("non-direct InBuf + non-direct OutBuf: " + - (endTime - startTime)); + perfOut("non-direct InBuf + non-direct OutBuf", endTime - startTime); match(outBuf, answer); // test#3: Direct Buffer in + direc Buffer out @@ -197,8 +193,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inDirectBuf, outDirectBuf); cipher.doFinal(inDirectBuf, outDirectBuf); endTime = System.nanoTime(); - perfOut("direct InBuf + direct OutBuf: " + - (endTime - startTime)); + perfOut("direct InBuf + direct OutBuf", endTime - startTime); //debugOut("(post) inputBuf: " + inDirectBuf + "\n"); //debugOut("(post) outputBuf: " + outDirectBuf + "\n"); @@ -215,8 +210,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inDirectBuf, outBuf); cipher.doFinal(inDirectBuf, outBuf); endTime = System.nanoTime(); - perfOut("direct InBuf + non-direct OutBuf: " + - (endTime - startTime)); + perfOut("direct InBuf + non-direct OutBuf", endTime - startTime); match(outBuf, answer); // test#5: Non-direct Buffer in + direct Buffer out @@ -231,26 +225,21 @@ private static void test(Cipher cipher, int mode, SecretKey key, cipher.update(inBuf, outDirectBuf); cipher.doFinal(inBuf, outDirectBuf); endTime = System.nanoTime(); - perfOut("non-direct InBuf + direct OutBuf: " + - (endTime - startTime)); + perfOut("non-direct InBuf + direct OutBuf", endTime - startTime); //debugOut("(post) inputBuf: " + inBuf + "\n"); //debugOut("(post) outputBuf: " + outDirectBuf + "\n"); match(outDirectBuf, answer); - debugBuf = null; + debugBuf.setLength(0); } - private static void perfOut(String msg) { - if (debugBuf != null) { - debugBuf.append("PERF>" + msg); - } + private static void perfOut(String msg, long elapsed) { + debugOut("PERF> " + msg + ", elapsed: " + elapsed + " ns\n"); } private static void debugOut(String msg) { - if (debugBuf != null) { - debugBuf.append(msg); - } + debugBuf.append(msg); } private static void match(byte[] b1, byte[] b2) throws Exception { diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java index 8f53cda2f6ba4..2288a5699fb34 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * 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 4898484 6604496 8001284 + * @bug 4898484 6604496 8001284 8330842 * @summary basic test for symmetric ciphers with no padding * @author Valerie Peng * @library /test/lib .. @@ -68,10 +68,12 @@ private static class CI { // class for holding Cipher Information new CI("AES/CBC/NoPadding", "AES", 4800), new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), new CI("AES/CTR/NoPadding", "AES", 1600), - new CI("AES/CTR/NoPadding", "AES", 65) + new CI("AES/CTR/NoPadding", "AES", 65), + new CI("AES/CTS/NoPadding", "AES", 1600), + new CI("AES/CTS/NoPadding", "AES", 65), }; - private static StringBuffer debugBuf; + private static final StringBuffer debugBuf = new StringBuffer(); @Override public void main(Provider p) throws Exception { @@ -111,9 +113,7 @@ public void main(Provider p) throws Exception { } } catch (Exception ex) { // print out debug info when exception is encountered - if (debugBuf != null) { - System.out.println(debugBuf.toString()); - } + System.out.println(debugBuf); throw ex; } } @@ -122,7 +122,6 @@ private static void test(Cipher cipher, int mode, SecretKey key, AlgorithmParameters params, byte[] in, byte[] answer) throws Exception { // test setup - debugBuf = new StringBuffer(); cipher.init(mode, key, params); int outLen = cipher.getOutputSize(in.length); debugBuf.append("Estimated output size = " + outLen + "\n"); @@ -214,7 +213,7 @@ private static void test(Cipher cipher, int mode, SecretKey key, } match(outBuf, answer); - debugBuf = null; + debugBuf.setLength(0); } private static void match(byte[] b1, byte[] b2) throws Exception { From b6ffb442acb4a222f017868433eff213d9b84ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 27 Jun 2024 15:14:36 +0000 Subject: [PATCH 080/288] 8335135: HttpURLConnection#HttpInputStream does not throw IOException when response is truncated Reviewed-by: dfuchs --- .../classes/sun/net/www/MeteredStream.java | 5 +- .../java/net/Authenticator/BasicTest4.java | 4 +- .../URLConnection/TruncatedFixedResponse.java | 112 ++++++++++++++++++ ...liveStreamCloseWithWrongContentLength.java | 4 +- 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/net/URLConnection/TruncatedFixedResponse.java diff --git a/src/java.base/share/classes/sun/net/www/MeteredStream.java b/src/java.base/share/classes/sun/net/www/MeteredStream.java index d12389416fcbd..eaa93bba56c4a 100644 --- a/src/java.base/share/classes/sun/net/www/MeteredStream.java +++ b/src/java.base/share/classes/sun/net/www/MeteredStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,9 @@ private final void justRead(long n) throws IOException { assert isLockHeldByCurrentThread(); if (n == -1) { + if (expected > count) { + throw new IOException("Premature EOF"); + } /* * don't close automatically when mark is set and is valid; diff --git a/test/jdk/java/net/Authenticator/BasicTest4.java b/test/jdk/java/net/Authenticator/BasicTest4.java index 0146651ba6a37..becfdb351abf9 100644 --- a/test/jdk/java/net/Authenticator/BasicTest4.java +++ b/test/jdk/java/net/Authenticator/BasicTest4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,7 +151,7 @@ public void run () { System.out.println ("checkfor returned " + success); readAll (s); os = s.getOutputStream(); - os.write (reply2.getBytes()); + os.write ((reply2+"HelloAgain").getBytes()); s.close (); if (success) diff --git a/test/jdk/java/net/URLConnection/TruncatedFixedResponse.java b/test/jdk/java/net/URLConnection/TruncatedFixedResponse.java new file mode 100644 index 0000000000000..89d801999309a --- /dev/null +++ b/test/jdk/java/net/URLConnection/TruncatedFixedResponse.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8335135 + * @library /test/lib + * @summary Check that reading from inputStream throws an IOException + * if the fixed response stream is closed before reading all bytes. + */ + +import jdk.test.lib.net.URIBuilder; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; + +public class TruncatedFixedResponse implements Runnable { + + ServerSocket ss; + + /* + * Our "http" server to return a truncated fixed response + */ + public void run() { + try { + Socket s = ss.accept(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(s.getInputStream())); + while (true) { + String req = in.readLine(); + if (req.isEmpty()) { + break; + } + } + PrintStream out = new PrintStream( + new BufferedOutputStream(s.getOutputStream())); + + /* send the header */ + out.print("HTTP/1.1 200\r\n"); + out.print("Content-Length: 100\r\n"); + out.print("Content-Type: text/html\r\n"); + out.print("\r\n"); + out.print("Some content, but too short"); + out.close(); + s.close(); + ss.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + TruncatedFixedResponse() throws Exception { + /* start the server */ + ss = new ServerSocket(); + ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + new Thread(this).start(); + + /* establish http connection to server */ + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(ss.getLocalPort()) + .path("/foo") + .toURL(); + HttpURLConnection http = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + + try (InputStream in = http.getInputStream()) { + while (in.read() != -1) { + // discard response + } + throw new AssertionError("Expected IOException was not thrown"); + } catch (IOException ex) { + System.out.println("Got expected exception: " + ex); + } + } + + public static void main(String args[]) throws Exception { + new TruncatedFixedResponse(); + } +} diff --git a/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java b/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java index 32796985a8b4d..e859d671a6740 100644 --- a/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java +++ b/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,7 +173,7 @@ public static void main (String[] args) throws Exception { c=is.read(); System.out.println("client reads: "+c); } catch (IOException ioe) { - is.read (); + System.out.println("client got expected exception: "+ioe); break; } } From 0e6b0cbaaa0d5272f60ee4fe09cf5e247e68c2a8 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 27 Jun 2024 15:38:06 +0000 Subject: [PATCH 081/288] 8334886: jdk/jfr/api/recording/time/TestTimeMultiple.java failed with RuntimeException: getStopTime() > afterStop Reviewed-by: mgronlun --- src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp | 2 -- src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp b/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp index b88ba06bdf799..a35b046e56c92 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp @@ -47,8 +47,6 @@ jlong JfrChunk::nanos_now() { const jlong now = seconds * 1000000000 + nanos; if (now > last) { last = now; - } else { - ++last; } return last; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java index 345d2fdcc8dfb..114052ecea250 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java @@ -103,7 +103,6 @@ static long nanosToTicks(long nanos) { static long getChunkStartNanos() { long nanos = JVM.getChunkStartNanos(); - // JVM::getChunkStartNanos() may return a bumped timestamp, +1 ns or +2 ns. // Spin here to give Instant.now() a chance to catch up. awaitUniqueTimestamp(); return nanos; From 9d986a013d01a5bcc0942bcc490258038291c22c Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 27 Jun 2024 16:06:35 +0000 Subject: [PATCH 082/288] 8335220: C2: Missing check for Opaque4 node in EscapeAnalysis Reviewed-by: chagedorn, cslucas --- src/hotspot/share/opto/escape.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 1338bb3c90901..2ca722148b61e 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -574,18 +574,23 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const { // CmpP/N used by the If controlling the cast. if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) { Node* iff = use->in(0)->in(0); - if (iff->Opcode() == Op_If && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) { + // We may have Opaque4 node between If and Bool nodes. + // Bail out in such case - we need to preserve Opaque4 for correct + // processing predicates after loop opts. + bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp(); + if (can_reduce) { Node* iff_cmp = iff->in(1)->in(1); int opc = iff_cmp->Opcode(); - if ((opc == Op_CmpP || opc == Op_CmpN) && !can_reduce_cmp(n, iff_cmp)) { + can_reduce = (opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(n, iff_cmp); + } + if (!can_reduce) { #ifndef PRODUCT - if (TraceReduceAllocationMerges) { - tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx); - n->dump(5); - } -#endif - return false; + if (TraceReduceAllocationMerges) { + tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx); + n->dump(5); } +#endif + return false; } } } @@ -651,7 +656,12 @@ Node* ConnectionGraph::specialize_cmp(Node* base, Node* curr_ctrl) { if (curr_ctrl == nullptr || curr_ctrl->is_Region()) { con = _igvn->zerocon(t->basic_type()); } else { - Node* curr_cmp = curr_ctrl->in(0)->in(1)->in(1); // true/false -> if -> bool -> cmp + // can_reduce_check_users() verified graph: true/false -> if -> bool -> cmp + assert(curr_ctrl->in(0)->Opcode() == Op_If, "unexpected node %s", curr_ctrl->in(0)->Name()); + Node* bol = curr_ctrl->in(0)->in(1); + assert(bol->is_Bool(), "unexpected node %s", bol->Name()); + Node* curr_cmp = bol->in(1); + assert(curr_cmp->Opcode() == Op_CmpP || curr_cmp->Opcode() == Op_CmpN, "unexpected node %s", curr_cmp->Name()); con = curr_cmp->in(1)->is_Con() ? curr_cmp->in(1) : curr_cmp->in(2); } From 243bae7dc0c3e71c02ffed9e1ee7d436af11d3b9 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 27 Jun 2024 18:25:16 +0000 Subject: [PATCH 083/288] 8304693: Remove -XX:-UseVtableBasedCHA Reviewed-by: kvn, coleenp, dholmes --- src/hotspot/share/ci/ciMethod.cpp | 15 +-- src/hotspot/share/code/dependencies.cpp | 10 +- src/hotspot/share/oops/instanceKlass.cpp | 21 +--- src/hotspot/share/oops/instanceKlass.hpp | 3 - src/hotspot/share/runtime/arguments.cpp | 1 + src/hotspot/share/runtime/globals.hpp | 3 - .../compiler/cha/AbstractRootMethod.java | 2 +- .../jtreg/compiler/cha/DefaultRootMethod.java | 2 +- .../cha/StrengthReduceInterfaceCall.java | 2 +- .../invocationOldCHATests.java | 117 ------------------ test/jtreg-ext/requires/VMProps.java | 1 - 11 files changed, 12 insertions(+), 165 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index aac2a553cda31..844ef0a0c03da 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -718,17 +718,10 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, { MutexLocker locker(Compile_lock); InstanceKlass* context = actual_recv->get_instanceKlass(); - if (UseVtableBasedCHA) { - target = methodHandle(THREAD, Dependencies::find_unique_concrete_method(context, - root_m->get_Method(), - callee_holder->get_Klass(), - this->get_Method())); - } else { - if (root_m->is_abstract()) { - return nullptr; // not supported - } - target = methodHandle(THREAD, Dependencies::find_unique_concrete_method(context, root_m->get_Method())); - } + target = methodHandle(THREAD, Dependencies::find_unique_concrete_method(context, + root_m->get_Method(), + callee_holder->get_Klass(), + this->get_Method())); assert(target() == nullptr || !target()->is_abstract(), "not allowed"); // %%% Should upgrade this ciMethod API to look for 1 or 2 concrete methods. } diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 26e53ed90275c..7d3b744313f12 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -113,11 +113,7 @@ void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm) void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm, ciKlass* resolved_klass, ciMethod* resolved_method) { check_ctxk(ctxk); check_unique_method(ctxk, uniqm); - if (UseVtableBasedCHA) { - assert_common_4(unique_concrete_method_4, ctxk, uniqm, resolved_klass, resolved_method); - } else { - assert_common_2(unique_concrete_method_2, ctxk, uniqm); - } + assert_common_4(unique_concrete_method_4, ctxk, uniqm, resolved_klass, resolved_method); } void Dependencies::assert_unique_implementor(ciInstanceKlass* ctxk, ciInstanceKlass* uniqk) { @@ -1474,7 +1470,6 @@ class LinkedConcreteMethodFinder : public AbstractClassHierarchyWalker { // Optionally, a method which was previously determined as a unique target (uniqm) is added as a participant // to enable dependency spot-checking and speed up the search. LinkedConcreteMethodFinder(InstanceKlass* resolved_klass, Method* resolved_method, Method* uniqm = nullptr) : AbstractClassHierarchyWalker(nullptr) { - assert(UseVtableBasedCHA, "required"); assert(resolved_klass->is_linked(), "required"); assert(resolved_method->method_holder()->is_linked(), "required"); assert(!resolved_method->can_be_statically_bound(), "no vtable index available"); @@ -1948,7 +1943,6 @@ Klass* Dependencies::check_unique_concrete_method(InstanceKlass* ctxk, Klass* resolved_klass, Method* resolved_method, KlassDepChange* changes) { - assert(UseVtableBasedCHA, "required"); assert(!ctxk->is_interface() || ctxk == resolved_klass, "sanity"); assert(!resolved_method->can_be_statically_bound() || resolved_method == uniqm, "sanity"); assert(resolved_klass->is_subtype_of(resolved_method->method_holder()), "sanity"); @@ -2129,7 +2123,7 @@ Klass* Dependencies::DepStream::check_klass_dependency(KlassDepChange* changes) Dependencies::check_valid_dependency_type(type()); if (changes != nullptr) { - if (UseVtableBasedCHA && changes->is_klass_init_change()) { + if (changes->is_klass_init_change()) { return check_klass_init_dependency(changes->as_klass_init_change()); } else { return check_new_klass_dependency(changes->as_new_klass_change()); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index aa8f47f62df2f..9c40bc1cee811 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -929,7 +929,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { // In case itable verification is ever added. // itable().verify(tty, true); #endif - if (UseVtableBasedCHA && Universe::is_fully_initialized()) { + if (Universe::is_fully_initialized()) { DeoptimizationScope deopt_scope; { // Now mark all code that assumes the class is not linked. @@ -1264,7 +1264,7 @@ void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) // Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock // is grabbed, to ensure that the compiler is not using the class hierarchy. -void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) { +void InstanceKlass::add_to_hierarchy(JavaThread* current) { assert(!SafepointSynchronize::is_at_safepoint(), "must NOT be at safepoint"); DeoptimizationScope deopt_scope; @@ -1290,23 +1290,6 @@ void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) { deopt_scope.deoptimize_marked(); } -void InstanceKlass::add_to_hierarchy(JavaThread* current) { - - if (UseVtableBasedCHA || !Universe::is_fully_initialized()) { - add_to_hierarchy_impl(current); - } else { - // In case we are not using CHA based vtables we need to make sure the loaded - // deopt is completed before anyone links this class. - // Linking is done with init_lock held, by loading and deopting with it - // held we make sure the deopt is completed before linking. - Handle h_init_lock(current, init_lock()); - ObjectLocker ol(h_init_lock, current); - add_to_hierarchy_impl(current); - - // This doesn't need a notify because the wait is only on the class initialization path. - } -} - InstanceKlass* InstanceKlass::implementor() const { InstanceKlass* volatile* ik = adr_implementor(); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index fe281f9514805..6e5d4ac8e7feb 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -828,9 +828,6 @@ class InstanceKlass: public Klass { void set_jni_ids(JNIid* ids) { _jni_ids = ids; } JNIid* jni_id_for(int offset); - private: - void add_to_hierarchy_impl(JavaThread* current); - public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index f428403fa3002..d353c5a162ae3 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -522,6 +522,7 @@ static SpecialFlag const special_jvm_flags[] = { #endif // X86 { "HeapFirstMaximumCompactionCount", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, + { "UseVtableBasedCHA", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index e4eb8d3e9e90c..468e9bd880086 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -968,9 +968,6 @@ const int ObjectAlignmentInBytes = 8; develop(bool, UseCHA, true, \ "Enable CHA") \ \ - product(bool, UseVtableBasedCHA, true, DIAGNOSTIC, \ - "Use vtable information during CHA") \ - \ product(bool, UseTypeProfile, true, \ "Check interpreter profile for historically monomorphic calls") \ \ diff --git a/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java b/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java index 57f41dece806d..6f173fefe1ebf 100644 --- a/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java +++ b/test/hotspot/jtreg/compiler/cha/AbstractRootMethod.java @@ -23,7 +23,7 @@ /* * @test - * @requires !vm.graal.enabled & vm.opt.final.UseVtableBasedCHA == true + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java b/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java index ee2dda744e697..1b72399069e3e 100644 --- a/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java +++ b/test/hotspot/jtreg/compiler/cha/DefaultRootMethod.java @@ -23,7 +23,7 @@ /* * @test - * @requires !vm.graal.enabled & vm.opt.final.UseVtableBasedCHA == true + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java b/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java index 736fa242bdcdd..068da4100bd69 100644 --- a/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java +++ b/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java @@ -23,7 +23,7 @@ /* * @test - * @requires !vm.graal.enabled & vm.opt.final.UseVtableBasedCHA == true + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java b/test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java deleted file mode 100644 index 415cd105ee9ad..0000000000000 --- a/test/hotspot/jtreg/runtime/InvocationTests/invocationOldCHATests.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. - * 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 id=special - * @summary Run invocation tests with old CHA (-XX:-UseVtableBasedCHA) - * @requires vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.misc - * @compile invokespecial/Checker.java invokespecial/ClassGenerator.java invokespecial/Generator.java - * - * @run driver/timeout=1800 invocationOldCHATests special - */ - -/* - * @test id=virtual - * @summary Run invocation tests with old CHA (-XX:-UseVtableBasedCHA) - * @requires vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.misc - * @compile invokevirtual/Checker.java invokevirtual/ClassGenerator.java invokevirtual/Generator.java - * - * @run driver/timeout=1800 invocationOldCHATests virtual - */ - -/* - * @test id=interface - * @summary Run invocation tests with old CHA (-XX:-UseVtableBasedCHA) - * @requires vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.misc - * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java invokeinterface/Generator.java - * - * @run driver/timeout=1800 invocationOldCHATests interface - */ - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.compiler.InMemoryJavaCompiler; - -public class invocationOldCHATests { - - public static void runTest(String whichTests, String classFileVersion) throws Throwable { - System.out.println("\nOld CHA invocation tests, Tests: " + whichTests + - ", class file version: " + classFileVersion); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128M", - "-Xcomp", "-XX:+UnlockDiagnosticVMOptions", "-XX:-UseVtableBasedCHA", - "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", - whichTests, "--classfile_version=" + classFileVersion); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - try { - output.shouldContain("EXECUTION STATUS: PASSED"); - output.shouldHaveExitValue(0); - } catch (Throwable e) { - System.out.println( - "\nNote that an entry such as 'B.m/C.m' in the failure chart means that" + - " the test case failed because method B.m was invoked but the test " + - "expected method C.m to be invoked. Similarly, a result such as 'AME/C.m'" + - " means that an AbstractMethodError exception was thrown but the test" + - " case expected method C.m to be invoked."); - System.out.println( - "\nAlso note that passing --dump to invoke*.Generator will" + - " dump the generated classes (for debugging purposes).\n"); - - throw e; - } - } - - public static void main(String args[]) throws Throwable { - if (args.length < 1) { - throw new IllegalArgumentException("Should provide the test name"); - } - String testName = args[0]; - - // Get current major class file version and test with it. - byte klassbuf[] = InMemoryJavaCompiler.compile("blah", "public class blah { }"); - int major_version = klassbuf[6] << 8 | klassbuf[7]; - - switch (testName) { - case "special": - runTest("invokespecial.Generator", String.valueOf(major_version)); - break; - case "virtual": - runTest("invokevirtual.Generator", String.valueOf(major_version)); - break; - case "interface": - runTest("invokeinterface.Generator", String.valueOf(major_version)); - break; - default: - throw new IllegalArgumentException("Unknown test name: " + testName); - } - } -} diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index e37646ac6d1c5..49cc6e1431114 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -386,7 +386,6 @@ protected void vmOptFinalFlags(SafeMap map) { vmOptFinalFlag(map, "EliminateAllocations"); vmOptFinalFlag(map, "UseCompressedOops"); vmOptFinalFlag(map, "UseVectorizedMismatchIntrinsic"); - vmOptFinalFlag(map, "UseVtableBasedCHA"); vmOptFinalFlag(map, "ZGenerational"); } From c35e58a5adf06e25a3b482e2be384af95a84f11a Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 27 Jun 2024 20:10:13 +0000 Subject: [PATCH 084/288] 8309634: Resolve CONSTANT_MethodRef at CDS dump time Reviewed-by: matsaave, ccheung --- src/hotspot/share/cds/classListParser.cpp | 2 + src/hotspot/share/cds/classListWriter.cpp | 21 +++- src/hotspot/share/cds/classPrelinker.cpp | 18 ++- src/hotspot/share/cds/dumpAllocStats.cpp | 4 + src/hotspot/share/cds/dumpAllocStats.hpp | 12 ++ .../share/interpreter/interpreterRuntime.cpp | 36 +++++- .../share/interpreter/interpreterRuntime.hpp | 7 +- .../share/interpreter/linkResolver.cpp | 104 +++++++++++++----- .../share/interpreter/linkResolver.hpp | 10 +- src/hotspot/share/oops/cpCache.cpp | 95 +++++++++++++++- src/hotspot/share/oops/cpCache.hpp | 4 +- .../share/oops/resolvedMethodEntry.hpp | 25 +++++ .../resolvedConstants/ResolvedConstants.java | 52 ++++++++- 13 files changed, 348 insertions(+), 42 deletions(-) diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 9ee5f25aa8918..b2695ac2e7873 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -830,6 +830,8 @@ void ClassListParser::parse_constant_pool_tag() { // ignore break; case JVM_CONSTANT_Fieldref: + case JVM_CONSTANT_Methodref: + case JVM_CONSTANT_InterfaceMethodref: preresolve_fmi = true; break; break; diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 97f0bc3476e55..78cd092445b70 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -258,15 +258,26 @@ void ClassListWriter::write_resolved_constants_for(InstanceKlass* ik) { if (field_entries != nullptr) { for (int i = 0; i < field_entries->length(); i++) { ResolvedFieldEntry* rfe = field_entries->adr_at(i); - if (rfe->is_resolved(Bytecodes::_getstatic) || - rfe->is_resolved(Bytecodes::_putstatic) || - rfe->is_resolved(Bytecodes::_getfield) || + if (rfe->is_resolved(Bytecodes::_getfield) || rfe->is_resolved(Bytecodes::_putfield)) { list.at_put(rfe->constant_pool_index(), true); print = true; } } } + + Array* method_entries = cp->cache()->resolved_method_entries(); + if (method_entries != nullptr) { + for (int i = 0; i < method_entries->length(); i++) { + ResolvedMethodEntry* rme = method_entries->adr_at(i); + if (rme->is_resolved(Bytecodes::_invokevirtual) || + rme->is_resolved(Bytecodes::_invokespecial) || + rme->is_resolved(Bytecodes::_invokeinterface)) { + list.at_put(rme->constant_pool_index(), true); + print = true; + } + } + } } if (print) { @@ -276,7 +287,9 @@ void ClassListWriter::write_resolved_constants_for(InstanceKlass* ik) { if (list.at(i)) { constantTag cp_tag = cp->tag_at(i).value(); assert(cp_tag.value() == JVM_CONSTANT_Class || - cp_tag.value() == JVM_CONSTANT_Fieldref, "sanity"); + cp_tag.value() == JVM_CONSTANT_Fieldref || + cp_tag.value() == JVM_CONSTANT_Methodref|| + cp_tag.value() == JVM_CONSTANT_InterfaceMethodref, "sanity"); stream->print(" %d", i); } } diff --git a/src/hotspot/share/cds/classPrelinker.cpp b/src/hotspot/share/cds/classPrelinker.cpp index 223d3937f9354..6b866bac9958d 100644 --- a/src/hotspot/share/cds/classPrelinker.cpp +++ b/src/hotspot/share/cds/classPrelinker.cpp @@ -89,7 +89,9 @@ bool ClassPrelinker::is_resolution_deterministic(ConstantPool* cp, int cp_index) // currently archive only CP entries that are already resolved. Klass* resolved_klass = cp->resolved_klass_at(cp_index); return resolved_klass != nullptr && is_class_resolution_deterministic(cp->pool_holder(), resolved_klass); - } else if (cp->tag_at(cp_index).is_field()) { + } else if (cp->tag_at(cp_index).is_field() || + cp->tag_at(cp_index).is_method() || + cp->tag_at(cp_index).is_interface_method()) { int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); if (!cp->tag_at(klass_cp_index).is_klass()) { // Not yet resolved @@ -263,6 +265,14 @@ void ClassPrelinker::preresolve_field_and_method_cp_entries(JavaThread* current, CLEAR_PENDING_EXCEPTION; // just ignore } break; + case Bytecodes::_invokespecial: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + maybe_resolve_fmi_ref(ik, m, raw_bc, bcs.get_index_u2(), preresolve_list, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; // just ignore + } + break; default: break; } @@ -301,6 +311,12 @@ void ClassPrelinker::maybe_resolve_fmi_ref(InstanceKlass* ik, Method* m, Bytecod InterpreterRuntime::resolve_get_put(bc, raw_index, mh, cp, false /*initialize_holder*/, CHECK); break; + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: + case Bytecodes::_invokeinterface: + InterpreterRuntime::cds_resolve_invoke(bc, raw_index, cp, CHECK); + break; + default: ShouldNotReachHere(); } diff --git a/src/hotspot/share/cds/dumpAllocStats.cpp b/src/hotspot/share/cds/dumpAllocStats.cpp index 30ef1597063b1..a1dac41e32271 100644 --- a/src/hotspot/share/cds/dumpAllocStats.cpp +++ b/src/hotspot/share/cds/dumpAllocStats.cpp @@ -110,4 +110,8 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all) { _num_field_cp_entries, _num_field_cp_entries_archived, percent_of(_num_field_cp_entries_archived, _num_field_cp_entries), _num_field_cp_entries_reverted); + msg.info("Method CP entries = %6d, archived = %6d (%5.1f%%), reverted = %6d", + _num_method_cp_entries, _num_method_cp_entries_archived, + percent_of(_num_method_cp_entries_archived, _num_method_cp_entries), + _num_method_cp_entries_reverted); } diff --git a/src/hotspot/share/cds/dumpAllocStats.hpp b/src/hotspot/share/cds/dumpAllocStats.hpp index 424a98aa73838..0332be7312088 100644 --- a/src/hotspot/share/cds/dumpAllocStats.hpp +++ b/src/hotspot/share/cds/dumpAllocStats.hpp @@ -71,6 +71,9 @@ class DumpAllocStats : public StackObj { int _num_klass_cp_entries; int _num_klass_cp_entries_archived; int _num_klass_cp_entries_reverted; + int _num_method_cp_entries; + int _num_method_cp_entries_archived; + int _num_method_cp_entries_reverted; public: enum { RO = 0, RW = 1 }; @@ -84,6 +87,9 @@ class DumpAllocStats : public StackObj { _num_klass_cp_entries = 0; _num_klass_cp_entries_archived = 0; _num_klass_cp_entries_reverted = 0; + _num_method_cp_entries = 0; + _num_method_cp_entries_archived = 0; + _num_method_cp_entries_reverted = 0; }; CompactHashtableStats* symbol_stats() { return &_symbol_stats; } @@ -122,6 +128,12 @@ class DumpAllocStats : public StackObj { _num_klass_cp_entries_reverted += reverted ? 1 : 0; } + void record_method_cp_entry(bool archived, bool reverted) { + _num_method_cp_entries ++; + _num_method_cp_entries_archived += archived ? 1 : 0; + _num_method_cp_entries_reverted += reverted ? 1 : 0; + } + void print_stats(int ro_all, int rw_all); }; diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index fb779b039f49a..4f2eae023f68d 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -832,7 +832,6 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt // resolve method CallInfo info; constantPoolHandle pool(current, last_frame.method()->constants()); - ConstantPoolCache* cache = pool->cache(); methodHandle resolved_method; @@ -857,10 +856,18 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt resolved_method = methodHandle(current, info.resolved_method()); } // end JvmtiHideSingleStepping + update_invoke_cp_cache_entry(info, bytecode, resolved_method, pool, method_index); +} + +void InterpreterRuntime::update_invoke_cp_cache_entry(CallInfo& info, Bytecodes::Code bytecode, + methodHandle& resolved_method, + constantPoolHandle& pool, + int method_index) { // Don't allow safepoints until the method is cached. NoSafepointVerifier nsv; // check if link resolution caused cpCache to be updated + ConstantPoolCache* cache = pool->cache(); if (cache->resolved_method_entry_at(method_index)->is_resolved(bytecode)) return; #ifdef ASSERT @@ -912,6 +919,33 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt } } +void InterpreterRuntime::cds_resolve_invoke(Bytecodes::Code bytecode, int method_index, + constantPoolHandle& pool, TRAPS) { + LinkInfo link_info(pool, method_index, bytecode, CHECK); + + if (!link_info.resolved_klass()->is_instance_klass() || InstanceKlass::cast(link_info.resolved_klass())->is_linked()) { + CallInfo call_info; + switch (bytecode) { + case Bytecodes::_invokevirtual: LinkResolver::cds_resolve_virtual_call (call_info, link_info, CHECK); break; + case Bytecodes::_invokeinterface: LinkResolver::cds_resolve_interface_call(call_info, link_info, CHECK); break; + case Bytecodes::_invokespecial: LinkResolver::cds_resolve_special_call (call_info, link_info, CHECK); break; + + default: fatal("Unimplemented: %s", Bytecodes::name(bytecode)); + } + methodHandle resolved_method(THREAD, call_info.resolved_method()); + guarantee(resolved_method->method_holder()->is_linked(), ""); + update_invoke_cp_cache_entry(call_info, bytecode, resolved_method, pool, method_index); + } else { + // FIXME: why a shared class is not linked yet? + // Can't link it here since there are no guarantees it'll be prelinked on the next run. + ResourceMark rm; + InstanceKlass* resolved_iklass = InstanceKlass::cast(link_info.resolved_klass()); + log_info(cds, resolve)("Not resolved: class not linked: %s %s %s", + resolved_iklass->is_shared() ? "is_shared" : "", + resolved_iklass->init_state_name(), + resolved_iklass->external_name()); + } +} // First time execution: Resolve symbols, create a permanent MethodType object. void InterpreterRuntime::resolve_invokehandle(JavaThread* current) { diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp index 3a8db1363df5b..61041694fc643 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -92,9 +92,11 @@ class InterpreterRuntime: AllStatic { static void resolve_from_cache(JavaThread* current, Bytecodes::Code bytecode); - // Used by ClassListParser. + // Used by ClassPrelinker static void resolve_get_put(Bytecodes::Code bytecode, int field_index, methodHandle& m, constantPoolHandle& pool, bool initialize_holder, TRAPS); + static void cds_resolve_invoke(Bytecodes::Code bytecode, int method_index, + constantPoolHandle& pool, TRAPS); private: // Statics & fields @@ -105,6 +107,9 @@ class InterpreterRuntime: AllStatic { static void resolve_invokehandle (JavaThread* current); static void resolve_invokedynamic(JavaThread* current); + static void update_invoke_cp_cache_entry(CallInfo& info, Bytecodes::Code bytecode, + methodHandle& resolved_method, + constantPoolHandle& pool, int method_index); public: // Synchronization static void monitorenter(JavaThread* current, BasicObjectLock* elem); diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 2c7decfa714a2..cadc3e8a2e802 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -142,7 +142,9 @@ void CallInfo::set_common(Klass* resolved_klass, CallKind kind, int index, TRAPS) { - assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond"); + if (selected_method.not_null()) { + assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond"); + } _resolved_klass = resolved_klass; _resolved_method = resolved_method; _selected_method = selected_method; @@ -151,7 +153,9 @@ void CallInfo::set_common(Klass* resolved_klass, _resolved_appendix = Handle(); DEBUG_ONLY(verify()); // verify before making side effects - CompilationPolicy::compile_if_required(selected_method, THREAD); + if (selected_method.not_null()) { + CompilationPolicy::compile_if_required(selected_method, THREAD); + } } // utility query for unreflecting a method @@ -1152,6 +1156,10 @@ void LinkResolver::resolve_special_call(CallInfo& result, runtime_resolve_special_method(result, link_info, methodHandle(THREAD, resolved_method), recv, CHECK); } +void LinkResolver::cds_resolve_special_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { + resolve_special_call(result, Handle(), link_info, CHECK); +} + // throws linktime exceptions Method* LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info, TRAPS) { @@ -1333,7 +1341,17 @@ void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, Klass* re runtime_resolve_virtual_method(result, methodHandle(THREAD, resolved_method), link_info.resolved_klass(), recv, receiver_klass, - check_null_and_abstract, CHECK); + check_null_and_abstract, + /*is_abstract_interpretation*/ false, CHECK); +} + +void LinkResolver::cds_resolve_virtual_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { + Method* resolved_method = linktime_resolve_virtual_method(link_info, CHECK); + runtime_resolve_virtual_method(result, methodHandle(THREAD, resolved_method), + link_info.resolved_klass(), + Handle(), nullptr, + /*check_null_and_abstract*/ false, + /*is_abstract_interpretation*/ true, CHECK); } // throws linktime exceptions @@ -1385,7 +1403,11 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, Handle recv, Klass* recv_klass, bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS) { + // is_abstract_interpretation is true IFF CDS is resolving method references without + // running any actual bytecode. Therefore, we don't have an actual recv/recv_klass, so + // we cannot check the actual selected_method (which is not needed by CDS anyway). // setup default return values int vtable_index = Method::invalid_vtable_index; @@ -1406,7 +1428,9 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, vtable_index = vtable_index_of_interface_method(resolved_klass, resolved_method); assert(vtable_index >= 0 , "we should have valid vtable index at this point"); - selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + if (!is_abstract_interpretation) { + selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + } } else { // at this point we are sure that resolved_method is virtual and not // a default or miranda method; therefore, it must have a valid vtable index. @@ -1420,31 +1444,40 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result, // resolved method, and it can never be changed by an override. if (vtable_index == Method::nonvirtual_vtable_index) { assert(resolved_method->can_be_statically_bound(), "cannot override this method"); - selected_method = resolved_method; + if (!is_abstract_interpretation) { + selected_method = resolved_method; + } } else { - selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + if (!is_abstract_interpretation) { + selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index)); + } } } - // check if method exists - if (selected_method.is_null()) { - throw_abstract_method_error(resolved_method, recv_klass, CHECK); - } + if (!is_abstract_interpretation) { + // check if method exists + if (selected_method.is_null()) { + throw_abstract_method_error(resolved_method, recv_klass, CHECK); + } - // check if abstract - if (check_null_and_abstract && selected_method->is_abstract()) { - // Pass arguments for generating a verbose error message. - throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK); - } + // check if abstract + if (check_null_and_abstract && selected_method->is_abstract()) { + // Pass arguments for generating a verbose error message. + throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK); + } - if (log_develop_is_enabled(Trace, vtables)) { - trace_method_resolution("invokevirtual selected method: receiver-class:", - recv_klass, resolved_klass, selected_method(), - false, vtable_index); + if (log_develop_is_enabled(Trace, vtables)) { + trace_method_resolution("invokevirtual selected method: receiver-class:", + recv_klass, resolved_klass, selected_method(), + false, vtable_index); + } } + // setup result result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); - JFR_ONLY(Jfr::on_resolution(result, CHECK);) + if (selected_method.not_null()) { + JFR_ONLY(Jfr::on_resolution(result, CHECK);) + } } void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* recv_klass, @@ -1454,7 +1487,16 @@ void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* Method* resolved_method = linktime_resolve_interface_method(link_info, CHECK); methodHandle mh(THREAD, resolved_method); runtime_resolve_interface_method(result, mh, link_info.resolved_klass(), - recv, recv_klass, check_null_and_abstract, CHECK); + recv, recv_klass, check_null_and_abstract, + /*is_abstract_interpretation*/ false, CHECK); +} + +void LinkResolver::cds_resolve_interface_call(CallInfo& result, const LinkInfo& link_info, TRAPS) { + Method* resolved_method = linktime_resolve_interface_method(link_info, CHECK); + runtime_resolve_interface_method(result, methodHandle(THREAD, resolved_method), link_info.resolved_klass(), + Handle(), nullptr, + /*check_null_and_abstract*/ false, + /*is_abstract_interpretation*/ true, CHECK); } Method* LinkResolver::linktime_resolve_interface_method(const LinkInfo& link_info, @@ -1473,7 +1515,9 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, Klass* resolved_klass, Handle recv, Klass* recv_klass, - bool check_null_and_abstract, TRAPS) { + bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS) { + // is_abstract_interpretation -- see comments in runtime_resolve_virtual_method() // check if receiver exists if (check_null_and_abstract && recv.is_null()) { @@ -1481,7 +1525,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, } // check if receiver klass implements the resolved interface - if (!recv_klass->is_subtype_of(resolved_klass)) { + if (!is_abstract_interpretation && !recv_klass->is_subtype_of(resolved_klass)) { ResourceMark rm(THREAD); char buf[200]; jio_snprintf(buf, sizeof(buf), "Class %s does not implement the requested interface %s", @@ -1490,10 +1534,14 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } - methodHandle selected_method = resolved_method; + methodHandle selected_method; + + if (!is_abstract_interpretation) { + selected_method = resolved_method; + } // resolve the method in the receiver class, unless it is private - if (!resolved_method()->is_private()) { + if (!is_abstract_interpretation && !resolved_method()->is_private()) { // do lookup based on receiver klass // This search must match the linktime preparation search for itable initialization // to correctly enforce loader constraints for interface method inheritance. @@ -1539,7 +1587,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, if (resolved_method->has_vtable_index()) { int vtable_index = resolved_method->vtable_index(); log_develop_trace(itables)(" -- vtable index: %d", vtable_index); - assert(vtable_index == selected_method->vtable_index(), "sanity check"); + assert(is_abstract_interpretation || vtable_index == selected_method->vtable_index(), "sanity check"); result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); } else if (resolved_method->has_itable_index()) { int itable_index = resolved_method()->itable_index(); @@ -1556,7 +1604,9 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, // This sets up the nonvirtual form of "virtual" call (as needed for final and private methods) result.set_virtual(resolved_klass, resolved_method, resolved_method, index, CHECK); } - JFR_ONLY(Jfr::on_resolution(result, CHECK);) + if (!is_abstract_interpretation) { + JFR_ONLY(Jfr::on_resolution(result, CHECK);) + } } diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp index 80f5d23005241..340c7d412d599 100644 --- a/src/hotspot/share/interpreter/linkResolver.hpp +++ b/src/hotspot/share/interpreter/linkResolver.hpp @@ -242,13 +242,15 @@ class LinkResolver: AllStatic { Klass* resolved_klass, Handle recv, Klass* recv_klass, - bool check_null_and_abstract, TRAPS); + bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS); static void runtime_resolve_interface_method (CallInfo& result, const methodHandle& resolved_method, Klass* resolved_klass, Handle recv, Klass* recv_klass, - bool check_null_and_abstract, TRAPS); + bool check_null_and_abstract, + bool is_abstract_interpretation, TRAPS); static bool resolve_previously_linked_invokehandle(CallInfo& result, const LinkInfo& link_info, @@ -325,6 +327,10 @@ class LinkResolver: AllStatic { static void resolve_dynamic_call (CallInfo& result, BootstrapInfo& bootstrap_specifier, TRAPS); + static void cds_resolve_virtual_call (CallInfo& result, const LinkInfo& link_info, TRAPS); + static void cds_resolve_interface_call(CallInfo& result, const LinkInfo& link_info, TRAPS); + static void cds_resolve_special_call (CallInfo& result, const LinkInfo& link_info, TRAPS); + // same as above for compile-time resolution; but returns null handle instead of throwing // an exception on error also, does not initialize klass (i.e., no side effects) static Method* resolve_virtual_call_or_null(Klass* receiver_klass, diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 95c3b8edaf5e1..817a35959f348 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -46,6 +46,7 @@ #include "oops/compressedOops.hpp" #include "oops/constantPool.inline.hpp" #include "oops/cpCache.inline.hpp" +#include "oops/method.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/resolvedFieldEntry.hpp" @@ -408,9 +409,7 @@ void ConstantPoolCache::remove_unshareable_info() { remove_resolved_field_entries_if_non_deterministic(); } if (_resolved_method_entries != nullptr) { - for (int i = 0; i < _resolved_method_entries->length(); i++) { - resolved_method_entry_at(i)->remove_unshareable_info(); - } + remove_resolved_method_entries_if_non_deterministic(); } } @@ -448,6 +447,96 @@ void ConstantPoolCache::remove_resolved_field_entries_if_non_deterministic() { ArchiveBuilder::alloc_stats()->record_field_cp_entry(archived, resolved && !archived); } } + +void ConstantPoolCache::remove_resolved_method_entries_if_non_deterministic() { + ConstantPool* cp = constant_pool(); + ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(cp); + for (int i = 0; i < _resolved_method_entries->length(); i++) { + ResolvedMethodEntry* rme = _resolved_method_entries->adr_at(i); + int cp_index = rme->constant_pool_index(); + bool archived = false; + bool resolved = rme->is_resolved(Bytecodes::_invokevirtual) || + rme->is_resolved(Bytecodes::_invokespecial) || + rme->is_resolved(Bytecodes::_invokeinterface); + + // Just for safety -- this should not happen, but do not archive if we ever see this. + resolved &= !(rme->is_resolved(Bytecodes::_invokehandle) || + rme->is_resolved(Bytecodes::_invokestatic)); + + if (resolved && can_archive_resolved_method(rme)) { + rme->mark_and_relocate(src_cp); + archived = true; + } else { + rme->remove_unshareable_info(); + } + if (resolved) { + LogStreamHandle(Trace, cds, resolve) log; + if (log.is_enabled()) { + ResourceMark rm; + int klass_cp_index = cp->uncached_klass_ref_index_at(cp_index); + Symbol* klass_name = cp->klass_name_at(klass_cp_index); + Symbol* name = cp->uncached_name_ref_at(cp_index); + Symbol* signature = cp->uncached_signature_ref_at(cp_index); + log.print("%s%s method CP entry [%3d]: %s %s.%s:%s", + (archived ? "archived" : "reverted"), + (rme->is_resolved(Bytecodes::_invokeinterface) ? " interface" : ""), + cp_index, + cp->pool_holder()->name()->as_C_string(), + klass_name->as_C_string(), name->as_C_string(), signature->as_C_string()); + if (archived) { + Klass* resolved_klass = cp->resolved_klass_at(klass_cp_index); + log.print(" => %s%s", + resolved_klass->name()->as_C_string(), + (rme->is_resolved(Bytecodes::_invokestatic) ? " *** static" : "")); + } + } + ArchiveBuilder::alloc_stats()->record_method_cp_entry(archived, resolved && !archived); + } + } +} + +bool ConstantPoolCache::can_archive_resolved_method(ResolvedMethodEntry* method_entry) { + InstanceKlass* pool_holder = constant_pool()->pool_holder(); + if (!(pool_holder->is_shared_boot_class() || pool_holder->is_shared_platform_class() || + pool_holder->is_shared_app_class())) { + // Archiving resolved cp entries for classes from non-builtin loaders + // is not yet supported. + return false; + } + + if (CDSConfig::is_dumping_dynamic_archive()) { + // InstanceKlass::methods() has been resorted. We need to + // update the vtable_index in method_entry (not implemented) + return false; + } + + if (!method_entry->is_resolved(Bytecodes::_invokevirtual)) { + if (method_entry->method() == nullptr) { + return false; + } + if (method_entry->method()->is_continuation_native_intrinsic()) { + return false; // FIXME: corresponding stub is generated on demand during method resolution (see LinkResolver::resolve_static_call). + } + } + + int cp_index = method_entry->constant_pool_index(); + ConstantPool* src_cp = ArchiveBuilder::current()->get_source_addr(constant_pool()); + assert(src_cp->tag_at(cp_index).is_method() || src_cp->tag_at(cp_index).is_interface_method(), "sanity"); + + if (!ClassPrelinker::is_resolution_deterministic(src_cp, cp_index)) { + return false; + } + + if (method_entry->is_resolved(Bytecodes::_invokeinterface) || + method_entry->is_resolved(Bytecodes::_invokevirtual) || + method_entry->is_resolved(Bytecodes::_invokespecial)) { + return true; + } else { + // invokestatic and invokehandle are not supported yet. + return false; + } + +} #endif // INCLUDE_CDS void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) { diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 1f91b194623eb..c741201c8332d 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -224,6 +224,8 @@ class ConstantPoolCache: public MetaspaceObj { #if INCLUDE_CDS void remove_resolved_field_entries_if_non_deterministic(); + void remove_resolved_method_entries_if_non_deterministic(); + bool can_archive_resolved_method(ResolvedMethodEntry* method_entry); #endif // RedefineClasses support diff --git a/src/hotspot/share/oops/resolvedMethodEntry.hpp b/src/hotspot/share/oops/resolvedMethodEntry.hpp index e84452236006a..8f49608127fbe 100644 --- a/src/hotspot/share/oops/resolvedMethodEntry.hpp +++ b/src/hotspot/share/oops/resolvedMethodEntry.hpp @@ -82,6 +82,21 @@ class ResolvedMethodEntry { bool _has_table_index; #endif + void copy_from(const ResolvedMethodEntry& other) { + _method = other._method; + _entry_specific = other._entry_specific; + _cpool_index = other._cpool_index; + _number_of_parameters = other._number_of_parameters; + _tos_state = other._tos_state; + _flags = other._flags; + _bytecode1 = other._bytecode1; + _bytecode2 = other._bytecode2; +#ifdef ASSERT + _has_interface_klass = other._has_interface_klass; + _has_table_index = other._has_table_index; +#endif + } + // Constructors public: ResolvedMethodEntry(u2 cpi) : @@ -99,6 +114,16 @@ class ResolvedMethodEntry { ResolvedMethodEntry() : ResolvedMethodEntry(0) {} + ResolvedMethodEntry(const ResolvedMethodEntry& other) { + copy_from(other); + } + + ResolvedMethodEntry& operator=(const ResolvedMethodEntry& other) { + copy_from(other); + return *this; + } + + // Bit shift to get flags enum { is_vfinal_shift = 0, diff --git a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java index 96744b546a8d4..474fa65d6ea08 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java @@ -54,6 +54,8 @@ public static void main(String[] args) throws Exception { "-cp", appJar, "-Xlog:cds+resolve=trace"); CDSTestUtils.createArchiveAndCheck(opts) + // Class References --- + // Always resolve reference when a class references itself .shouldMatch("cds,resolve.*archived klass.* ResolvedConstantsApp app => ResolvedConstantsApp app") @@ -70,6 +72,8 @@ public static void main(String[] args) throws Exception { // class yet (i.e., there's no initiaited class entry for System in the app loader's dictionary) .shouldMatch("cds,resolve.*reverted klass.* ResolvedConstantsApp .*java/lang/System") + // Field References --- + // Always resolve references to fields in the current class or super class(es) .shouldMatch("cds,resolve.*archived field.* ResolvedConstantsBar => ResolvedConstantsBar.b:I") .shouldMatch("cds,resolve.*archived field.* ResolvedConstantsBar => ResolvedConstantsBar.a:I") @@ -80,11 +84,45 @@ public static void main(String[] args) throws Exception { .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsFoo ResolvedConstantsBar.a:I") .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsFoo ResolvedConstantsBar.b:I") - // Do not resolve field references to unrelated classes .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsApp ResolvedConstantsBar.a:I") .shouldMatch("cds,resolve.*reverted field.* ResolvedConstantsApp ResolvedConstantsBar.b:I") + // Method References --- + + // Should resolve references to own constructor + .shouldMatch("cds,resolve.*archived method .* ResolvedConstantsApp ResolvedConstantsApp.:") + // Should resolve references to super constructor + .shouldMatch("cds,resolve.*archived method .* ResolvedConstantsApp java/lang/Object.:") + + // Should resolve interface methods in VM classes + .shouldMatch("cds,resolve.*archived interface method .* ResolvedConstantsApp java/lang/Runnable.run:") + + // Should resolve references to own non-static method (private or public) + .shouldMatch("archived method.*: ResolvedConstantsBar ResolvedConstantsBar.doBar:") + .shouldMatch("archived method.*: ResolvedConstantsApp ResolvedConstantsApp.privateInstanceCall:") + .shouldMatch("archived method.*: ResolvedConstantsApp ResolvedConstantsApp.publicInstanceCall:") + + // Should not resolve references to static method + .shouldNotMatch(" archived method CP entry.*: ResolvedConstantsApp ResolvedConstantsApp.staticCall:") + + // Should resolve references to method in super type + .shouldMatch(" archived method CP entry.*: ResolvedConstantsBar ResolvedConstantsFoo.doBar:") + + // App class cannot resolve references to methods in boot classes: + // When the app class loader tries to resolve a class X that's normally loaded by + // the boot loader, it's possible for the app class loader to get a different copy of + // X (by using MethodHandles.Lookup.defineClass(), etc). Therefore, let's be on + // the side of safety and revert all such references. + // + // This will be addressed in JDK-8315737. + .shouldMatch("reverted method.*: ResolvedConstantsApp java/io/PrintStream.println:") + .shouldMatch("reverted method.*: ResolvedConstantsBar java/lang/Class.getName:") + + // Should not resolve methods in unrelated classes. + .shouldMatch("reverted method.*: ResolvedConstantsApp ResolvedConstantsBar.doit:") + + // End --- ; } } @@ -92,7 +130,11 @@ public static void main(String[] args) throws Exception { class ResolvedConstantsApp implements Runnable { public static void main(String args[]) { System.out.println("Hello ResolvedConstantsApp"); - Object a = new ResolvedConstantsApp(); + ResolvedConstantsApp app = new ResolvedConstantsApp(); + ResolvedConstantsApp.staticCall(); + app.privateInstanceCall(); + app.publicInstanceCall(); + Object a = app; ((Runnable)a).run(); ResolvedConstantsFoo foo = new ResolvedConstantsFoo(); @@ -101,6 +143,10 @@ public static void main(String args[]) { bar.b ++; bar.doit(); } + private static void staticCall() {} + private void privateInstanceCall() {} + public void publicInstanceCall() {} + public void run() {} } @@ -124,5 +170,7 @@ void doit() { System.out.println("b = " + b); doBar(this); + + ((ResolvedConstantsFoo)this).doBar(this); } } From 3b1ca986427d3a69c9e167b9b4c07d1b83bc264d Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Thu, 27 Jun 2024 20:27:51 +0000 Subject: [PATCH 085/288] 8334895: OpenJDK fails to configure on linux aarch64 when CDS is disabled after JDK-8331942 Reviewed-by: erikj --- make/autoconf/jdk-options.m4 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 0dca5d133131f..54ead5ec1d760 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -197,9 +197,8 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], # three different page sizes: 4K, 64K, and if run on Mac m1 hardware, 16K. COMPATIBLE_CDS_ALIGNMENT_DEFAULT=false if test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then - COMPATIBLE_CDS_ALIGNMENT_DEFAULT=true + COMPATIBLE_CDS_ALIGNMENT_DEFAULT=auto fi - AC_SUBST(COMPATIBLE_CDS_ALIGNMENT_DEFAULT) # Compress jars COMPRESS_JARS=false @@ -672,7 +671,7 @@ AC_DEFUN([JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT], UTIL_ARG_ENABLE(NAME: compatible-cds-alignment, DEFAULT: $COMPATIBLE_CDS_ALIGNMENT_DEFAULT, RESULT: ENABLE_COMPATIBLE_CDS_ALIGNMENT, DESC: [enable use alternative compatible cds core region alignment], - DEFAULT_DESC: [disabled], + DEFAULT_DESC: [disabled except on linux-aarch64], CHECKING_MSG: [if compatible cds region alignment enabled], CHECK_AVAILABLE: [ AC_MSG_CHECKING([if CDS archive is available]) From 4e8cbf884ab1eee9c3110712ab62edc706e948ba Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 27 Jun 2024 22:20:14 +0000 Subject: [PATCH 086/288] 8335134: Test com/sun/jdi/BreakpointOnClassPrepare.java timeout Reviewed-by: kevinw, coleenp --- test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java index f4f1427e39b24..deffffc0fa85a 100644 --- a/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java +++ b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java @@ -104,7 +104,15 @@ public static void main(String[] args) throws Exception { public void breakpointReached(BreakpointEvent event) { bkptCount++; - System.out.println("Got BreakpointEvent: " + bkptCount + " for thread " + event.thread()); + String threadInfo; + try { + threadInfo = event.thread().toString(); + } catch (ObjectCollectedException e) { + // It's possible the Thread already terminated and was collected + // if the SUSPEND_NONE policy was used. + threadInfo = "(thread collected)"; + } + System.out.println("Got BreakpointEvent: " + bkptCount + " for thread " + threadInfo); } public void vmDisconnected(VMDisconnectEvent event) { From cd46c87dc916b2b74067accf80c62df1792f74cf Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Fri, 28 Jun 2024 01:44:14 +0000 Subject: [PATCH 087/288] 8334843: RISC-V: Fix wraparound checking for r_array_index in lookup_secondary_supers_table_slow_path Reviewed-by: fyang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index e889c26e5f419..0e6a9099265ce 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3799,7 +3799,7 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // Check for wraparound. Label skip; - bge(r_array_length, r_array_index, skip); + blt(r_array_index, r_array_length, skip); mv(r_array_index, zr); bind(skip); From b4df380f1a4587247a843fe28ae041265f7cfc29 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 28 Jun 2024 03:07:09 +0000 Subject: [PATCH 088/288] 8334763: --enable-asan: assert(_thread->is_in_live_stack((address)this)) failed: not on stack? Reviewed-by: kbarrett, stuefe, erikj --- make/autoconf/jdk-options.m4 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 54ead5ec1d760..76e95127f7393 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -437,12 +437,23 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER], # It's harmless to be suppressed in clang as well. ASAN_CFLAGS="-fsanitize=address -Wno-stringop-truncation -fno-omit-frame-pointer -fno-common -DADDRESS_SANITIZER" ASAN_LDFLAGS="-fsanitize=address" + # detect_stack_use_after_return causes ASAN to offload stack-local + # variables to c-heap and therefore breaks assumptions in hotspot + # that rely on data (e.g. Marks) living in thread stacks. + if test "x$TOOLCHAIN_TYPE" = "xgcc"; then + ASAN_CFLAGS="$ASAN_CFLAGS --param asan-use-after-return=0" + fi + if test "x$TOOLCHAIN_TYPE" = "xclang"; then + ASAN_CFLAGS="$ASAN_CFLAGS -fsanitize-address-use-after-return=never" + fi elif test "x$TOOLCHAIN_TYPE" = "xmicrosoft"; then # -Oy- is equivalent to -fno-omit-frame-pointer in GCC/Clang. ASAN_CFLAGS="-fsanitize=address -Oy- -DADDRESS_SANITIZER" # MSVC produces a warning if you pass -fsanitize=address to the linker. It also complains $ if -DEBUG is not passed to the linker when building with ASan. ASAN_LDFLAGS="-debug" + # -fsanitize-address-use-after-return is off by default in MS Visual Studio 22 (19.37.32824). + # cl : Command line warning D9002 : ignoring unknown option '-fno-sanitize-address-use-after-return' fi JVM_CFLAGS="$JVM_CFLAGS $ASAN_CFLAGS" JVM_LDFLAGS="$JVM_LDFLAGS $ASAN_LDFLAGS" From 308a81238362c39f5b18e2ae8444c96420ef297a Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Fri, 28 Jun 2024 04:42:33 +0000 Subject: [PATCH 089/288] 8334645: Un-problemlist vmTestbase/nsk/sysdict/vm/stress/chain/chain007/chain007.java Reviewed-by: thartmann, lmesnik --- test/hotspot/jtreg/ProblemList-generational-zgc.txt | 2 -- test/hotspot/jtreg/ProblemList-zgc.txt | 2 -- 2 files changed, 4 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index 4d5e985c0a677..db8182641ac54 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -115,5 +115,3 @@ serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic- serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 - -vmTestbase/nsk/sysdict/vm/stress/chain/chain007/chain007.java 8298991 linux-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index d7d600aad490c..1afe56c99f8af 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -46,5 +46,3 @@ serviceability/sa/TestSysProps.java 8302055 generic- serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 - -vmTestbase/nsk/sysdict/vm/stress/chain/chain007/chain007.java 8298991 linux-x64 From c47a0e005e54551e42ee1ae33d7169417a5f86d4 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Fri, 28 Jun 2024 06:19:37 +0000 Subject: [PATCH 090/288] 8334147: Shenandoah: Avoid taking lock for disabled free set logging Reviewed-by: shade, ysr --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 5 +---- .../gc/shenandoah/shenandoahControlThread.cpp | 22 +++++++------------ .../share/gc/shenandoah/shenandoahFreeSet.cpp | 10 +++++++++ .../share/gc/shenandoah/shenandoahFreeSet.hpp | 6 ++++- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 44ccac467fe85..aea0af2457500 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -153,10 +153,7 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { // the space. This would be the last action if there is nothing to evacuate. entry_cleanup_early(); - { - ShenandoahHeapLocker locker(heap->lock()); - heap->free_set()->log_status(); - } + heap->free_set()->log_status_under_lock(); // Perform concurrent class unloading if (heap->unload_classes() && diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 4f71135084465..e538ca024678f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -147,10 +147,7 @@ void ShenandoahControlThread::run_service() { heap->set_forced_counters_update(true); // If GC was requested, we better dump freeset data for performance debugging - { - ShenandoahHeapLocker locker(heap->lock()); - heap->free_set()->log_status(); - } + heap->free_set()->log_status_under_lock(); switch (mode) { case concurrent_normal: @@ -178,18 +175,15 @@ void ShenandoahControlThread::run_service() { // Report current free set state at the end of cycle, whether // it is a normal completion, or the abort. - { - ShenandoahHeapLocker locker(heap->lock()); - heap->free_set()->log_status(); + heap->free_set()->log_status_under_lock(); - // Notify Universe about new heap usage. This has implications for - // global soft refs policy, and we better report it every time heap - // usage goes down. - heap->update_capacity_and_used_at_gc(); + // Notify Universe about new heap usage. This has implications for + // global soft refs policy, and we better report it every time heap + // usage goes down. + heap->update_capacity_and_used_at_gc(); - // Signal that we have completed a visit to all live objects. - heap->record_whole_heap_examined_timestamp(); - } + // Signal that we have completed a visit to all live objects. + heap->record_whole_heap_examined_timestamp(); // Disable forced counters update, and update counters one more time // to capture the state at the end of GC session. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index c11d7e814e4e0..258dfe17b736e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1130,6 +1130,16 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve) { } } +void ShenandoahFreeSet::log_status_under_lock() { + // Must not be heap locked, it acquires heap lock only when log is enabled + shenandoah_assert_not_heaplocked(); + if (LogTarget(Info, gc, free)::is_enabled() + DEBUG_ONLY(|| LogTarget(Debug, gc, free)::is_enabled())) { + ShenandoahHeapLocker locker(_heap->lock()); + log_status(); + } +} + void ShenandoahFreeSet::log_status() { shenandoah_assert_heaplocked(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index e2852e5548cf3..e4789d48f802e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -318,6 +318,9 @@ class ShenandoahFreeSet : public CHeapObj { void finish_rebuild(size_t cset_regions); + // log status, assuming lock has already been acquired by the caller. + void log_status(); + public: ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions); @@ -340,7 +343,8 @@ class ShenandoahFreeSet : public CHeapObj { void move_regions_from_collector_to_mutator(size_t cset_regions); void recycle_trash(); - void log_status(); + // Acquire heap lock and log status, assuming heap lock is not acquired by the caller. + void log_status_under_lock(); inline size_t capacity() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); } inline size_t used() const { return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } From d457609f700bbb1fed233f1a04501c995852e5ac Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 28 Jun 2024 06:43:32 +0000 Subject: [PATCH 091/288] 8319947: Recursive lightweight locking: s390x implementation Reviewed-by: aboldtch, lucy --- .../cpu/s390/c1_MacroAssembler_s390.cpp | 14 +- .../cpu/s390/c2_MacroAssembler_s390.cpp | 13 +- .../cpu/s390/c2_MacroAssembler_s390.hpp | 8 +- src/hotspot/cpu/s390/interp_masm_s390.cpp | 28 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 493 +++++++++++++++--- src/hotspot/cpu/s390/macroAssembler_s390.hpp | 6 +- src/hotspot/cpu/s390/s390.ad | 34 ++ src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 18 +- src/hotspot/cpu/s390/vm_version_s390.hpp | 2 + 9 files changed, 489 insertions(+), 127 deletions(-) diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index c35b092329781..13b080678217f 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -67,9 +67,6 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox verify_oop(Roop, FILE_AND_LINE); - // Load object header. - z_lg(Rmark, Address(Roop, hdr_offset)); - // Save object being locked into the BasicObjectLock... z_stg(Roop, Address(Rbox, BasicObjectLock::obj_offset())); @@ -85,6 +82,10 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox lightweight_lock(Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { NearLabel done; + + // Load object header. + z_lg(Rmark, Address(Roop, hdr_offset)); + // and mark it as unlocked. z_oill(Rmark, markWord::unlocked_value); // Save unlocked object header into the displaced header location on the stack. @@ -141,12 +142,7 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb verify_oop(Roop, FILE_AND_LINE); if (LockingMode == LM_LIGHTWEIGHT) { - const Register tmp = Z_R1_scratch; - z_lg(Rmark, Address(Roop, hdr_offset)); - z_lgr(tmp, Rmark); - z_nill(tmp, markWord::monitor_value); - branch_optimized(Assembler::bcondNotZero, slow_case); - lightweight_unlock(Roop, Rmark, tmp, slow_case); + lightweight_unlock(Roop, Rmark, Z_R1_scratch, slow_case); } else if (LockingMode == LM_LEGACY) { // Test if object header is pointing to the displaced header, and if so, restore // the displaced header in the object. If the object header is not pointing to diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 62c1bd943b69f..3641d82dabea9 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,15 @@ #define BLOCK_COMMENT(str) block_comment(str) #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") +void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2) { + compiler_fast_lock_lightweight_object(obj, temp1, temp2); +} + + +void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2) { + compiler_fast_unlock_lightweight_object(obj, temp1, temp2); +} + //------------------------------------------------------ // Special String Intrinsics. Implementation //------------------------------------------------------ diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp index a502e41ee08ee..aecb483f0a611 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,10 @@ // C2_MacroAssembler contains high-level macros for C2 public: + // Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in s390.ad file. + void fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2); + void fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2); + //------------------------------------------- // Special String Intrinsics Implementation. //------------------------------------------- diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index bc7996c270fa0..14bb98cea6ac3 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1005,9 +1005,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // markWord header = obj->mark().set_unlocked(); - // Load markWord from object into header. - z_lg(header, hdr_offset, object); - if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, object); testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); @@ -1015,9 +1012,12 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(object, /* mark word */ header, tmp, slow_case); + lightweight_lock(object, header, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { + // Load markWord from object into header. + z_lg(header, hdr_offset, object); + // Set header to be (markWord of object | UNLOCK_VALUE). // This will not change anything if it was unlocked before. z_oill(header, markWord::unlocked_value); @@ -1153,26 +1153,8 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) // If we still have a lightweight lock, unlock the object and be done. if (LockingMode == LM_LIGHTWEIGHT) { - // Check for non-symmetric locking. This is allowed by the spec and the interpreter - // must handle it. - - Register tmp = current_header; - - // First check for lock-stack underflow. - z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - compareU32_and_branch(tmp, (unsigned)LockStack::start_offset(), Assembler::bcondNotHigh, slow_case); - - // Then check if the top of the lock-stack matches the unlocked object. - z_aghi(tmp, -oopSize); - z_lg(tmp, Address(Z_thread, tmp)); - compare64_and_branch(tmp, object, Assembler::bcondNotEqual, slow_case); - - z_lg(header, Address(object, hdr_offset)); - z_lgr(tmp, header); - z_nill(tmp, markWord::monitor_value); - z_brne(slow_case); - lightweight_unlock(object, header, tmp, slow_case); + lightweight_unlock(object, header, current_header, slow_case); z_bru(done); } else { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 275f4a8d832e3..66d6f25f0fd4a 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3190,16 +3190,20 @@ void MacroAssembler::increment_counter_eq(address counter_address, Register tmp1 bind(l); } +// "The box" is the space on the stack where we copy the object mark. void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2) { + + assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_lock_lightweight"); + assert_different_registers(oop, box, temp1, temp2); + Register displacedHeader = temp1; - Register currentHeader = temp1; - Register temp = temp2; + Register currentHeader = temp1; + Register temp = temp2; + NearLabel done, object_has_monitor; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(temp1, temp2, oop, box); - BLOCK_COMMENT("compiler_fast_lock_object {"); // Load markWord from oop into mark. @@ -3207,8 +3211,10 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(temp, oop); - testbit(Address(temp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); - z_btrue(done); + z_l(temp, Address(temp, Klass::access_flags_offset())); + assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); + z_nilh(temp, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_brne(done); } // Handle existing monitor. @@ -3222,7 +3228,8 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis // From loading the markWord, we know that oop != nullptr z_ltgr(oop, oop); z_bru(done); - } else if (LockingMode == LM_LEGACY) { + } else { + assert(LockingMode == LM_LEGACY, "must be"); // Set mark to markWord | markWord::unlocked_value. z_oill(displacedHeader, markWord::unlocked_value); @@ -3251,10 +3258,6 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis z_stg(currentHeader/*==0 or not 0*/, BasicLock::displaced_header_offset_in_bytes(), box); - z_bru(done); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - lightweight_lock(oop, displacedHeader, temp, done); z_bru(done); } @@ -3270,10 +3273,9 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis // Otherwise, register zero is filled with the current owner. z_lghi(zero, 0); z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor_tagged); - if (LockingMode != LM_LIGHTWEIGHT) { - // Store a non-null value into the box. - z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); - } + + // Store a non-null value into the box. + z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); z_bre(done); // acquired the lock for the first time. @@ -3295,14 +3297,16 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis } void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2) { + + assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_unlock_lightweight"); + assert_different_registers(oop, box, temp1, temp2); + Register displacedHeader = temp1; - Register currentHeader = temp2; - Register temp = temp1; + Register currentHeader = temp2; + Register temp = temp1; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - assert_different_registers(temp1, temp2, oop, box); - Label done, object_has_monitor, not_recursive; BLOCK_COMMENT("compiler_fast_unlock_object {"); @@ -3326,18 +3330,14 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg // Set NE to indicate 'failure' -> take slow-path z_ltgr(oop, oop); z_bru(done); - } else if (LockingMode == LM_LEGACY) { + } else { + assert(LockingMode == LM_LEGACY, "must be"); // Check if it is still a lightweight lock, this is true if we see // the stack address of the basicLock in the markWord of the object // copy box to currentHeader such that csg does not kill it. z_lgr(currentHeader, box); z_csg(currentHeader, displacedHeader, hdr_offset, oop); z_bru(done); // csg sets CR as desired. - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - - lightweight_unlock(oop, currentHeader, displacedHeader, done); - z_bru(done); } // In case of LM_LIGHTWEIGHT, we may reach here with (temp & ObjectMonitor::ANONYMOUS_OWNER) != 0. @@ -5705,103 +5705,426 @@ SkipIfEqual::~SkipIfEqual() { } // Implements lightweight-locking. -// Branches to slow upon failure to lock the object. -// Falls through upon success. -// // - obj: the object to be locked, contents preserved. -// - hdr: the header, already loaded from obj, contents destroyed. +// - temp1, temp2: temporary registers, contents destroyed. // Note: make sure Z_R1 is not manipulated here when C2 compiler is in play -void MacroAssembler::lightweight_lock(Register obj, Register hdr, Register temp, Label& slow_case) { +void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register temp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, temp); + assert_different_registers(obj, temp1, temp2); + + Label push; + const Register top = temp1; + const Register mark = temp2; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); + + // Preload the markWord. It is important that this is the first + // instruction emitted as it is part of C1's null check semantics. + z_lg(mark, Address(obj, mark_offset)); + // First we need to check if the lock-stack has room for pushing the object reference. - z_lgf(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + z_lgf(top, Address(Z_thread, ls_top_offset)); - compareU32_and_branch(temp, (unsigned)LockStack::end_offset()-1, bcondHigh, slow_case); + compareU32_and_branch(top, (unsigned)LockStack::end_offset(), bcondNotLow, slow); - // attempting a lightweight_lock - // Load (object->mark() | 1) into hdr - z_oill(hdr, markWord::unlocked_value); + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. - z_lgr(temp, hdr); + // Check for recursion: + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + z_bre(push); - // Clear lock-bits from hdr (locked state) - z_xilf(temp, markWord::unlocked_value); + // Check header for monitor (0b10). + z_tmll(mark, markWord::monitor_value); + branch_optimized(bcondNotAllZero, slow); - z_csg(hdr, temp, oopDesc::mark_offset_in_bytes(), obj); - branch_optimized(Assembler::bcondNotEqual, slow_case); + { // Try to lock. Transition lock bits 0b01 => 0b00 + const Register locked_obj = top; + z_oill(mark, markWord::unlocked_value); + z_lgr(locked_obj, mark); + // Clear lock-bits from locked_obj (locked state) + z_xilf(locked_obj, markWord::unlocked_value); + z_csg(mark, locked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondNotEqual, slow); + } - // After successful lock, push object on lock-stack - z_lgf(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - z_stg(obj, Address(Z_thread, temp)); - z_ahi(temp, oopSize); - z_st(temp, Address(Z_thread, JavaThread::lock_stack_top_offset())); + bind(push); - // as locking was successful, set CC to EQ - z_cr(temp, temp); + // After successful lock, push object on lock-stack + z_lgf(top, Address(Z_thread, ls_top_offset)); + z_stg(obj, Address(Z_thread, top)); + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); } // Implements lightweight-unlocking. -// Branches to slow upon failure. -// Falls through upon success. -// // - obj: the object to be unlocked -// - hdr: the (pre-loaded) header of the object, will be destroyed +// - temp1, temp2: temporary registers, will be destroyed // - Z_R1_scratch: will be killed in case of Interpreter & C1 Compiler -void MacroAssembler::lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow) { +void MacroAssembler::lightweight_unlock(Register obj, Register temp1, Register temp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, hdr, tmp); + assert_different_registers(obj, temp1, temp2); + + Label unlocked, push_and_slow; + const Register mark = temp1; + const Register top = temp2; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); #ifdef ASSERT - { - // Check that hdr is lightweight-locked. - Label hdr_ok; - z_lgr(tmp, hdr); - z_nill(tmp, markWord::lock_mask_in_place); - z_bre(hdr_ok); - stop("Header is not lightweight-locked"); - bind(hdr_ok); - } { // The following checks rely on the fact that LockStack is only ever modified by // its owning thread, even if the lock got inflated concurrently; removal of LockStack // entries after inflation will happen delayed in that case. // Check for lock-stack underflow. - Label stack_ok; - z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - compareU32_and_branch(tmp, (unsigned)LockStack::start_offset(), Assembler::bcondHigh, stack_ok); + NearLabel stack_ok; + z_lgf(top, Address(Z_thread, ls_top_offset)); + compareU32_and_branch(top, (unsigned)LockStack::start_offset(), bcondNotLow, stack_ok); stop("Lock-stack underflow"); bind(stack_ok); } - { - // Check if the top of the lock-stack matches the unlocked object. - Label tos_ok; - z_aghi(tmp, -oopSize); - z_lg(tmp, Address(Z_thread, tmp)); - compare64_and_branch(tmp, obj, Assembler::bcondEqual, tos_ok); - stop("Top of lock-stack does not match the unlocked object"); - bind(tos_ok); +#endif // ASSERT + + // Check if obj is top of lock-stack. + z_lgf(top, Address(Z_thread, ls_top_offset)); + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + branch_optimized(bcondNotEqual, slow); + + // pop object from lock-stack +#ifdef ASSERT + const Register temp_top = temp1; // mark is not yet loaded, but be careful + z_agrk(temp_top, top, Z_thread); + z_xc(0, oopSize-1, temp_top, 0, temp_top); // wipe out lock-stack entry +#endif // ASSERT + z_alsi(in_bytes(ls_top_offset), Z_thread, -oopSize); // pop object + + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. + + // Check if recursive. (this is a check for the 2nd object on the stack) + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + branch_optimized(bcondEqual, unlocked); + + // Not recursive. Check header for monitor (0b10). + z_lg(mark, Address(obj, mark_offset)); + z_tmll(mark, markWord::monitor_value); + z_brnaz(push_and_slow); + +#ifdef ASSERT + // Check header not unlocked (0b01). + NearLabel not_unlocked; + z_tmll(mark, markWord::unlocked_value); + z_braz(not_unlocked); + stop("lightweight_unlock already unlocked"); + bind(not_unlocked); +#endif // ASSERT + + { // Try to unlock. Transition lock bits 0b00 => 0b01 + Register unlocked_obj = top; + z_lgr(unlocked_obj, mark); + z_oill(unlocked_obj, markWord::unlocked_value); + z_csg(mark, unlocked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondEqual, unlocked); + } + + bind(push_and_slow); + + // Restore lock-stack and handle the unlock in runtime. + z_lgf(top, Address(Z_thread, ls_top_offset)); + DEBUG_ONLY(z_stg(obj, Address(Z_thread, top));) + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); + // set CC to NE + z_ltgr(obj, obj); // object shouldn't be null at this point + branch_optimized(bcondAlways, slow); + + bind(unlocked); +} + +void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2) { + assert_different_registers(obj, tmp1, tmp2); + + // Handle inflated monitor. + NearLabel inflated; + // Finish fast lock successfully. MUST reach to with flag == NE + NearLabel locked; + // Finish fast lock unsuccessfully. MUST branch to with flag == EQ + NearLabel slow_path; + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp1, obj); + z_l(tmp1, Address(tmp1, Klass::access_flags_offset())); + assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); + z_nilh(tmp1, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_brne(slow_path); + } + + const Register mark = tmp1; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); + + BLOCK_COMMENT("compiler_fast_lightweight_locking {"); + { // lightweight locking + + // Push lock to the lock stack and finish successfully. MUST reach to with flag == EQ + NearLabel push; + + const Register top = tmp2; + + // Check if lock-stack is full. + z_lgf(top, Address(Z_thread, ls_top_offset)); + compareU32_and_branch(top, (unsigned) LockStack::end_offset() - 1, bcondHigh, slow_path); + + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. + + // Check if recursive. + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + z_bre(push); + + // Check for monitor (0b10) + z_lg(mark, Address(obj, mark_offset)); + z_tmll(mark, markWord::monitor_value); + z_brnaz(inflated); + + // not inflated + + { // Try to lock. Transition lock bits 0b01 => 0b00 + assert(mark_offset == 0, "required to avoid a lea"); + const Register locked_obj = top; + z_oill(mark, markWord::unlocked_value); + z_lgr(locked_obj, mark); + // Clear lock-bits from locked_obj (locked state) + z_xilf(locked_obj, markWord::unlocked_value); + z_csg(mark, locked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondNotEqual, slow_path); + } + + bind(push); + + // After successful lock, push object on lock-stack. + z_lgf(top, Address(Z_thread, ls_top_offset)); + z_stg(obj, Address(Z_thread, top)); + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); + + z_cgr(obj, obj); // set the CC to EQ, as it could be changed by alsi + z_bru(locked); + } + BLOCK_COMMENT("} compiler_fast_lightweight_locking"); + + BLOCK_COMMENT("handle_inflated_monitor_lightweight_locking {"); + { // Handle inflated monitor. + bind(inflated); + + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const Register zero = tmp2; + + // Try to CAS m->owner from null to current thread. + // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); + z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); + z_bre(locked); + + // Check if recursive. + z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction + z_brne(slow_path); + + // Recursive + z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); + z_cgr(zero, zero); + // z_bru(locked); + // Uncomment above line in the future, for now jump address is right next to us. } + BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking"); + + bind(locked); + +#ifdef ASSERT + // Check that locked label is reached with flag == EQ. + NearLabel flag_correct; + z_bre(flag_correct); + stop("CC is not set to EQ, it should be - lock"); +#endif // ASSERT + + bind(slow_path); + +#ifdef ASSERT + // Check that slow_path label is reached with flag == NE. + z_brne(flag_correct); + stop("CC is not set to NE, it should be - lock"); + bind(flag_correct); #endif // ASSERT - z_lgr(tmp, hdr); - z_oill(tmp, markWord::unlocked_value); - z_csg(hdr, tmp, oopDesc::mark_offset_in_bytes(), obj); - branch_optimized(Assembler::bcondNotEqual, slow); + // C2 uses the value of flag (NE vs EQ) to determine the continuation. +} + +void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2) { + assert_different_registers(obj, tmp1, tmp2); - // After successful unlock, pop object from lock-stack + // Handle inflated monitor. + NearLabel inflated, inflated_load_monitor; + // Finish fast unlock successfully. MUST reach to with flag == EQ. + NearLabel unlocked; + // Finish fast unlock unsuccessfully. MUST branch to with flag == NE. + NearLabel slow_path; + + const Register mark = tmp1; + const Register top = tmp2; + const int mark_offset = oopDesc::mark_offset_in_bytes(); + const ByteSize ls_top_offset = JavaThread::lock_stack_top_offset(); + + BLOCK_COMMENT("compiler_fast_lightweight_unlock {"); + { // Lightweight Unlock + + // Check if obj is top of lock-stack. + z_lgf(top, Address(Z_thread, ls_top_offset)); + + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + branch_optimized(bcondNotEqual, inflated_load_monitor); + + // Pop lock-stack. #ifdef ASSERT - z_lgf(tmp, Address(Z_thread, JavaThread::lock_stack_top_offset())); - z_aghi(tmp, -oopSize); - z_agr(tmp, Z_thread); - z_xc(0, oopSize-1, tmp, 0, tmp); // wipe out lock-stack entry + const Register temp_top = tmp1; // let's not kill top here, we can use for recursive check + z_agrk(temp_top, top, Z_thread); + z_xc(0, oopSize-1, temp_top, 0, temp_top); // wipe out lock-stack entry #endif - z_alsi(in_bytes(JavaThread::lock_stack_top_offset()), Z_thread, -oopSize); // pop object - z_cr(tmp, tmp); // set CC to EQ + z_alsi(in_bytes(ls_top_offset), Z_thread, -oopSize); // pop object + + // The underflow check is elided. The recursive check will always fail + // when the lock stack is empty because of the _bad_oop_sentinel field. + + // Check if recursive. + z_aghi(top, -oopSize); + z_cg(obj, Address(Z_thread, top)); + z_bre(unlocked); + + // Not recursive + + // Check for monitor (0b10). + z_lg(mark, Address(obj, mark_offset)); + z_tmll(mark, markWord::monitor_value); + z_brnaz(inflated); + +#ifdef ASSERT + // Check header not unlocked (0b01). + NearLabel not_unlocked; + z_tmll(mark, markWord::unlocked_value); + z_braz(not_unlocked); + stop("lightweight_unlock already unlocked"); + bind(not_unlocked); +#endif // ASSERT + + { // Try to unlock. Transition lock bits 0b00 => 0b01 + Register unlocked_obj = top; + z_lgr(unlocked_obj, mark); + z_oill(unlocked_obj, markWord::unlocked_value); + z_csg(mark, unlocked_obj, mark_offset, obj); + branch_optimized(Assembler::bcondEqual, unlocked); + } + + // Restore lock-stack and handle the unlock in runtime. + z_lgf(top, Address(Z_thread, ls_top_offset)); + DEBUG_ONLY(z_stg(obj, Address(Z_thread, top));) + z_alsi(in_bytes(ls_top_offset), Z_thread, oopSize); + // set CC to NE + z_ltgr(obj, obj); // object is not null here + z_bru(slow_path); + } + BLOCK_COMMENT("} compiler_fast_lightweight_unlock"); + + { // Handle inflated monitor. + + bind(inflated_load_monitor); + + z_lg(mark, Address(obj, mark_offset)); + +#ifdef ASSERT + z_tmll(mark, markWord::monitor_value); + z_brnaz(inflated); + stop("Fast Unlock not monitor"); +#endif // ASSERT + + bind(inflated); + +#ifdef ASSERT + NearLabel check_done, loop; + z_lgf(top, Address(Z_thread, ls_top_offset)); + bind(loop); + z_aghi(top, -oopSize); + compareU32_and_branch(top, in_bytes(JavaThread::lock_stack_base_offset()), + bcondLow, check_done); + z_cg(obj, Address(Z_thread, top)); + z_brne(loop); + stop("Fast Unlock lock on stack"); + bind(check_done); +#endif // ASSERT + + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; + + NearLabel not_recursive; + const Register recursions = tmp2; + + // Check if recursive. + load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking + + // Recursive unlock + z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); + z_cgr(monitor, monitor); // set the CC to EQUAL + z_bru(unlocked); + + bind(not_recursive); + + NearLabel not_ok; + // Check if the entry lists are empty. + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + z_brne(not_ok); + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + z_brne(not_ok); + + z_release(); + z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + + z_bru(unlocked); // CC = EQ here + + bind(not_ok); + + // The owner may be anonymous, and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + z_bru(slow_path); // CC = NE here + } + + bind(unlocked); + +#ifdef ASSERT + // Check that unlocked label is reached with flag == EQ. + NearLabel flag_correct; + z_bre(flag_correct); + stop("CC is not set to EQ, it should be - unlock"); +#endif // ASSERT + + bind(slow_path); + +#ifdef ASSERT + // Check that slow_path label is reached with flag == NE. + z_brne(flag_correct); + stop("CC is not set to NE, it should be - unlock"); + bind(flag_correct); +#endif // ASSERT + + // C2 uses the value of flag (NE vs EQ) to determine the continuation. } void MacroAssembler::pop_count_int(Register r_dst, Register r_src, Register r_tmp) { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 9f45542dd65cf..684741d79db2f 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -727,8 +727,10 @@ class MacroAssembler: public Assembler { void compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2); void compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2); - void lightweight_lock(Register obj, Register hdr, Register tmp, Label& slow); - void lightweight_unlock(Register obj, Register hdr, Register tmp, Label& slow); + void lightweight_lock(Register obj, Register tmp1, Register tmp2, Label& slow); + void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Label& slow); + void compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2); + void compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2); void resolve_jobject(Register value, Register tmp1, Register tmp2); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 56cf494d27e0a..0fe3840b9b53c 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -9579,6 +9579,7 @@ instruct partialSubtypeCheck_vs_zero(flagsReg pcc, rarg2RegP sub, rarg3RegP supe // inlined locking and unlocking instruct cmpFastLock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode != LM_LIGHTWEIGHT); match(Set pcc (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2); ins_cost(100); @@ -9589,6 +9590,7 @@ instruct cmpFastLock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRe %} instruct cmpFastUnlock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode != LM_LIGHTWEIGHT); match(Set pcc (FastUnlock oop box)); effect(TEMP tmp1, TEMP tmp2); ins_cost(100); @@ -9598,6 +9600,38 @@ instruct cmpFastUnlock(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, i ins_pipe(pipe_class_dummy); %} +instruct cmpFastLockLightweight(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set pcc (FastLock oop box)); + effect(TEMP tmp1, TEMP tmp2); + ins_cost(100); + // TODO: s390 port size(VARIABLE_SIZE); + format %{ "FASTLOCK $oop, $box; KILL Z_ARG4, Z_ARG5" %} + ins_encode %{ + __ fast_lock_lightweight($oop$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); + // If locking was successful, cc should indicate 'EQ'. + // The compiler generates a branch to the runtime call to + // _complete_monitor_locking_Java for the case where cc is 'NE'. + %} + ins_pipe(pipe_class_dummy); +%} + +instruct cmpFastUnlockLightweight(flagsReg pcc, iRegP_N2P oop, iRegP_N2P box, iRegP tmp1, iRegP tmp2) %{ + predicate(LockingMode == LM_LIGHTWEIGHT); + match(Set pcc (FastUnlock oop box)); + effect(TEMP tmp1, TEMP tmp2); + ins_cost(100); + // TODO: s390 port size(FIXED_SIZE); + format %{ "FASTUNLOCK $oop, $box; KILL Z_ARG4, Z_ARG5" %} + ins_encode %{ + __ fast_unlock_lightweight($oop$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); + // If unlocking was successful, cc should indicate 'EQ'. + // The compiler generates a branch to the runtime call to + // _complete_monitor_unlocking_Java for the case where cc is 'NE'. + %} + ins_pipe(pipe_class_dummy); +%} + instruct inlineCallClearArrayConst(SSlenDW cnt, iRegP_N2P base, Universe dummy, flagsReg cr) %{ match(Set dummy (ClearArray cnt base)); effect(KILL cr); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 87cf9cb600cb4..0ee88345282b7 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1711,8 +1711,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ add2reg(r_box, lock_offset, Z_SP); // Try fastpath for locking. - // Fast_lock kills r_temp_1, r_temp_2. - __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); + if (LockingMode == LM_LIGHTWEIGHT) { + // Fast_lock kills r_temp_1, r_temp_2. + __ compiler_fast_lock_lightweight_object(r_oop, r_tmp1, r_tmp2); + } else { + // Fast_lock kills r_temp_1, r_temp_2. + __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); + } __ z_bre(done); //------------------------------------------------------------------------- @@ -1910,8 +1915,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ add2reg(r_box, lock_offset, Z_SP); // Try fastpath for unlocking. - // Fast_unlock kills r_tmp1, r_tmp2. - __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); + if (LockingMode == LM_LIGHTWEIGHT) { + // Fast_unlock kills r_tmp1, r_tmp2. + __ compiler_fast_unlock_lightweight_object(r_oop, r_tmp1, r_tmp2); + } else { + // Fast_unlock kills r_tmp1, r_tmp2. + __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); + } __ z_bre(done); // Slow path for unlocking. diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 7ac60a10ae7f8..4f963c4e4851a 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -413,6 +413,8 @@ class VM_Version: public Abstract_VM_Version { // s390 supports fast class initialization checks static bool supports_fast_class_init_checks() { return true; } + constexpr static bool supports_recursive_lightweight_locking() { return true; } + // CPU feature query functions static const char* get_model_string() { return _model_string; } static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; } From 3b3a19e907c7267f03c0b07312b929b7b4b6d200 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 28 Jun 2024 08:27:07 +0000 Subject: [PATCH 092/288] 8335314: Problem list compiler/uncommontrap/DeoptReallocFailure.java Reviewed-by: chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 254e621bfdd47..febde61c4fda1 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -70,6 +70,8 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all +compiler/uncommontrap/DeoptReallocFailure.java 8335308 windows-x64 + ############################################################################# # :hotspot_gc From 6f4ddc2f6bf0dd9a626a76d0f5e56a54c6cf6b65 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 28 Jun 2024 09:23:48 +0000 Subject: [PATCH 093/288] 8335142: compiler/c1/TestTraceLinearScanLevel.java occasionally times out with -Xcomp Reviewed-by: thartmann, kvn --- test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java b/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java index 2e4ec32869dc9..46a294388e6c9 100644 --- a/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java +++ b/test/hotspot/jtreg/compiler/c1/TestTraceLinearScanLevel.java @@ -26,8 +26,8 @@ * @bug 8251093 * @summary Sanity check the flag TraceLinearScanLevel with the highest level in a silent HelloWorld program. * - * @requires vm.debug == true & vm.compiler1.enabled - * @run main/othervm -XX:TraceLinearScanLevel=4 compiler.c1.TestTraceLinearScanLevel + * @requires vm.debug == true & vm.compiler1.enabled & vm.compMode != "Xcomp" + * @run main/othervm -Xbatch -XX:TraceLinearScanLevel=4 compiler.c1.TestTraceLinearScanLevel */ package compiler.c1; From 99d2bbf767ac33e1a021c90ba12d95ef37ea4816 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 28 Jun 2024 09:31:14 +0000 Subject: [PATCH 094/288] 8334433: jshell.exe runs an executable test.exe on startup Reviewed-by: jpai --- .../jdk/internal/org/jline/utils/OSUtils.java | 2 +- .../jshell/tool/ConsoleIOContext.java | 7 +- .../jdk/jshell/TerminalNoExecTest.java | 96 +++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/langtools/jdk/jshell/TerminalNoExecTest.java diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java index 344d081c12486..7fdfb9a028fc9 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java @@ -63,7 +63,7 @@ private static boolean isExecutable(File f) { String sttyfopt = null; String infocmp = null; String test = null; - String path = System.getenv("PATH"); + String path = "/usr/bin" + File.pathSeparator + "/bin";//was: System.getenv("PATH"); if (path != null) { String[] paths = path.split(File.pathSeparator); for (String p : paths) { diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index a2b1ca0d2d058..f4ca58d6af438 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -154,7 +154,12 @@ public int readBuffered(byte[] b) throws IOException { setupReader = setupReader.andThen(r -> r.option(Option.DISABLE_HIGHLIGHTER, !enableHighlighter)); input.setInputStream(cmdin); } else { - terminal = TerminalBuilder.builder().inputStreamWrapper(in -> { + //on platforms which are known to be fully supported by + //the FFMTerminalProvider, do not permit the ExecTerminalProvider: + boolean allowExecTerminal = !OSUtils.IS_WINDOWS && + !OSUtils.IS_LINUX && + !OSUtils.IS_OSX; + terminal = TerminalBuilder.builder().exec(allowExecTerminal).inputStreamWrapper(in -> { input.setInputStream(in); return nonBlockingInput; }).nativeSignals(false).build(); diff --git a/test/langtools/jdk/jshell/TerminalNoExecTest.java b/test/langtools/jdk/jshell/TerminalNoExecTest.java new file mode 100644 index 0000000000000..3d76157fd26f0 --- /dev/null +++ b/test/langtools/jdk/jshell/TerminalNoExecTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8334433 + * @summary Verify that when running JShell on platforms that support FFMTerminalProvider, + * no new processes are spawned. + * @requires os.family == "windows" | os.family == "mac" | os.family == "linux" + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavaTask TerminalNoExecTest + * @run main TerminalNoExecTest + */ + +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import jdk.jfr.consumer.RecordingStream; +import jdk.jshell.tool.JavaShellToolBuilder; + +import toolbox.ToolBox; + +public class TerminalNoExecTest { + + public static void main(String... args) throws Exception { + if (args.length > 0) { + AtomicBoolean spawnedNewProcess = new AtomicBoolean(); + try (var rs = new RecordingStream()) { + rs.enable("jdk.ProcessStart").withoutThreshold(); + rs.onEvent(evt -> { + System.err.println("evt: " + evt); + spawnedNewProcess.set(true); + }); + rs.startAsync(); + JavaShellToolBuilder.builder().run("--execution=local", "--no-startup"); + rs.stop(); + } + if (spawnedNewProcess.get()) { + System.err.println("Spawned a new process!"); + System.exit(1); + } + System.exit(0); + } else { + Path testScript = Paths.get("do-exit"); + try (Writer w = Files.newBufferedWriter(testScript)) { + w.append("/exit\n"); + } + + ToolBox tb = new ToolBox(); + Process target = + new ProcessBuilder(tb.getJDKTool("java").toString(), + "-classpath", System.getProperty("java.class.path"), + TerminalNoExecTest.class.getName(), + "run-test") + .redirectError(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectInput(testScript.toFile()) + .start(); + + target.waitFor(); + + int exitCode = target.exitValue(); + + if (exitCode != 0) { + throw new AssertionError("Incorrect exit value, expected 0, got: " + exitCode); + } + } + } + +} From c798316bc4cb33fd902f926030d8a0b6870d661a Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 28 Jun 2024 09:38:18 +0000 Subject: [PATCH 095/288] 8269657: Test java/nio/channels/DatagramChannel/Loopback.java failed: Unexpected message Reviewed-by: dfuchs --- .../nio/channels/DatagramChannel/Loopback.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/Loopback.java b/test/jdk/java/nio/channels/DatagramChannel/Loopback.java index a61a4d0b17721..5562378b83f1d 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Loopback.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Loopback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,8 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) // send datagram to multicast group System.out.format("send %s -> %s%n", dc.getLocalAddress(), target); - ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8")); + String str = "hello " + System.nanoTime(); + ByteBuffer src = ByteBuffer.wrap(str.getBytes("UTF-8")); dc.send(src, target); // receive datagram sent to multicast group @@ -142,6 +143,7 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) System.out.format("send %s -> %s%n", dc.getLocalAddress(), target); src.clear(); dc.send(src, target); + src.flip(); // test that we don't receive the datagram sent to multicast group dc.configureBlocking(false); @@ -157,10 +159,16 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) } else { sel.selectedKeys().clear(); SocketAddress sender = dc.receive(dst); + if (src.mismatch(dst) != -1) { + System.out.println("src: " + src + "not equal to dst: " + dst); + dst.clear(); + continue; + } if (sender != null) { System.out.format("received %s from %s%n", dst, sender); senderPort = ((InetSocketAddress) sender).getPort(); - assertTrue(senderPort != localPort, "Unexpected message"); + assertTrue(senderPort != localPort, + "Unexpected message: localPort=" + localPort); } } } From 8ec378a6c8a460dd0727df800419b3cf45d3c57a Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 28 Jun 2024 11:03:29 +0000 Subject: [PATCH 096/288] 8277949: (dc) java/nio/channels/DatagramChannel/AdaptorBasic.java failed in timeout Reviewed-by: jpai --- .../DatagramChannel/AdaptorBasic.java | 40 ++++++++++++++++--- test/jdk/java/nio/channels/TestServers.java | 31 ++++++++++++-- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java index 4ac5d4b3c8885..504b648dcb6dc 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,8 @@ import java.util.*; import java.lang.reflect.Field; +import jdk.test.lib.Platform; + public class AdaptorBasic { @@ -69,6 +71,8 @@ static void test(DatagramSocket ds, InetSocketAddress dst, boolean shouldTimeout for (;;) { try { ds.receive(ip); + // weed off stray datagrams + if (ip.getPort() != dst.getPort()) continue; } catch (SocketTimeoutException x) { if (shouldTimeout) { out.println("Receive timed out, as expected"); @@ -111,12 +115,36 @@ static void test(InetSocketAddress dst, // Original ds = new DatagramSocket(); } else { - DatagramChannel dc = DatagramChannel.open(); - ds = dc.socket(); - ds.bind(new InetSocketAddress(0)); + int attempts = 0; + DatagramChannel toclose = null; + while (true) { + DatagramChannel dc = DatagramChannel.open(); + ds = dc.socket(); + if (Platform.isOSX() && dst.getAddress().isLoopbackAddress()) { + // avoid binding to the wildcard on macOS if possible, in order to limit + // potential port conflict issues + ds.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + } else { + ds.bind(new InetSocketAddress(0)); + } + // on some systems it may be possible to bind two sockets + // to the same port if one of them is bound to the wildcard, + // if that happens, try again... + if (ds.getLocalPort() == dst.getPort()) { + if (toclose != null) toclose.close(); + toclose = dc; + if (++attempts == 10) { + throw new AssertionError("Couldn't allocate port for client socket"); + } + continue; + } + if (toclose != null) toclose.close(); + break; + } } - out.println("socket: " + ds); + out.println("socket: " + ds + " bound to src: " + + ds.getLocalSocketAddress() + ", dst: " + dst); if (connect) { ds.connect(dst); out.println("connect: " + ds); @@ -141,7 +169,7 @@ static void test(InetSocketAddress dst, public static void main(String[] args) throws Exception { // need an UDP echo server try (TestServers.UdpEchoServer echoServer - = TestServers.UdpEchoServer.startNewServer(100)) { + = TestServers.UdpEchoServer.startNewServer(100, InetAddress.getLoopbackAddress())) { final InetSocketAddress address = new InetSocketAddress(echoServer.getAddress(), echoServer.getPort()); diff --git a/test/jdk/java/nio/channels/TestServers.java b/test/jdk/java/nio/channels/TestServers.java index e2c4151195dcf..4f459c439f573 100644 --- a/test/jdk/java/nio/channels/TestServers.java +++ b/test/jdk/java/nio/channels/TestServers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -497,6 +497,7 @@ static abstract class AbstractUdpServer extends AbstractServer implements Runnable, Closeable { protected final long linger; // #of ms to wait before responding + protected final InetAddress bindAddress; //local address to bind to; can be null. private Thread acceptThread; // thread waiting for packets private DatagramSocket serverSocket; // the server socket private boolean started = false; // whether the server is started @@ -509,7 +510,20 @@ static abstract class AbstractUdpServer extends AbstractServer * responding to requests. */ protected AbstractUdpServer(long linger) { + this(linger, null); + } + + /** + * Creates a new abstract UDP server. + * + * @param linger the amount of time the server should wait before + * responding to requests. + * @param bindAddress the address to bind to. If {@code null}, will + * bind to InetAddress.getLocalHost(); + */ + protected AbstractUdpServer(long linger, InetAddress bindAddress) { this.linger = linger; + this.bindAddress = bindAddress; } /** @@ -574,8 +588,9 @@ public final synchronized void start() throws IOException { if (started) { return; } + InetAddress lh = bindAddress == null ? InetAddress.getLocalHost() : bindAddress; final DatagramSocket socket = - newDatagramSocket(0, InetAddress.getLocalHost()); + newDatagramSocket(0, lh); serverSocket = socket; acceptThread = new Thread(this); acceptThread.setDaemon(true); @@ -759,7 +774,11 @@ public UdpEchoServer() { } public UdpEchoServer(long linger) { - super(linger); + this(linger, null); + } + + public UdpEchoServer(long linger, InetAddress bindAddress) { + super(linger, bindAddress); } @Override @@ -795,7 +814,11 @@ public static UdpEchoServer startNewServer() throws IOException { } public static UdpEchoServer startNewServer(long linger) throws IOException { - final UdpEchoServer echoServer = new UdpEchoServer(linger); + return startNewServer(0, InetAddress.getLocalHost()); + } + + public static UdpEchoServer startNewServer(long linger, InetAddress bindAddress) throws IOException { + final UdpEchoServer echoServer = new UdpEchoServer(linger, bindAddress); echoServer.start(); return echoServer; } From 49eb00da8dc66cff3ca430f06ab21357ee6180ef Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 28 Jun 2024 11:13:11 +0000 Subject: [PATCH 097/288] 8299813: java/nio/channels/DatagramChannel/Disconnect.java fails with jtreg test timeout due to lost datagram Reviewed-by: aefimov --- .../channels/DatagramChannel/Disconnect.java | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java index 1ba742b655241..cdc5882fefd9d 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.nio.*; import java.nio.channels.*; import java.io.IOException; + import jdk.test.lib.net.IPSupport; public class Disconnect { @@ -42,43 +43,61 @@ public static void main(String[] args) throws IOException { // test with default protocol family try (DatagramChannel dc = DatagramChannel.open()) { - test(dc); - test(dc); + InetAddress lo = InetAddress.getLoopbackAddress(); + System.out.println("Testing with default family and " + lo); + test(dc, lo); + test(dc, lo); } if (IPSupport.hasIPv4()) { // test with IPv4 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { - test(dc); - test(dc); + InetAddress lo4 = InetAddress.ofLiteral("127.0.0.1"); + System.out.println("Testing with INET family and " + lo4); + test(dc, lo4); + test(dc, lo4); } } if (IPSupport.hasIPv6()) { // test with IPv6 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { - test(dc); - test(dc); + InetAddress lo6 = InetAddress.ofLiteral("::1"); + System.out.println("Testing with INET6 family and " + lo6); + test(dc, lo6); + test(dc, lo6); } } } + static int getLocalPort(DatagramChannel ch) throws IOException { + return ((InetSocketAddress) ch.getLocalAddress()).getPort(); + } + /** * Connect DatagramChannel to a server, write a datagram and disconnect. Invoke * a second or subsequent time with the same DatagramChannel instance to check * that disconnect works as expected. */ - static void test(DatagramChannel dc) throws IOException { + static void test(DatagramChannel dc, InetAddress lo) throws IOException { try (DatagramChannel server = DatagramChannel.open()) { - server.bind(new InetSocketAddress(0)); + server.bind(new InetSocketAddress(lo, 0)); - InetAddress lh = InetAddress.getLocalHost(); - dc.connect(new InetSocketAddress(lh, server.socket().getLocalPort())); + SocketAddress dcbound = dc.getLocalAddress(); + dc.connect(new InetSocketAddress(lo, server.socket().getLocalPort())); + System.out.println("dc bound to " + dcbound + " and connected from " + + dc.getLocalAddress() + " to " + dc.getRemoteAddress()); dc.write(ByteBuffer.wrap("hello".getBytes())); - ByteBuffer bb = ByteBuffer.allocate(100); - server.receive(bb); + if (getLocalPort(dc) != getLocalPort(server)) { + ByteBuffer bb = ByteBuffer.allocate(100); + server.receive(bb); + } else { + // some systems may allow dc and server to bind to the same port. + // when that happen the datagram may never be received + System.out.println("Server and clients are bound to the same port: skipping receive"); + } dc.disconnect(); From f4d8c005b35ce34c96027b7f3abb7a307bca3f4c Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Fri, 28 Jun 2024 12:45:26 +0000 Subject: [PATCH 098/288] 8334562: Automate com/sun/security/auth/callback/TextCallbackHandler/Default.java test Reviewed-by: weijun --- test/jdk/ProblemList.txt | 1 - test/jdk/TEST.groups | 1 - .../callback/TextCallbackHandler/Default.java | 55 +++-- .../testlibrary/HumanInputStream.java | 192 ++++++++++++++++++ .../security/tools/keytool/KeyToolTest.java | 173 +--------------- 5 files changed, 231 insertions(+), 191 deletions(-) create mode 100644 test/jdk/java/security/testlibrary/HumanInputStream.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 790b3de0f969c..20dfcef539de3 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -609,7 +609,6 @@ sun/security/smartcardio/TestMultiplePresent.java 8039280 generic- sun/security/smartcardio/TestPresent.java 8039280 generic-all sun/security/smartcardio/TestTransmit.java 8039280 generic-all com/sun/crypto/provider/Cipher/DES/PerformanceTest.java 8039280 generic-all -com/sun/security/auth/callback/TextCallbackHandler/Default.java 8039280 generic-all com/sun/security/auth/callback/TextCallbackHandler/Password.java 8039280 generic-all com/sun/security/sasl/gsskerb/AuthOnly.java 8039280 generic-all com/sun/security/sasl/gsskerb/ConfSecurityLayer.java 8039280 generic-all diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 0a8d27484652a..6a5be3736e859 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -624,7 +624,6 @@ jdk_security_manual_no_input = \ com/sun/crypto/provider/Cipher/DES/PerformanceTest.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java \ - com/sun/security/auth/callback/TextCallbackHandler/Default.java \ com/sun/security/auth/callback/TextCallbackHandler/Password.java \ com/sun/security/sasl/gsskerb/AuthOnly.java \ com/sun/security/sasl/gsskerb/ConfSecurityLayer.java \ diff --git a/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java b/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java index 606a1ad5e0e1a..1fb3350c8f7ea 100644 --- a/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java +++ b/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Default.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * 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,31 +23,48 @@ /* * @test + * @library /test/lib /java/security/testlibrary * @bug 4470717 * @summary fix default handling and other misc - * @run main/manual Default + * @run main/othervm Default */ import com.sun.security.auth.callback.TextCallbackHandler; +import jdk.test.lib.Asserts; + import javax.security.auth.callback.*; +import java.io.*; public class Default { - public static void main(String args[]) throws Exception { - TextCallbackHandler h = new TextCallbackHandler(); - NameCallback nc = new NameCallback("Name: ", "charlie"); - ConfirmationCallback cc = new ConfirmationCallback - ("Correct?", - ConfirmationCallback.INFORMATION, - ConfirmationCallback.YES_NO_OPTION, - ConfirmationCallback.NO); - - Callback[] callbacks = { nc, cc }; - h.handle(callbacks); - - if (cc.getSelectedIndex() == ConfirmationCallback.YES) { - System.out.println("yes"); - } else { - System.out.println("no"); + public static void main(String args[]) throws Exception { + InputStream in = System.in; + PrintStream err = System.err; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final String defaultName = "charlie"; + final String simulatedInput = "-1\n-1\n"; + HumanInputStream humanInputStream = new HumanInputStream(simulatedInput); + + try (PrintStream prints = new PrintStream(baos)) { + System.setIn(humanInputStream); + System.setErr(prints); + NameCallback nameCallback = new NameCallback("Name: ", defaultName); + ConfirmationCallback confirmationCallback = new ConfirmationCallback( + "Correct?", + ConfirmationCallback.INFORMATION, + ConfirmationCallback.YES_NO_OPTION, + ConfirmationCallback.NO); + new TextCallbackHandler().handle(new Callback[]{nameCallback, confirmationCallback}); + + Asserts.assertEquals(nameCallback.getDefaultName(), defaultName); + Asserts.assertEquals(confirmationCallback.getSelectedIndex(), ConfirmationCallback.NO); + + } finally { + System.setIn(in); + System.setErr(err); } - } + + // check that the default name and confirmation were visible in the output + Asserts.assertTrue(baos.toString().contains(String.format("Name: [%s]", defaultName))); + Asserts.assertTrue(baos.toString().contains("1. No [default]")); + } } diff --git a/test/jdk/java/security/testlibrary/HumanInputStream.java b/test/jdk/java/security/testlibrary/HumanInputStream.java new file mode 100644 index 0000000000000..50e5dd0bcc8c4 --- /dev/null +++ b/test/jdk/java/security/testlibrary/HumanInputStream.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * HumanInputStream tries to act like a human sitting in front of a computer + * terminal typing on the keyboard while a program is running. + *

    + * The program may call InputStream.read() and BufferedReader.readLine() in + * various places. a call to B.readLine() will try to buffer as much input as + * possible. Thus, a trivial InputStream will find it impossible to feed + * anything to I.read() after a B.readLine() call. + *

    + * This is why HumanInputStream was created, which will only send a single line + * to B.readLine(), no more, no less, and the next I.read() can have a chance + * to read the exact character right after "\n". + * + */ + +public class HumanInputStream extends InputStream { + byte[] src; + int pos; + int length; + boolean inLine; + int stopIt; + + public HumanInputStream(String input) { + src = input.getBytes(); + pos = 0; + length = src.length; + stopIt = 0; + inLine = false; + } + + // the trick: when called through read(byte[], int, int), + // return -1 twice after "\n" + + @Override public int read() throws IOException { + int re; + if(pos < length) { + re = src[pos]; + if(inLine) { + if(stopIt > 0) { + stopIt--; + re = -1; + } else { + if(re == '\n') { + stopIt = 2; + } + pos++; + } + } else { + pos++; + } + } else { + re = -1; //throws new IOException("NO MORE TO READ"); + } + return re; + } + @Override public int read(byte[] buffer, int offset, int len) { + inLine = true; + try { + return super.read(buffer, offset, len); + } catch(Exception e) { + throw new RuntimeException("HumanInputStream error"); + } finally { + inLine = false; + } + } + @Override public int available() { + if (pos < length) return 1; + return 0; + } + + // test part + static void assertTrue(boolean bool) { + if (!bool) + throw new RuntimeException(); + } + + public static void test() throws Exception { + class Tester { + HumanInputStream is; + BufferedReader reader; + Tester(String s) { + is = new HumanInputStream(s); + reader = new BufferedReader(new InputStreamReader(is)); + } + + // three kinds of test method + // 1. read byte by byte from InputStream + void testStreamReadOnce(int expection) throws Exception { + assertTrue(is.read() == expection); + } + void testStreamReadMany(String expectation) throws Exception { + char[] keys = expectation.toCharArray(); + for (char key : keys) { + assertTrue(is.read() == key); + } + } + // 2. read a line with a newly created Reader + void testReaderReadline(String expectation) throws Exception { + String s = new BufferedReader(new InputStreamReader(is)).readLine(); + if(s == null) assertTrue(expectation == null); + else assertTrue(s.equals(expectation)); + } + // 3. read a line with the old Reader + void testReaderReadline2(String expectation) throws Exception { + String s = reader.readLine(); + if(s == null) assertTrue(expectation == null); + else assertTrue(s.equals(expectation)); + } + } + + Tester test; + + test = new Tester("111\n222\n\n444\n\n"); + test.testReaderReadline("111"); + test.testReaderReadline("222"); + test.testReaderReadline(""); + test.testReaderReadline("444"); + test.testReaderReadline(""); + test.testReaderReadline(null); + + test = new Tester("111\n222\n\n444\n\n"); + test.testReaderReadline2("111"); + test.testReaderReadline2("222"); + test.testReaderReadline2(""); + test.testReaderReadline2("444"); + test.testReaderReadline2(""); + test.testReaderReadline2(null); + + test = new Tester("111\n222\n\n444\n\n"); + test.testReaderReadline2("111"); + test.testReaderReadline("222"); + test.testReaderReadline2(""); + test.testReaderReadline2("444"); + test.testReaderReadline(""); + test.testReaderReadline2(null); + + test = new Tester("1\n2"); + test.testStreamReadMany("1\n2"); + test.testStreamReadOnce(-1); + + test = new Tester("12\n234"); + test.testStreamReadOnce('1'); + test.testReaderReadline("2"); + test.testStreamReadOnce('2'); + test.testReaderReadline2("34"); + test.testReaderReadline2(null); + + test = new Tester("changeit\n"); + test.testStreamReadMany("changeit\n"); + test.testReaderReadline(null); + + test = new Tester("changeit\nName\nCountry\nYes\n"); + test.testStreamReadMany("changeit\n"); + test.testReaderReadline("Name"); + test.testReaderReadline("Country"); + test.testReaderReadline("Yes"); + test.testReaderReadline(null); + + test = new Tester("Me\nHere\n"); + test.testReaderReadline2("Me"); + test.testReaderReadline2("Here"); + } +} diff --git a/test/jdk/sun/security/tools/keytool/KeyToolTest.java b/test/jdk/sun/security/tools/keytool/KeyToolTest.java index b17f7b7d999e6..7b5f4d5556eee 100644 --- a/test/jdk/sun/security/tools/keytool/KeyToolTest.java +++ b/test/jdk/sun/security/tools/keytool/KeyToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @library /java/security/testlibrary * @bug 6251120 8231950 8242151 * @summary Testing keytool * @@ -1865,172 +1866,4 @@ class TestException extends Exception { public TestException(String e) { super(e); } -} - -/** - * HumanInputStream tries to act like a human sitting in front of a computer - * terminal typing on the keyboard while the keytool program is running. - * - * keytool has called InputStream.read() and BufferedReader.readLine() in - * various places. a call to B.readLine() will try to buffer as much input as - * possible. Thus, a trivial InputStream will find it impossible to feed - * anything to I.read() after a B.readLine() call. - * - * This is why i create HumanInputStream, which will only send a single line - * to B.readLine(), no more, no less, and the next I.read() can have a chance - * to read the exact character right after "\n". - * - * I don't know why HumanInputStream works. - */ -class HumanInputStream extends InputStream { - byte[] src; - int pos; - int length; - boolean inLine; - int stopIt; - - public HumanInputStream(String input) { - src = input.getBytes(); - pos = 0; - length = src.length; - stopIt = 0; - inLine = false; - } - - // the trick: when called through read(byte[], int, int), - // return -1 twice after "\n" - - @Override public int read() throws IOException { - int re; - if(pos < length) { - re = src[pos]; - if(inLine) { - if(stopIt > 0) { - stopIt--; - re = -1; - } else { - if(re == '\n') { - stopIt = 2; - } - pos++; - } - } else { - pos++; - } - } else { - re = -1;//throw new IOException("NO MORE TO READ"); - } - //if (re < 32) System.err.printf("[%02d]", re); - //else System.err.printf("[%c]", (char)re); - return re; - } - @Override public int read(byte[] buffer, int offset, int len) { - inLine = true; - try { - int re = super.read(buffer, offset, len); - return re; - } catch(Exception e) { - throw new RuntimeException("HumanInputStream error"); - } finally { - inLine = false; - } - } - @Override public int available() { - if(pos < length) return 1; - return 0; - } - - // test part - static void assertTrue(boolean bool) { - if(!bool) - throw new RuntimeException(); - } - - public static void test() throws Exception { - - class Tester { - HumanInputStream is; - BufferedReader reader; - Tester(String s) { - is = new HumanInputStream(s); - reader = new BufferedReader(new InputStreamReader(is)); - } - - // three kinds of test method - // 1. read byte by byte from InputStream - void testStreamReadOnce(int expection) throws Exception { - assertTrue(is.read() == expection); - } - void testStreamReadMany(String expection) throws Exception { - char[] keys = expection.toCharArray(); - for(int i=0; i Date: Fri, 28 Jun 2024 13:28:53 +0000 Subject: [PATCH 099/288] 8335237: ubsan: vtableStubs.hpp is_vtable_stub exclude from ubsan checks Reviewed-by: mdoerr, clanger --- src/hotspot/share/code/vtableStubs.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 3993e1e72d5cf..426753ef00813 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "code/vmreg.hpp" #include "memory/allStatic.hpp" +#include "sanitizers/ub.hpp" #include "utilities/checkedCast.hpp" // A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables @@ -173,6 +174,9 @@ class VtableStub { public: // Query bool is_itable_stub() { return !_is_vtable_stub; } + // We reinterpret arbitrary memory as VtableStub. This does not cause failures because the lookup/equality + // check will reject false objects. Disabling UBSan is a temporary workaround until JDK-8331725 is fixed. + ATTRIBUTE_NO_UBSAN bool is_vtable_stub() { return _is_vtable_stub; } bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; } bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; } From 45c4eaa5600016d3da5ca769b2519df53835e4f7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 28 Jun 2024 16:26:34 +0000 Subject: [PATCH 100/288] 8335274: SwitchBootstraps.ResolvedEnumLabels.resolvedEnum should be final Reviewed-by: liach, jlahoda --- .../share/classes/java/lang/runtime/SwitchBootstraps.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 3eecd2ab42f9c..24ee48c1f4735 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -358,7 +358,7 @@ private static final class ResolvedEnumLabels implements BiPredicate[] enumDescs; @Stable - private Object[] resolvedEnum; + private final Object[] resolvedEnum; public ResolvedEnumLabels(MethodHandles.Lookup lookup, EnumDesc[] enumDescs) { this.lookup = lookup; From 79a3554e1da604627b3a010dc269c1bd914c79d3 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 28 Jun 2024 19:01:36 +0000 Subject: [PATCH 101/288] 8335124: com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java failed with CPU time out of expected range Reviewed-by: phh, cjplummer --- .../com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java index 83e37f0b475de..6b0302aafbf9e 100644 --- a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java +++ b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java @@ -75,7 +75,6 @@ public static void main(String[] argv) // threads block after doing some computation waitUntilThreadBlocked(); - long times[] = mbean.getThreadCpuTime(ids); long userTimes[] = mbean.getThreadUserTime(ids); @@ -222,6 +221,8 @@ private static void waitUntilThreadBlocked() } } } + // Account for threads using CPU for a few millis after their WAITING state is visible: + goSleep(500); } public static void doit() { From 3e23e9c535e0ed1d7517a836d4703c7fb3e917e4 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Fri, 28 Jun 2024 19:17:24 +0000 Subject: [PATCH 102/288] 8335344: test/jdk/sun/security/tools/keytool/NssTest.java fails to compile Reviewed-by: weijun --- test/jdk/sun/security/tools/keytool/NssTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/tools/keytool/NssTest.java b/test/jdk/sun/security/tools/keytool/NssTest.java index db5d124015308..1ed2d4c3f391c 100644 --- a/test/jdk/sun/security/tools/keytool/NssTest.java +++ b/test/jdk/sun/security/tools/keytool/NssTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ /* * @test * @summary It tests (almost) all keytool behaviors with NSS. - * @library /test/lib /test/jdk/sun/security/pkcs11 + * @library /test/lib /test/jdk/sun/security/pkcs11 /java/security/testlibrary * @modules java.base/sun.security.tools.keytool * java.base/sun.security.util * java.base/sun.security.x509 From 166f9d9ac099fa971805511b32e1cae5c6c108e0 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 28 Jun 2024 19:36:00 +0000 Subject: [PATCH 103/288] 8335221: Some C2 intrinsics incorrectly assume that type argument is compile-time constant Reviewed-by: roland, chagedorn --- src/hotspot/share/opto/library_call.cpp | 104 +++++++++++++++--------- src/hotspot/share/opto/library_call.hpp | 1 + 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 0148d985bc59b..ebe9258f99b60 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -5489,42 +5489,72 @@ void LibraryCallKit::create_new_uncommon_trap(CallStaticJavaNode* uncommon_trap_ uncommon_trap_call->set_req(0, top()); // not used anymore, kill it } +// Common checks for array sorting intrinsics arguments. +// Returns `true` if checks passed. +bool LibraryCallKit::check_array_sort_arguments(Node* elementType, Node* obj, BasicType& bt) { + // check address of the class + if (elementType == nullptr || elementType->is_top()) { + return false; // dead path + } + const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); + if (elem_klass == nullptr) { + return false; // dead path + } + // java_mirror_type() returns non-null for compile-time Class constants only + ciType* elem_type = elem_klass->java_mirror_type(); + if (elem_type == nullptr) { + return false; + } + bt = elem_type->basic_type(); + // Disable the intrinsic if the CPU does not support SIMD sort + if (!Matcher::supports_simd_sort(bt)) { + return false; + } + // check address of the array + if (obj == nullptr || obj->is_top()) { + return false; // dead path + } + const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); + if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM) { + return false; // failed input validation + } + return true; +} + //------------------------------inline_array_partition----------------------- bool LibraryCallKit::inline_array_partition() { + address stubAddr = StubRoutines::select_array_partition_function(); + if (stubAddr == nullptr) { + return false; // Intrinsic's stub is not implemented on this platform + } + assert(callee()->signature()->size() == 9, "arrayPartition has 8 parameters (one long)"); - Node* elementType = null_check(argument(0)); + // no receiver because it is a static method + Node* elementType = argument(0); Node* obj = argument(1); - Node* offset = argument(2); + Node* offset = argument(2); // long Node* fromIndex = argument(4); Node* toIndex = argument(5); Node* indexPivot1 = argument(6); Node* indexPivot2 = argument(7); + // PartitionOperation: argument(8) is ignored Node* pivotIndices = nullptr; + BasicType bt = T_ILLEGAL; + if (!check_array_sort_arguments(elementType, obj, bt)) { + return false; + } + null_check(obj); + // If obj is dead, only null-path is taken. + if (stopped()) { + return true; + } // Set the original stack and the reexecute bit for the interpreter to reexecute // the bytecode that invokes DualPivotQuicksort.partition() if deoptimization happens. { PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); - const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); - ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); - BasicType bt = elem_type->basic_type(); - // Disable the intrinsic if the CPU does not support SIMD sort - if (!Matcher::supports_simd_sort(bt)) { - return false; - } - address stubAddr = nullptr; - stubAddr = StubRoutines::select_array_partition_function(); - // stub not loaded - if (stubAddr == nullptr) { - return false; - } - // get the address of the array - const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); - if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) { - return false; // failed input validation - } Node* obj_adr = make_unsafe_address(obj, offset); // create the pivotIndices array of type int and size = 2 @@ -5557,31 +5587,29 @@ bool LibraryCallKit::inline_array_partition() { //------------------------------inline_array_sort----------------------- bool LibraryCallKit::inline_array_sort() { + address stubAddr = StubRoutines::select_arraysort_function(); + if (stubAddr == nullptr) { + return false; // Intrinsic's stub is not implemented on this platform + } + assert(callee()->signature()->size() == 7, "arraySort has 6 parameters (one long)"); - Node* elementType = null_check(argument(0)); + // no receiver because it is a static method + Node* elementType = argument(0); Node* obj = argument(1); - Node* offset = argument(2); + Node* offset = argument(2); // long Node* fromIndex = argument(4); Node* toIndex = argument(5); + // SortOperation: argument(6) is ignored - const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); - ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); - BasicType bt = elem_type->basic_type(); - // Disable the intrinsic if the CPU does not support SIMD sort - if (!Matcher::supports_simd_sort(bt)) { - return false; - } - address stubAddr = nullptr; - stubAddr = StubRoutines::select_arraysort_function(); - //stub not loaded - if (stubAddr == nullptr) { + BasicType bt = T_ILLEGAL; + + if (!check_array_sort_arguments(elementType, obj, bt)) { return false; } - - // get address of the array - const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); - if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) { - return false; // failed input validation + null_check(obj); + // If obj is dead, only null-path is taken. + if (stopped()) { + return true; } Node* obj_adr = make_unsafe_address(obj, offset); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 941282ce2e744..313e8c39544c6 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -279,6 +279,7 @@ class LibraryCallKit : public GraphKit { JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms_before_guards, int saved_reexecute_sp, uint new_idx); + bool check_array_sort_arguments(Node* elementType, Node* obj, BasicType& bt); bool inline_array_sort(); bool inline_array_partition(); typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; From 5d866bf17d96bd0f0e4545d7eee5912eda2e3a94 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 28 Jun 2024 22:27:34 +0000 Subject: [PATCH 104/288] 8335252: Reduce size of j.u.Formatter.Conversion#isValid Reviewed-by: redestad --- src/java.base/share/classes/java/util/Formatter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index a7d95ee5780c8..41b9540001c83 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -4967,9 +4967,9 @@ static boolean isValid(char c) { DECIMAL_FLOAT, HEXADECIMAL_FLOAT, HEXADECIMAL_FLOAT_UPPER, - LINE_SEPARATOR, - PERCENT_SIGN -> true; - default -> false; + LINE_SEPARATOR -> true; + // Don't put PERCENT_SIGN inside switch, as that will make the method size exceed 325 and cannot be inlined. + default -> c == PERCENT_SIGN; }; } From 8350b1daedae8ef5785a7165e664b1d3149b18b7 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sat, 29 Jun 2024 05:04:47 +0000 Subject: [PATCH 105/288] 8335294: Fix simple -Wzero-as-null-pointer-constant warnings in gc code Reviewed-by: tschatzl, coleenp, jwaters --- .../gc/x/xPhysicalMemoryBacking_linux.cpp | 6 +++--- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 6 +++--- .../share/gc/parallel/parMarkBitMap.cpp | 4 ++-- .../share/gc/parallel/parallelScavengeHeap.cpp | 2 +- .../share/gc/parallel/psParallelCompact.cpp | 6 +++--- src/hotspot/share/gc/z/zPage.inline.hpp | 3 +-- .../gc/gctests/nativeGC01/libnativeGC01.cpp | 6 +++--- .../gc/gctests/nativeGC02/libnativeGC02.cpp | 8 ++++---- .../gc/gctests/nativeGC03/libnativeGC03.cpp | 2 +- .../gc/gctests/nativeGC05/libnativeGC05.cpp | 18 +++++++++--------- 10 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp index 5db59741a5864..35625f613d349 100644 --- a/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/x/xPhysicalMemoryBacking_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -389,7 +389,7 @@ XErrno XPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(size_t offset, si // On hugetlbfs, mapping a file segment will fail immediately, without // the need to touch the mapped pages first, if there aren't enough huge // pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); if (addr == MAP_FAILED) { // Failed return errno; @@ -439,7 +439,7 @@ static bool safe_touch_mapping(void* addr, size_t length, size_t page_size) { XErrno XPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(size_t offset, size_t length) const { // On tmpfs, we need to touch the mapped pages to figure out // if there are enough pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset); if (addr == MAP_FAILED) { // Failed return errno; diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index 76f9d90cd7198..b80124cc34e43 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,7 +391,7 @@ ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_hugetlbfs(zoffset offset, s // On hugetlbfs, mapping a file segment will fail immediately, without // the need to touch the mapped pages first, if there aren't enough huge // pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); if (addr == MAP_FAILED) { // Failed return errno; @@ -441,7 +441,7 @@ static bool safe_touch_mapping(void* addr, size_t length, size_t page_size) { ZErrno ZPhysicalMemoryBacking::fallocate_compat_mmap_tmpfs(zoffset offset, size_t length) const { // On tmpfs, we need to touch the mapped pages to figure out // if there are enough pages available to back the mapping. - void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); + void* const addr = mmap(nullptr, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, untype(offset)); if (addr == MAP_FAILED) { // Failed return errno; diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index 434b719aa13ee..658c3ef106fa0 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) return true; } - _heap_start = 0; + _heap_start = nullptr; _heap_size = 0; if (_virtual_space != nullptr) { delete _virtual_space; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 2984cedafe196..665b14bb1eabf 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -661,7 +661,7 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const { "addr should be in allocated part of old gen"); return old_gen()->start_array()->object_start((HeapWord*)addr); } - return 0; + return nullptr; } bool ParallelScavengeHeap::block_is_obj(const HeapWord* addr) const { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 6c08503438423..b4fe706d1e410 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -237,7 +237,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) MemTracker::record_virtual_memory_type((address)rs.base(), mtGC); PSVirtualSpace* vspace = new PSVirtualSpace(rs, page_sz); - if (vspace != 0) { + if (vspace != nullptr) { if (vspace->expand_by(_reserved_byte_size)) { return vspace; } @@ -246,7 +246,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) rs.release(); } - return 0; + return nullptr; } bool ParallelCompactData::initialize_region_data(size_t heap_size) @@ -255,7 +255,7 @@ bool ParallelCompactData::initialize_region_data(size_t heap_size) const size_t count = heap_size >> Log2RegionSize; _region_vspace = create_vspace(count, sizeof(RegionData)); - if (_region_vspace != 0) { + if (_region_vspace != nullptr) { _region_data = (RegionData*)_region_vspace->reserved_low_addr(); _region_count = count; return true; diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index ff5fe0bbd6c87..0b4ee28ba7d0a 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,6 @@ inline const char* ZPage::type_to_string() const { default: fatal("Unexpected page type"); - return 0; } } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp index 63aed51a89764..efd1fd3fa3ab4 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC01/libnativeGC01.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ Java_gc_gctests_nativeGC01_nativeGC01_nativeMethod01 */ cls = env->GetObjectClass(obj); mid = env->GetMethodID(cls, "callbackGC", "()V"); - if (mid == 0) { + if (mid == nullptr) { printf("couldnt locate method callbackGC()"); return -1; } @@ -56,7 +56,7 @@ Java_gc_gctests_nativeGC01_nativeGC01_nativeMethod01 clss = env->GetObjectClass(linked_list); mid2 = env->GetMethodID(clss, "getLength", "()I"); - if (mid2 == 0) { + if (mid2 == nullptr) { printf("couldnt locate method getLength()"); return -1; } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp index e6db8cf618460..eec3fa3e8e865 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC02/libnativeGC02.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ Java_gc_gctests_nativeGC02_nativeGC02_nativeMethod02 clss = env->GetObjectClass(obj); fid = env->GetFieldID(clss, "cl", "Lnsk/share/gc/CircularLinkedList;"); - if (fid == 0) { + if (fid == nullptr) { printf("could not locate field - cl\n"); return -1; } @@ -53,7 +53,7 @@ Java_gc_gctests_nativeGC02_nativeGC02_nativeMethod02 cls = env->GetObjectClass(obj); mid = env->GetMethodID(cls, "callbackGC", "()V"); - if (mid == 0) { + if (mid == nullptr) { printf("couldnt locate method callbackGC()\n"); return -1; } @@ -66,7 +66,7 @@ Java_gc_gctests_nativeGC02_nativeGC02_nativeMethod02 clss = env->GetObjectClass(linked_list); mid2 = env->GetMethodID(clss, "getLength", "(Lnsk/share/gc/CircularLinkedList;)I"); - if (mid2 == 0) { + if (mid2 == nullptr) { printf("couldnt locate method getLength(CircularLinkedList)\n"); return -1; } diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp index 2c97863db5a9f..e3f54ec86ec50 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC03/libnativeGC03.cpp @@ -46,7 +46,7 @@ Java_gc_gctests_nativeGC03_nativeGC03_nativeMethod03 clss = env->GetObjectClass(obj); mid = env->GetMethodID(clss, "fillArray", "()V"); - if (mid == 0) { + if (mid == nullptr) { return; } env->CallVoidMethod(obj, mid); diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp index 4bfaeda1f0606..a796cf938bbe6 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/nativeGC05/libnativeGC05.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,8 @@ extern "C" { JNIEXPORT void JNICALL Java_gc_gctests_nativeGC05_nativeGC05_kickOffRefillers (JNIEnv *env, jobject obj, jobject matrix, jobject stack) { - jclass matrixClass, stackClass, pairClass = 0; - jmethodID stack_pop_mid, stack_empty_mid, matrix_repopulate_mid, pair_geti_mid = 0, pair_getj_mid = 0; + jclass matrixClass, stackClass, pairClass = nullptr; + jmethodID stack_pop_mid, stack_empty_mid, matrix_repopulate_mid, pair_geti_mid = nullptr, pair_getj_mid = nullptr; jobject pair; jint i, j; jboolean b; @@ -40,18 +40,18 @@ Java_gc_gctests_nativeGC05_nativeGC05_kickOffRefillers /* GetMethodID's for the pop() and Repopulate() methods */ stack_pop_mid = env->GetMethodID(stackClass, "pop", "()Ljava/lang/Object;"); - if (stack_pop_mid == 0) { + if (stack_pop_mid == nullptr) { printf("could not get a methodID for Stack::pop()\n"); return; } stack_empty_mid = env->GetMethodID(stackClass, "empty", "()Z"); - if (stack_empty_mid == 0) { + if (stack_empty_mid == nullptr) { printf("could not get a methodID for Stack::empty()\n"); return; } matrix_repopulate_mid = env->GetMethodID(matrixClass, "repopulate", "(II)V"); - if (matrix_repopulate_mid == 0) { + if (matrix_repopulate_mid == nullptr) { printf("could not get a methodID for Matrix::repopulate(int, int)\n"); return; } @@ -62,15 +62,15 @@ Java_gc_gctests_nativeGC05_nativeGC05_kickOffRefillers /** pair = stack.pop() */ pair = env->CallObjectMethod(stack, stack_pop_mid); - if (pairClass == 0) { + if (pairClass == nullptr) { pairClass = env->GetObjectClass(pair); pair_geti_mid = env->GetMethodID(pairClass, "getI", "()I"); - if (pair_geti_mid == 0) { + if (pair_geti_mid == nullptr) { printf("could not get a methodID for IndexPair::getI()\n"); return; } pair_getj_mid = env->GetMethodID(pairClass, "getJ", "()I"); - if (pair_getj_mid == 0) { + if (pair_getj_mid == nullptr) { printf("could not get a methodID for IndexPair::getJ()\n"); return; } From bb18498d71dddf49db9bdfac886aed9ae123651d Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Sat, 29 Jun 2024 08:19:33 +0000 Subject: [PATCH 106/288] 8335349: jcmd VM.classloaders "fold" option should be optional Reviewed-by: cjplummer, stuefe --- src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp b/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp index f89090fbb5c06..8a8113db4036d 100644 --- a/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp +++ b/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -39,7 +39,7 @@ ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool he : DCmdWithParser(output, heap), _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false"), _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false"), - _fold("fold", "Show loaders of the same name and class as one.", "BOOLEAN", true, "true") { + _fold("fold", "Show loaders of the same name and class as one.", "BOOLEAN", false, "true") { _dcmdparser.add_dcmd_option(&_show_classes); _dcmdparser.add_dcmd_option(&_verbose); _dcmdparser.add_dcmd_option(&_fold); From d9bcf061450ebfb7fe02b5a50c855db1d9178e5d Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Sat, 29 Jun 2024 20:40:51 +0000 Subject: [PATCH 107/288] 8335217: Fix memory ordering in ClassLoaderData::ChunkedHandleList Reviewed-by: dholmes, stefank, eosterlund --- src/hotspot/share/classfile/classLoaderData.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 16837da9cf260..de4490e73f326 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -202,9 +202,9 @@ OopHandle ClassLoaderData::ChunkedHandleList::add(oop o) { int ClassLoaderData::ChunkedHandleList::count() const { int count = 0; - Chunk* chunk = _head; + Chunk* chunk = Atomic::load_acquire(&_head); while (chunk != nullptr) { - count += chunk->_size; + count += Atomic::load(&chunk->_size); chunk = chunk->_next; } return count; @@ -258,9 +258,9 @@ bool ClassLoaderData::ChunkedHandleList::contains(oop p) { #ifndef PRODUCT bool ClassLoaderData::ChunkedHandleList::owner_of(oop* oop_handle) { - Chunk* chunk = _head; + Chunk* chunk = Atomic::load_acquire(&_head); while (chunk != nullptr) { - if (&(chunk->_data[0]) <= oop_handle && oop_handle < &(chunk->_data[chunk->_size])) { + if (&(chunk->_data[0]) <= oop_handle && oop_handle < &(chunk->_data[Atomic::load(&chunk->_size)])) { return true; } chunk = chunk->_next; From 53242cdf9ef17c502ebd541e84370e7c158639c1 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Jul 2024 06:37:09 +0000 Subject: [PATCH 108/288] 8335283: Build failure due to 'no_sanitize' attribute directive ignored Reviewed-by: shade, tschatzl, kbarrett, jwaters --- src/hotspot/share/sanitizers/ub.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/sanitizers/ub.hpp b/src/hotspot/share/sanitizers/ub.hpp index 23e8ef4576c9f..66cd014c35cd4 100644 --- a/src/hotspot/share/sanitizers/ub.hpp +++ b/src/hotspot/share/sanitizers/ub.hpp @@ -32,9 +32,11 @@ // following function or method. // Useful if the function or method is known to do something special or even 'dangerous', for // example causing desired signals/crashes. +#ifdef UNDEFINED_BEHAVIOR_SANITIZER #if defined(__clang__) || defined(__GNUC__) #define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) #endif +#endif #ifndef ATTRIBUTE_NO_UBSAN #define ATTRIBUTE_NO_UBSAN From c7e9ebb4cfff56b7a977eb2942f563f96b3336bd Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Mon, 1 Jul 2024 08:07:42 +0000 Subject: [PATCH 109/288] 8331732: [PPC64] Unify and optimize code which converts != 0 to 1 Reviewed-by: mdoerr, amitkumar --- src/hotspot/cpu/ppc/assembler_ppc.hpp | 7 +++-- src/hotspot/cpu/ppc/assembler_ppc.inline.hpp | 9 +++++-- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 9 ++----- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 2 ++ .../cpu/ppc/macroAssembler_ppc.inline.hpp | 27 +++++++++++++++++-- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 6 +---- .../ppc/templateInterpreterGenerator_ppc.cpp | 4 +-- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index 61a5d6425eec6..d18574f50a949 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2023 SAP SE. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -350,6 +350,7 @@ class Assembler : public AbstractAssembler { SETBC_OPCODE = (31u << OPCODE_SHIFT | 384u << 1), SETNBC_OPCODE = (31u << OPCODE_SHIFT | 448u << 1), + SETBCR_OPCODE = (31u << OPCODE_SHIFT | 416u << 1), // condition register logic instructions CRAND_OPCODE = (19u << OPCODE_SHIFT | 257u << 1), @@ -1780,6 +1781,8 @@ class Assembler : public AbstractAssembler { inline void setbc( Register d, ConditionRegister cr, Condition cc); inline void setnbc(Register d, int biint); inline void setnbc(Register d, ConditionRegister cr, Condition cc); + inline void setbcr(Register d, int biint); + inline void setbcr(Register d, ConditionRegister cr, Condition cc); // Special purpose registers // Exception Register diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index d78dec964cbb0..98c8b629844c9 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2020 SAP SE. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -419,6 +419,11 @@ inline void Assembler::setnbc(Register d, int biint) inline void Assembler::setnbc(Register d, ConditionRegister cr, Condition cc) { setnbc(d, bi0(cr, cc)); } +inline void Assembler::setbcr(Register d, int biint) + { emit_int32(SETBCR_OPCODE | rt(d) | bi(biint)); } +inline void Assembler::setbcr(Register d, ConditionRegister cr, Condition cc) { + setbcr(d, bi0(cr, cc)); +} // Special purpose registers // Exception Register diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 0527cb306b274..f9e584a1e6b57 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2383,10 +2383,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, addi(r_array_base, r_array_base, Array::base_offset_in_bytes()); // convert !=0 to 1 - neg(R0, result); - orr(result, result, R0); - srdi(result, result, 63); - + normalize_bool(result, R0, true); const Register linear_result = r_array_index; // reuse li(linear_result, 1); cmpdi(CCR0, r_array_length, 0); @@ -2395,9 +2392,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, bind(failure); // convert !=0 to 1 - neg(R0, linear_result); - orr(linear_result, linear_result, R0); - srdi(linear_result, linear_result, 63); + normalize_bool(linear_result, R0, true); cmpd(CCR0, result, linear_result); beq(CCR0, passed); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 4f2ff708a46a3..15b5e26f8f634 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -178,6 +178,8 @@ class MacroAssembler: public Assembler { void inline set_cmp3(Register dst); // set dst to (treat_unordered_like_less ? -1 : +1) void inline set_cmpu3(Register dst, bool treat_unordered_like_less); + // Branch-free implementation to convert !=0 to 1. + void inline normalize_bool(Register dst, Register temp = R0, bool is_64bit = false); inline void pd_patch_instruction(address branch, address target, const char* file, int line); NOT_PRODUCT(static void pd_print_patched_instruction(address branch);) diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp index f81d49684c992..e9c6fd38f4593 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2021 SAP SE. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -264,6 +264,29 @@ inline void MacroAssembler::set_cmpu3(Register dst, bool treat_unordered_like_le set_cmp3(dst); } +// Branch-free implementation to convert !=0 to 1 +// Set register dst to 1 if dst is non-zero. Uses setbcr instruction on Power10. +inline void MacroAssembler::normalize_bool(Register dst, Register temp, bool is_64bit) { + + if (VM_Version::has_brw()) { + if (is_64bit) { + cmpdi(CCR0, dst, 0); + } else { + cmpwi(CCR0, dst, 0); + } + setbcr(dst, CCR0, Assembler::equal); + } else { + assert_different_registers(temp, dst); + neg(temp, dst); + orr(temp, dst, temp); + if (is_64bit) { + srdi(dst, temp, 63); + } else { + srwi(dst, temp, 31); + } + } +} + // Convenience bc_far versions inline void MacroAssembler::blt_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, less), L, optimize); } inline void MacroAssembler::bgt_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, greater), L, optimize); } diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 14aa768e3ff18..9b5a86bc45bfd 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2472,11 +2472,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, case T_ARRAY: break; case T_BOOLEAN: { // 0 -> false(0); !0 -> true(1) - Label skip_modify; - __ cmpwi(CCR0, R3_RET, 0); - __ beq(CCR0, skip_modify); - __ li(R3_RET, 1); - __ bind(skip_modify); + __ normalize_bool(R3_RET); break; } case T_BYTE: { // sign extension diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index c4eaf0493e337..4caae20025309 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -372,9 +372,7 @@ address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type switch (type) { case T_BOOLEAN: // convert !=0 to 1 - __ neg(R0, R3_RET); - __ orr(R0, R3_RET, R0); - __ srwi(R3_RET, R0, 31); + __ normalize_bool(R3_RET); break; case T_BYTE: // sign extend 8 bits From 71e3798bf67cddef37a8b4e377c4bf21dbd01567 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 1 Jul 2024 08:12:20 +0000 Subject: [PATCH 110/288] 8335308: compiler/uncommontrap/DeoptReallocFailure.java times out with SerialGC on Windows Reviewed-by: kvn, thartmann, chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 -- .../jtreg/compiler/uncommontrap/DeoptReallocFailure.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index febde61c4fda1..254e621bfdd47 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -70,8 +70,6 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all -compiler/uncommontrap/DeoptReallocFailure.java 8335308 windows-x64 - ############################################################################# # :hotspot_gc diff --git a/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java b/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java index 949a3ecb5c29f..96c79864b52e7 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/DeoptReallocFailure.java @@ -63,7 +63,7 @@ public static synchronized long test() { NoEscape[] noEscape = new NoEscape[45]; noEscape[0] = new NoEscape(); for (int i=0;i<1024*256;i++) { - root.array[i]= new Object[45]; + root.array[i]= new Object[4500]; } return noEscape[0].f1; } From 0a6ffa57954ddf4f92205205a5a1bada813d127a Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Mon, 1 Jul 2024 08:47:29 +0000 Subject: [PATCH 111/288] 8261242: [Linux] OSContainer::is_containerized() returns true when run outside a container Reviewed-by: stuefe, iklam --- .../os/linux/cgroupSubsystem_linux.cpp | 119 +++++++++++++++--- .../os/linux/cgroupSubsystem_linux.hpp | 7 +- .../os/linux/cgroupV1Subsystem_linux.cpp | 11 ++ .../os/linux/cgroupV1Subsystem_linux.hpp | 8 +- .../os/linux/cgroupV2Subsystem_linux.cpp | 4 + .../os/linux/cgroupV2Subsystem_linux.hpp | 6 +- src/hotspot/os/linux/osContainer_linux.cpp | 39 +++++- src/hotspot/share/include/jvm.h | 3 + src/hotspot/share/prims/jvm.cpp | 12 ++ .../jdk/internal/platform/CgroupMetrics.java | 6 + .../internal/platform/CgroupSubsystem.java | 5 + .../linux/native/libjava/CgroupMetrics.c | 6 + .../jdk/internal/platform/Metrics.java | 17 +++ .../classes/sun/launcher/LauncherHelper.java | 4 + .../runtime/test_cgroupSubsystem_linux.cpp | 9 +- test/hotspot/jtreg/ProblemList.txt | 1 - ...{PlainRead.java => TestContainerized.java} | 42 +------ .../platform/cgroup/TestSystemSettings.java | 45 +++++++ .../lib/containers/cgroup/MetricsTester.java | 10 ++ 19 files changed, 290 insertions(+), 64 deletions(-) rename test/hotspot/jtreg/containers/cgroup/{PlainRead.java => TestContainerized.java} (54%) create mode 100644 test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 560589c3602c4..0dbd6ffd52be7 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -63,7 +63,9 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { // Construct the subsystem, free resources and return // Note: any index in cg_infos will do as the path is the same for // all controllers. - CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, cg_infos[MEMORY_IDX]._cgroup_path); + CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, + cg_infos[MEMORY_IDX]._cgroup_path, + cg_infos[MEMORY_IDX]._read_only); log_debug(os, container)("Detected cgroups v2 unified hierarchy"); cleanup(cg_infos); return new CgroupV2Subsystem(unified); @@ -100,19 +102,19 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupInfo info = cg_infos[i]; if (info._data_complete) { // pids controller might have incomplete data if (strcmp(info._name, "memory") == 0) { - memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path); + memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path, info._read_only); memory->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuset") == 0) { - cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuset->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpu") == 0) { - cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpu->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuacct") == 0) { - cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path); + cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuacct->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "pids") == 0) { - pids = new CgroupV1Controller(info._root_mount_path, info._mount_path); + pids = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); pids->set_subsystem_path(info._cgroup_path); } } else { @@ -127,7 +129,8 @@ void CgroupSubsystemFactory::set_controller_paths(CgroupInfo* cg_infos, int controller, const char* name, char* mount_path, - char* root_path) { + char* root_path, + bool read_only) { if (cg_infos[controller]._mount_path != nullptr) { // On some systems duplicate controllers get mounted in addition to // the main cgroup controllers most likely under /sys/fs/cgroup. In that @@ -139,6 +142,7 @@ void CgroupSubsystemFactory::set_controller_paths(CgroupInfo* cg_infos, os::free(cg_infos[controller]._root_mount_path); cg_infos[controller]._mount_path = os::strdup(mount_path); cg_infos[controller]._root_mount_path = os::strdup(root_path); + cg_infos[controller]._read_only = read_only; } else { log_debug(os, container)("Duplicate %s controllers detected. Picking %s, skipping %s.", name, cg_infos[controller]._mount_path, mount_path); @@ -146,9 +150,66 @@ void CgroupSubsystemFactory::set_controller_paths(CgroupInfo* cg_infos, } else { cg_infos[controller]._mount_path = os::strdup(mount_path); cg_infos[controller]._root_mount_path = os::strdup(root_path); + cg_infos[controller]._read_only = read_only; } } +/* + * Determine whether or not the mount options, which are comma separated, + * contain the 'ro' string. + */ +static bool find_ro_opt(char* mount_opts) { + char* token; + char* mo_ptr = mount_opts; + // mount options are comma-separated (man proc). + while ((token = strsep(&mo_ptr, ",")) != NULL) { + if (strcmp(token, "ro") == 0) { + return true; + } + } + return false; +} + +/* + * Read values of a /proc/self/mountinfo line into variables. For cgroups v1 + * super options are needed. On cgroups v2 super options are not used. + * + * The scanning of a single mountinfo line entry is as follows: + * + * 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + * (1) (2) (3):(4) (5) (6) (7) (8) (9) (10) (11) (12) + * + * The numbers in parentheses are labels for the descriptions below: + * + * (1) mount ID: matched with '%*d' and discarded + * (2) parent ID: matched with '%*d' and discarded + * (3) major: ---,---> major, minor separated by ':'. matched with '%*d:%*d' and discarded + * (4) minor: ---' + * (5) root: matched with '%s' and captured in 'tmproot'. Must be non-empty. + * (6) mount point: matched with '%s' and captured in 'tmpmount'. Must be non-empty. + * (7) mount options: matched with '%s' and captured in 'mount_opts'. Must be non-empty. + * (8) optional fields: ---,---> matched with '%*[^-]-'. Anything not a hyphen, followed by a hyphen + * (9) separator: ---' and discarded. Note: The discarded match is space characters if there + * are no optionals. Otherwise it includes the optional fields as well. + * (10) filesystem type: matched with '%s' and captured in 'tmp_fs_type' + * (11) mount source: matched with '%*s' and discarded + * (12) super options: matched with '%s' and captured in 'tmpcgroups' + */ +static inline bool match_mount_info_line(char* line, + char* tmproot, + char* tmpmount, + char* mount_opts, + char* tmp_fs_type, + char* tmpcgroups) { + return sscanf(line, + "%*d %*d %*d:%*d %s %s %s%*[^-]- %s %*s %s", + tmproot, + tmpmount, + mount_opts, + tmp_fs_type, + tmpcgroups) == 5; +} + bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, const char* proc_cgroups, const char* proc_self_cgroup, @@ -318,26 +379,40 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, char tmproot[MAXPATHLEN+1]; char tmpmount[MAXPATHLEN+1]; char tmpcgroups[MAXPATHLEN+1]; + char mount_opts[MAXPATHLEN+1]; char *cptr = tmpcgroups; char *token; - // Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so - // as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 - // block in the hybrid case. - if (is_cgroupsV2 && sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %*s", tmproot, tmpmount, tmp_fs_type) == 3) { + /* Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so + * as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 + * block in the hybrid case. + * + * We collect the read only mount option in the cgroup infos so as to have that + * info ready when determining is_containerized(). + */ + if (is_cgroupsV2 && match_mount_info_line(p, + tmproot, + tmpmount, + mount_opts, + tmp_fs_type, + tmpcgroups /* unused */)) { // we likely have an early match return (e.g. cgroup fs match), be sure we have cgroup2 as fstype if (strcmp("cgroup2", tmp_fs_type) == 0) { cgroupv2_mount_point_found = true; any_cgroup_mounts_found = true; + // For unified we only have a single line with cgroup2 fs type. + // Therefore use that option for all CG info structs. + bool ro_option = find_ro_opt(mount_opts); for (int i = 0; i < CG_INFO_LENGTH; i++) { - set_controller_paths(cg_infos, i, "(cg2, unified)", tmpmount, tmproot); + set_controller_paths(cg_infos, i, "(cg2, unified)", tmpmount, tmproot, ro_option); } } } /* Cgroup v1 relevant info * - * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids + * Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids. For each controller + * determine whether or not they show up as mounted read only or not. * * Example for docker: * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory @@ -346,8 +421,9 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, * 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory * * 44 31 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,pids + * */ - if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %s", tmproot, tmpmount, tmp_fs_type, tmpcgroups) == 4) { + if (match_mount_info_line(p, tmproot, tmpmount, mount_opts, tmp_fs_type, tmpcgroups)) { if (strcmp("cgroup", tmp_fs_type) != 0) { // Skip cgroup2 fs lines on hybrid or unified hierarchy. continue; @@ -355,23 +431,28 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, while ((token = strsep(&cptr, ",")) != nullptr) { if (strcmp(token, "memory") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, MEMORY_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, MEMORY_IDX, token, tmpmount, tmproot, ro_option); cg_infos[MEMORY_IDX]._data_complete = true; } else if (strcmp(token, "cpuset") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPUSET_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPUSET_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPUSET_IDX]._data_complete = true; } else if (strcmp(token, "cpu") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPU_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPU_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPU_IDX]._data_complete = true; } else if (strcmp(token, "cpuacct") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, CPUACCT_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, CPUACCT_IDX, token, tmpmount, tmproot, ro_option); cg_infos[CPUACCT_IDX]._data_complete = true; } else if (strcmp(token, "pids") == 0) { any_cgroup_mounts_found = true; - set_controller_paths(cg_infos, PIDS_IDX, token, tmpmount, tmproot); + bool ro_option = find_ro_opt(mount_opts); + set_controller_paths(cg_infos, PIDS_IDX, token, tmpmount, tmproot, ro_option); cg_infos[PIDS_IDX]._data_complete = true; } } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 6c17ff4508d55..00419c77570ae 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -105,6 +105,7 @@ class CgroupController: public CHeapObj { public: virtual char* subsystem_path() = 0; + virtual bool is_read_only() = 0; /* Read a numerical value as unsigned long * @@ -211,6 +212,7 @@ class CgroupSubsystem: public CHeapObj { virtual jlong memory_max_usage_in_bytes() = 0; virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; + virtual bool is_containerized() = 0; virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; @@ -233,6 +235,7 @@ class CgroupInfo : public StackObj { char* _name; int _hierarchy_id; bool _enabled; + bool _read_only; // whether or not the mount path is mounted read-only bool _data_complete; // indicating cgroup v1 data is complete for this controller char* _cgroup_path; // cgroup controller path from /proc/self/cgroup char* _root_mount_path; // root mount path from /proc/self/mountinfo. Unused for cgroup v2 @@ -243,6 +246,7 @@ class CgroupInfo : public StackObj { _name = nullptr; _hierarchy_id = -1; _enabled = false; + _read_only = false; _data_complete = false; _cgroup_path = nullptr; _root_mount_path = nullptr; @@ -274,7 +278,8 @@ class CgroupSubsystemFactory: AllStatic { int controller, const char* name, char* mount_path, - char* root_path); + char* root_path, + bool read_only); // Determine the cgroup type (version 1 or version 2), given // relevant paths to files. Sets 'flags' accordingly. static bool determine_type(CgroupInfo* cg_infos, diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 72adaa23b8132..3f6ae813810f2 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -215,6 +215,17 @@ jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { } } +bool CgroupV1Subsystem::is_containerized() { + // containerized iff all required controllers are mounted + // read-only. See OSContainer::is_containerized() for + // the full logic. + // + return _memory->controller()->is_read_only() && + _cpu->controller()->is_read_only() && + _cpuacct->is_read_only() && + _cpuset->is_read_only(); +} + /* memory_usage_in_bytes * * Return the amount of used memory for this process. diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 254b17de0ba8c..2b67678c2e8da 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -36,19 +36,22 @@ class CgroupV1Controller: public CgroupController { /* mountinfo contents */ char *_root; char *_mount_point; + bool _read_only; /* Constructed subsystem directory */ char *_path; public: - CgroupV1Controller(char *root, char *mountpoint) { + CgroupV1Controller(char *root, char *mountpoint, bool ro) { _root = os::strdup(root); _mount_point = os::strdup(mountpoint); _path = nullptr; + _read_only = ro; } virtual void set_subsystem_path(char *cgroup_path); char *subsystem_path() { return _path; } + bool is_read_only() { return _read_only; } }; class CgroupV1MemoryController: public CgroupV1Controller { @@ -65,7 +68,7 @@ class CgroupV1MemoryController: public CgroupV1Controller { void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } public: - CgroupV1MemoryController(char *root, char *mountpoint) : CgroupV1Controller(root, mountpoint) { + CgroupV1MemoryController(char *root, char *mountpoint, bool ro) : CgroupV1Controller(root, mountpoint, ro) { _uses_mem_hierarchy = false; } @@ -97,6 +100,7 @@ class CgroupV1Subsystem: public CgroupSubsystem { jlong pids_max(); jlong pids_current(); + bool is_containerized(); void print_version_specific_info(outputStream* st); diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 1ba7c1e69d5b3..1f97b0212395c 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -94,6 +94,10 @@ int CgroupV2Subsystem::cpu_quota() { return limit; } +bool CgroupV2Subsystem::is_containerized() { + return _unified->is_read_only(); +} + char* CgroupV2Subsystem::cpu_cpuset_cpus() { char cpus[1024]; CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index a004c8f75b984..8e06466a138a5 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -33,19 +33,22 @@ class CgroupV2Controller: public CgroupController { char *_mount_path; /* The cgroup path for the controller */ char *_cgroup_path; + bool _read_only; /* Constructed full path to the subsystem directory */ char *_path; static char* construct_path(char* mount_path, char *cgroup_path); public: - CgroupV2Controller(char * mount_path, char *cgroup_path) { + CgroupV2Controller(char * mount_path, char *cgroup_path, bool ro) { _mount_path = mount_path; _cgroup_path = os::strdup(cgroup_path); _path = construct_path(mount_path, cgroup_path); + _read_only = ro; } char *subsystem_path() { return _path; } + bool is_read_only() { return _read_only; } }; class CgroupV2Subsystem: public CgroupSubsystem { @@ -83,6 +86,7 @@ class CgroupV2Subsystem: public CgroupSubsystem { jlong pids_max(); jlong pids_current(); + bool is_containerized(); void print_version_specific_info(outputStream* st); const char * container_type() { diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index fdb138c864faa..25e8eb464108d 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -58,8 +58,43 @@ void OSContainer::init() { if (cgroup_subsystem == nullptr) { return; // Required subsystem files not found or other error } - - _is_containerized = true; + /* + * In order to avoid a false positive on is_containerized() on + * Linux systems outside a container *and* to ensure compatibility + * with in-container usage, we detemine is_containerized() by two + * steps: + * 1.) Determine if all the cgroup controllers are mounted read only. + * If yes, is_containerized() == true. Otherwise, do the fallback + * in 2.) + * 2.) Query for memory and cpu limits. If any limit is set, we set + * is_containerized() == true. + * + * Step 1.) covers the basic in container use-cases. Step 2.) ensures + * that limits enforced by other means (e.g. systemd slice) are properly + * detected. + */ + const char *reason; + bool any_mem_cpu_limit_present = false; + bool controllers_read_only = cgroup_subsystem->is_containerized(); + if (controllers_read_only) { + // in-container case + reason = " because all controllers are mounted read-only (container case)"; + } else { + // We can be in one of two cases: + // 1.) On a physical Linux system without any limit + // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) + any_mem_cpu_limit_present = cgroup_subsystem->memory_limit_in_bytes() > 0 || + os::Linux::active_processor_count() != cgroup_subsystem->active_processor_count(); + if (any_mem_cpu_limit_present) { + reason = " because either a cpu or a memory limit is present"; + } else { + reason = " because no cpu or memory limit is present"; + } + } + _is_containerized = controllers_read_only || any_mem_cpu_limit_present; + log_debug(os, container)("OSContainer::init: is_containerized() = %s%s", + _is_containerized ? "true" : "false", + reason); } const char * OSContainer::container_type() { diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 99cdac3aec5bf..0aad9160ae8b5 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -150,6 +150,9 @@ JVM_ActiveProcessorCount(void); JNIEXPORT jboolean JNICALL JVM_IsUseContainerSupport(void); +JNIEXPORT jboolean JNICALL +JVM_IsContainerized(void); + JNIEXPORT void * JNICALL JVM_LoadZipLibrary(); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 9588f32e6b376..d55c8a6be656d 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -113,6 +113,9 @@ #if INCLUDE_MANAGEMENT #include "services/finalizerService.hpp" #endif +#ifdef LINUX +#include "osContainer_linux.hpp" +#endif #include @@ -496,6 +499,15 @@ JVM_LEAF(jboolean, JVM_IsUseContainerSupport(void)) return JNI_FALSE; JVM_END +JVM_LEAF(jboolean, JVM_IsContainerized(void)) +#ifdef LINUX + if (OSContainer::is_containerized()) { + return JNI_TRUE; + } +#endif + return JNI_FALSE; +JVM_END + // java.lang.Throwable ////////////////////////////////////////////////////// JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver)) diff --git a/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java b/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java index 8797711bf4b91..af551a07b1e71 100644 --- a/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java +++ b/src/java.base/linux/classes/jdk/internal/platform/CgroupMetrics.java @@ -35,6 +35,11 @@ public class CgroupMetrics implements Metrics { this.subsystem = Objects.requireNonNull(subsystem); } + @Override + public boolean isContainerized() { + return isContainerized0(); + } + @Override public String getProvider() { return subsystem.getProvider(); @@ -194,6 +199,7 @@ public static Metrics getInstance() { } private static native boolean isUseContainerSupport(); + private static native boolean isContainerized0(); private static native long getTotalMemorySize0(); private static native long getTotalSwapSize0(); diff --git a/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java b/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java index 952de13e9f25b..7df86d03ff4e3 100644 --- a/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java +++ b/src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystem.java @@ -31,6 +31,11 @@ */ public interface CgroupSubsystem extends Metrics { + + default boolean isContainerized() { + return false; // This default impl is never used + } + /** * Returned for metrics of type long if the underlying implementation * has determined that no limit is being imposed. diff --git a/src/java.base/linux/native/libjava/CgroupMetrics.c b/src/java.base/linux/native/libjava/CgroupMetrics.c index a5e41167bc319..e2f98633459be 100644 --- a/src/java.base/linux/native/libjava/CgroupMetrics.c +++ b/src/java.base/linux/native/libjava/CgroupMetrics.c @@ -36,6 +36,12 @@ Java_jdk_internal_platform_CgroupMetrics_isUseContainerSupport(JNIEnv *env, jcla return JVM_IsUseContainerSupport(); } +JNIEXPORT jboolean JNICALL +Java_jdk_internal_platform_CgroupMetrics_isContainerized0(JNIEnv *env, jclass ignored) +{ + return JVM_IsContainerized(); +} + JNIEXPORT jlong JNICALL Java_jdk_internal_platform_CgroupMetrics_getTotalMemorySize0 (JNIEnv *env, jclass ignored) diff --git a/src/java.base/share/classes/jdk/internal/platform/Metrics.java b/src/java.base/share/classes/jdk/internal/platform/Metrics.java index 50523d137ef5d..07d60f7f9fe88 100644 --- a/src/java.base/share/classes/jdk/internal/platform/Metrics.java +++ b/src/java.base/share/classes/jdk/internal/platform/Metrics.java @@ -71,6 +71,23 @@ public static Metrics systemMetrics() { */ public String getProvider(); + /** + * Determines whether or not the underlying system + * has useful metrics (a.k.a. is containerized). + * + * @implNote + * Note that Metrics on some systems aren't useful. + * For example on a regular Linux system with cgroups + * present, with no limits enforced and not running in + * a container, Metric aren't useful. This can be used + * in order to determine if the system is containerized. + * + * @return true when the JVM runs in containerized mode. + * false otherwise. + * + */ + public boolean isContainerized(); + /* *************************************************************** * CPU Accounting Subsystem diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 601155260273a..ccb82c84c92e4 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -370,6 +370,10 @@ private static void printSystemMetrics() { final long longRetvalNotSupported = -2; ostream.println(INDENT + "Provider: " + c.getProvider()); + if (!c.isContainerized()) { + ostream.println(INDENT + "System not containerized."); + return; + } ostream.println(INDENT + "Effective CPU Count: " + c.getEffectiveCpuCount()); ostream.println(formatCpuVal(c.getCpuPeriod(), INDENT + "CPU Period: ", longRetvalNotSupported)); ostream.println(formatCpuVal(c.getCpuQuota(), INDENT + "CPU Quota: ", longRetvalNotSupported)); diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index aa1d2a19b28ec..0f054a3bd7293 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -78,6 +78,9 @@ class TestController : public CgroupController { char* subsystem_path() override { return _path; }; + bool is_read_only() override { + return true; // doesn't matter + } }; static void fill_file(const char* path, const char* content) { @@ -436,7 +439,8 @@ TEST(cgroupTest, set_cgroupv1_subsystem_path) { &container_engine }; for (int i = 0; i < length; i++) { CgroupV1Controller* ctrl = new CgroupV1Controller( (char*)testCases[i]->root_path, - (char*)testCases[i]->mount_path); + (char*)testCases[i]->mount_path, + true /* read-only mount */); ctrl->set_subsystem_path((char*)testCases[i]->cgroup_path); ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); } @@ -460,7 +464,8 @@ TEST(cgroupTest, set_cgroupv2_subsystem_path) { &sub_path }; for (int i = 0; i < length; i++) { CgroupV2Controller* ctrl = new CgroupV2Controller( (char*)testCases[i]->mount_path, - (char*)testCases[i]->cgroup_path); + (char*)testCases[i]->cgroup_path, + true /* read-only mount */); ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); } } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 254e621bfdd47..0f574f7168a0c 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -113,7 +113,6 @@ runtime/ClassInitErrors/TestStackOverflowDuringInit.java 8334545 generic-all applications/jcstress/copy.java 8229852 linux-all -containers/cgroup/PlainRead.java 8333967,8261242 linux-all containers/docker/TestJcmd.java 8278102 linux-all containers/docker/TestMemoryAwareness.java 8303470 linux-all containers/docker/TestJFREvents.java 8327723 linux-x64 diff --git a/test/hotspot/jtreg/containers/cgroup/PlainRead.java b/test/hotspot/jtreg/containers/cgroup/TestContainerized.java similarity index 54% rename from test/hotspot/jtreg/containers/cgroup/PlainRead.java rename to test/hotspot/jtreg/containers/cgroup/TestContainerized.java index 21eccd79835d4..52cf5451a8d5c 100644 --- a/test/hotspot/jtreg/containers/cgroup/PlainRead.java +++ b/test/hotspot/jtreg/containers/cgroup/TestContainerized.java @@ -22,57 +22,27 @@ */ /* - * @test PlainRead + * @test + * @bug 8261242 * @key cgroups * @requires os.family == "linux" * @requires vm.flagless * @library /testlibrary /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI PlainRead + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestContainerized */ import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Platform; import jdk.test.whitebox.WhiteBox; -public class PlainRead { - - static public void match(OutputAnalyzer oa, String what, String value) { - oa.shouldMatch("^.*" + what + " *" + value + ".*$"); - } - - static public void noMatch(OutputAnalyzer oa, String what, String value) { - oa.shouldNotMatch("^.*" + what + " *" + value + ".*$"); - } - - static final String good_value = "(\\d+|-1|-2|Unlimited)"; - static final String bad_value = "(failed)"; - - static final String[] variables = {"Memory Limit is:", "CPU Quota is:", "CPU Period is:", "active_processor_count:"}; - - static public void isContainer(OutputAnalyzer oa) { - for (String v: variables) { - match(oa, v, good_value); - } - for (String v: variables) { - noMatch(oa, v, bad_value); - } - } - - static public void isNotContainer(OutputAnalyzer oa) { - oa.shouldMatch("^.*Can't open /proc/self/mountinfo.*$"); - } +public class TestContainerized { public static void main(String[] args) throws Exception { WhiteBox wb = WhiteBox.getWhiteBox(); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:os+container=trace", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - if (wb.isContainerized()) { - System.out.println("Inside a cgroup, testing..."); - isContainer(output); + throw new RuntimeException("Test failed! Expected not containerized on plain Linux."); } + System.out.println("Plain linux, no limits. Passed!"); } } diff --git a/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java new file mode 100644 index 0000000000000..8d9279e1603c1 --- /dev/null +++ b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 cgroups + * @requires os.family == "linux" + * @requires vm.flagless + * @library /test/lib + * @build TestSystemSettings + * @run main/othervm TestSystemSettings + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestSystemSettings { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XshowSettings:system", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldContain("System not containerized."); + } +} diff --git a/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java index a6eff3d237aa4..0b29d288cd92d 100644 --- a/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java +++ b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java @@ -69,6 +69,16 @@ private void testAll(Metrics m, boolean inContainer) throws Exception { tester.testMemoryUsage(); } tester.testMisc(); + testContainerized(m, inContainer); + } + + private void testContainerized(Metrics m, boolean inContainer) { + if (m.isContainerized() != inContainer) { + throw new RuntimeException("containerized test failed. " + + "Expected isContainerized()==" + inContainer + + " but got '" + m.isContainerized() + "'"); + } + System.out.println("testContainerized() PASSED!"); } public static void main(String[] args) throws Exception { From 747e1e47f576b0ca3ac97d1deea87418e67ff2d1 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Mon, 1 Jul 2024 10:21:31 +0000 Subject: [PATCH 112/288] 8334295: CTW: update modules Reviewed-by: shade, thartmann --- .../applications/ctw/modules/generate.bash | 4 +- .../ctw/modules/jdk_incubator_vector.java | 38 +++++++++++++++++++ .../ctw/modules/jdk_internal_md.java | 38 +++++++++++++++++++ .../ctw/modules/jdk_jpackage.java | 38 +++++++++++++++++++ .../ctw/modules/jdk_nio_mapmode.java | 38 +++++++++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_incubator_vector.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_internal_md.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_jpackage.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/jdk_nio_mapmode.java diff --git a/test/hotspot/jtreg/applications/ctw/modules/generate.bash b/test/hotspot/jtreg/applications/ctw/modules/generate.bash index 56e191e7af184..935503484b9c0 100644 --- a/test/hotspot/jtreg/applications/ctw/modules/generate.bash +++ b/test/hotspot/jtreg/applications/ctw/modules/generate.bash @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ do echo creating $file for $module... cat > $file < Date: Mon, 1 Jul 2024 11:51:13 +0000 Subject: [PATCH 113/288] 8335060: ClassCastException after JDK-8294960 Reviewed-by: liach, jpai --- .../invoke/TypeConvertingMethodAdapter.java | 16 +- .../java/lang/invoke/TypeConvertingTest.java | 798 ++++++++++++++++++ 2 files changed, 806 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/lang/invoke/TypeConvertingTest.java diff --git a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java index e35271dc8b42c..7a1419f03b109 100644 --- a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java +++ b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java @@ -69,14 +69,14 @@ private static MethodRefEntry unbox(ClassDesc owner, String methodName, ClassDes } private static TypeKind primitiveTypeKindFromClass(Class type) { - if (type == int.class) return TypeKind.IntType; - if (type == long.class) return TypeKind.LongType; - if (type == boolean.class) return TypeKind.BooleanType; - if (type == short.class) return TypeKind.ShortType; - if (type == byte.class) return TypeKind.ByteType; - if (type == char.class) return TypeKind.CharType; - if (type == float.class) return TypeKind.FloatType; - if (type == double.class) return TypeKind.DoubleType; + if (type == Integer.class) return TypeKind.IntType; + if (type == Long.class) return TypeKind.LongType; + if (type == Boolean.class) return TypeKind.BooleanType; + if (type == Short.class) return TypeKind.ShortType; + if (type == Byte.class) return TypeKind.ByteType; + if (type == Character.class) return TypeKind.CharType; + if (type == Float.class) return TypeKind.FloatType; + if (type == Double.class) return TypeKind.DoubleType; return null; } diff --git a/test/jdk/java/lang/invoke/TypeConvertingTest.java b/test/jdk/java/lang/invoke/TypeConvertingTest.java new file mode 100644 index 0000000000000..1df6e007880d1 --- /dev/null +++ b/test/jdk/java/lang/invoke/TypeConvertingTest.java @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/* @test + * @bug 8335060 + * @summary unit tests of TypeConvertingMethodAdapter + * @run junit TypeConvertingTest + */ +public class TypeConvertingTest { + + static void smallBooleanC(boolean b) { + assertTrue(b); + } + + static void bigBooleanC(Boolean b) { + assertTrue(b); + } + + static void smallByteC(byte b) { + assertEquals(1, b); + } + + static void bigByteC(Byte b) { + assertEquals((byte)1, b); + } + + static void smallShortC(short s) { + assertEquals(1, s); + } + + static void bigShortC(Short s) { + assertEquals((short)1, s); + } + + static void smallCharC(char c) { + assertEquals(1, c); + } + + static void bigCharC(Character c) { + assertEquals((char)1, c); + } + + static void smallIntC(int i) { + assertEquals(1, i); + } + + static void bigIntC(Integer i) { + assertEquals(1, i); + } + + static void smallLongC(long l) { + assertEquals(1, l); + } + + static void bigLongC(Long l) { + assertEquals(1, l); + } + + static void smallFloatC(float f) { + assertEquals(1.0f, f); + } + + static void bigFloatC(Float f) { + assertEquals(1.0f, f); + } + + static void smallDoubleC(double d) { + assertEquals(1.0, d); + } + + static void bigDoubleC(Double d) { + assertEquals(1.0, d); + } + + static void numberC(Number n) { + assertEquals(1, n.intValue()); + } + + + static boolean smallBooleanS() {return true;} + + static Boolean bigBooleanS() {return true;} + + static byte smallByteS() {return 1;} + + static Byte bigByteS() {return 1;} + + static short smallShortS() {return 1;} + + static Short bigShortS() {return 1;} + + static char smallCharS() {return 1;} + + static Character bigCharS() {return 1;} + + static int smallIntS() {return 1;} + + static Integer bigIntS() {return 1;} + + static long smallLongS() {return 1;} + + static Long bigLongS() {return 1l;} + + static float smallFloatS() {return 1;} + + static Float bigFloatS() {return 1f;} + + static double smallDoubleS() {return 1;} + + static Double bigDoubleS() {return 1d;} + + static Number numberS() {return 1;} + + + interface GenericC { + void m(T t); + } + + interface SmallBooleanC { + void m(boolean b); + } + + interface BigBooleanC { + void m(Boolean b); + } + + interface SmallByteC { + void m(byte b); + } + + interface BigByteC { + void m(Byte b); + } + + interface SmallShortC { + void m(short s); + } + + interface BigShortC { + void m(Short s); + } + + interface SmallCharC { + void m(char c); + } + + interface BigCharC { + void m(Character c); + } + + interface SmallIntC { + void m(int i); + } + + interface BigIntC { + void m(Integer i); + } + + interface SmallLongC { + void m(long l); + } + + interface BigLongC { + void m(Long l); + } + + interface SmallFloatC { + void m(float f); + } + + interface BigFloatC { + void m(Float f); + } + + interface SmallDoubleC { + void m(double d); + } + + interface BigDoubleC { + void m(Double d); + } + + interface BigNumberC { + void m(Number n); + } + + + interface GenericS { + T m(); + } + + interface SmallBooleanS { + boolean m(); + } + + interface BigBooleanS { + Boolean m(); + } + + interface SmallByteS { + byte m(); + } + + interface BigByteS { + Byte m(); + } + + interface SmallShortS { + short m(); + } + + interface BigShortS { + Short m(); + } + + interface SmallCharS { + char m(); + } + + interface BigCharS { + Character m(); + } + + interface SmallIntS { + int m(); + } + + interface BigIntS { + Integer m(); + } + + interface SmallLongS { + long m(); + } + + interface BigLongS { + Long m(); + } + + interface SmallFloatS { + float m(); + } + + interface BigFloatS { + Float m(); + } + + interface SmallDoubleS { + double m(); + } + + interface BigDoubleS { + Double m(); + } + + interface BigNumberS { + Number m(); + } + + + static void testGenericBoolean(GenericC t) { + t.m(true); + } + + static void testGenericByte(GenericC t) { + t.m((byte)1); + } + + static void testGenericShort(GenericC t) { + t.m((short)1); + } + + static void testGenericChar(GenericC t) { + t.m((char)1); + } + + static void testGenericInt(GenericC t) { + t.m(1); + } + + static void testGenericLong(GenericC t) { + t.m(1l); + } + + static void testGenericFloat(GenericC t) { + t.m(1.0f); + } + + static void testGenericDouble(GenericC t) { + t.m(1.0d); + } + + static void testGenericNumber(GenericC t) { + t.m(1); + } + + static void testSmallBoolean(SmallBooleanC t) { + t.m(true); + } + + static void testSmallByte(SmallByteC t) { + t.m((byte)1); + } + + static void testSmallShort(SmallShortC t) { + t.m((short)1); + } + + static void testSmallChar(SmallCharC t) { + t.m((char)1); + } + + static void testSmallInt(SmallIntC t) { + t.m(1); + } + + static void testSmallLong(SmallLongC t) { + t.m(1l); + } + + static void testSmallFloat(SmallFloatC t) { + t.m(1.0f); + } + + static void testSmallDouble(SmallDoubleC t) { + t.m(1.0d); + } + + static void testBigBoolean(BigBooleanC t) { + t.m(true); + } + + static void testBigByte(BigByteC t) { + t.m((byte)1); + } + + static void testBigShort(BigShortC t) { + t.m((short)1); + } + + static void testBigChar(BigCharC t) { + t.m((char)1); + } + + static void testBigInt(BigIntC t) { + t.m(1); + } + + static void testBigLong(BigLongC t) { + t.m(1l); + } + + static void testBigFloat(BigFloatC t) { + t.m(1.0f); + } + + static void testBigDouble(BigDoubleC t) { + t.m(1.0d); + } + + static void testBigNumber(BigNumberC t) { + t.m(1); + } + + + static void testGenericBoolean(GenericS t) { + assertEquals(true, t.m()); + } + + static void testGenericByte(GenericS t) { + assertEquals((byte)1, t.m()); + } + + static void testGenericShort(GenericS t) { + assertEquals((short)1, t.m()); + } + + static void testGenericChar(GenericS t) { + assertEquals((char)1, t.m()); + } + + static void testGenericInt(GenericS t) { + assertEquals(1, t.m()); + } + + static void testGenericLong(GenericS t) { + assertEquals(1, t.m()); + } + + static void testGenericFloat(GenericS t) { + assertEquals(1.0f, t.m()); + } + + static void testGenericDouble(GenericS t) { + assertEquals(1.0d, t.m()); + } + + static void testGenericNumber(GenericS t) { + assertEquals(1, t.m().intValue()); + } + + static void testSmallBoolean(SmallBooleanS t) { + assertEquals(true, t.m()); + } + + static void testSmallByte(SmallByteS t) { + assertEquals(1, t.m()); + } + + static void testSmallShort(SmallShortS t) { + assertEquals(1, t.m()); + } + + static void testSmallChar(SmallCharS t) { + assertEquals(1, t.m()); + } + + static void testSmallInt(SmallIntS t) { + assertEquals(1, t.m()); + } + + static void testSmallLong(SmallLongS t) { + assertEquals(1, t.m()); + } + + static void testSmallFloat(SmallFloatS t) { + assertEquals(1.0f, t.m()); + } + + static void testSmallDouble(SmallDoubleS t) { + assertEquals(1.0d, t.m()); + } + + static void testBigBoolean(BigBooleanS t) { + assertEquals(true, t.m()); + } + + static void testBigByte(BigByteS t) { + assertEquals((byte)1, t.m()); + } + + static void testBigShort(BigShortS t) { + assertEquals((short)1, t.m()); + } + + static void testBigChar(BigCharS t) { + assertEquals((char)1, t.m()); + } + + static void testBigInt(BigIntS t) { + assertEquals(1, t.m()); + } + + static void testBigLong(BigLongS t) { + assertEquals(1, t.m()); + } + + static void testBigFloat(BigFloatS t) { + assertEquals(1.0f, t.m()); + } + + static void testBigDouble(BigDoubleS t) { + assertEquals(1.0f, t.m()); + } + + static void testBigNumber(BigNumberS t) { + assertEquals(1, t.m().intValue()); + } + + + @Test + void testGenericBoolean() { + testGenericBoolean(TypeConvertingTest::smallBooleanC); + testGenericBoolean(TypeConvertingTest::bigBooleanC); + + testGenericBoolean(TypeConvertingTest::smallBooleanS); + testGenericBoolean(TypeConvertingTest::bigBooleanS); + } + + @Test + void testGenericByte() { + testGenericByte(TypeConvertingTest::smallByteC); + testGenericByte(TypeConvertingTest::bigByteC); + testGenericByte(TypeConvertingTest::smallShortC); + testGenericByte(TypeConvertingTest::smallIntC); + testGenericByte(TypeConvertingTest::smallLongC); + testGenericByte(TypeConvertingTest::smallFloatC); + testGenericByte(TypeConvertingTest::smallDoubleC); + testGenericByte(TypeConvertingTest::numberC); + + testGenericByte(TypeConvertingTest::smallByteS); + testGenericByte(TypeConvertingTest::bigByteS); + } + + @Test + void testGenericShort() { + testGenericShort(TypeConvertingTest::smallShortC); + testGenericShort(TypeConvertingTest::bigShortC); + testGenericShort(TypeConvertingTest::smallIntC); + testGenericShort(TypeConvertingTest::smallLongC); + testGenericShort(TypeConvertingTest::smallFloatC); + testGenericShort(TypeConvertingTest::smallDoubleC); + testGenericShort(TypeConvertingTest::numberC); + + testGenericShort(TypeConvertingTest::smallShortS); + testGenericShort(TypeConvertingTest::bigShortS); + } + + @Test + void testGenericChar() { + testGenericChar(TypeConvertingTest::smallCharC); + testGenericChar(TypeConvertingTest::bigCharC); + testGenericChar(TypeConvertingTest::smallIntC); + testGenericChar(TypeConvertingTest::smallLongC); + testGenericChar(TypeConvertingTest::smallFloatC); + testGenericChar(TypeConvertingTest::smallDoubleC); + + testGenericChar(TypeConvertingTest::smallCharS); + testGenericChar(TypeConvertingTest::bigCharS); + } + + @Test + void testGenericInt() { + testGenericInt(TypeConvertingTest::smallIntC); + testGenericInt(TypeConvertingTest::bigIntC); + testGenericInt(TypeConvertingTest::smallLongC); + testGenericInt(TypeConvertingTest::smallFloatC); + testGenericInt(TypeConvertingTest::smallDoubleC); + testGenericInt(TypeConvertingTest::numberC); + + testGenericInt(TypeConvertingTest::smallIntS); + testGenericInt(TypeConvertingTest::bigIntS); + } + + @Test + void testGenericLong() { + testGenericLong(TypeConvertingTest::smallLongC); + testGenericLong(TypeConvertingTest::bigLongC); + testGenericLong(TypeConvertingTest::smallFloatC); + testGenericLong(TypeConvertingTest::smallDoubleC); + testGenericLong(TypeConvertingTest::numberC); + + testGenericLong(TypeConvertingTest::smallLongS); + testGenericLong(TypeConvertingTest::bigLongS); + } + + @Test + void testGenericFloat() { + testGenericFloat(TypeConvertingTest::smallFloatC); + testGenericFloat(TypeConvertingTest::bigFloatC); + testGenericFloat(TypeConvertingTest::smallDoubleC); + testGenericFloat(TypeConvertingTest::numberC); + + testGenericFloat(TypeConvertingTest::smallFloatS); + testGenericFloat(TypeConvertingTest::bigFloatS); + } + + @Test + void testGenericDouble() { + testGenericDouble(TypeConvertingTest::smallDoubleC); + testGenericDouble(TypeConvertingTest::bigDoubleC); + testGenericDouble(TypeConvertingTest::numberC); + + testGenericDouble(TypeConvertingTest::smallDoubleS); + testGenericDouble(TypeConvertingTest::bigDoubleS); + } + + @Test + void testGenericNumber() { + testGenericNumber(TypeConvertingTest::numberC); + + testGenericNumber(TypeConvertingTest::numberS); + } + + @Test + void testSmallBoolean() { + testSmallBoolean(TypeConvertingTest::smallBooleanC); + testSmallBoolean(TypeConvertingTest::bigBooleanC); + + testSmallBoolean(TypeConvertingTest::smallBooleanS); + testSmallBoolean(TypeConvertingTest::bigBooleanS); + } + + @Test + void testSmallByte() { + testSmallByte(TypeConvertingTest::smallByteC); + testSmallByte(TypeConvertingTest::bigByteC); + testSmallByte(TypeConvertingTest::smallShortC); + testSmallByte(TypeConvertingTest::smallIntC); + testSmallByte(TypeConvertingTest::smallLongC); + testSmallByte(TypeConvertingTest::smallFloatC); + testSmallByte(TypeConvertingTest::smallDoubleC); + testSmallByte(TypeConvertingTest::numberC); + + testSmallByte(TypeConvertingTest::smallByteS); + testSmallByte(TypeConvertingTest::bigByteS); + } + + @Test + void testSmallShort() { + testSmallShort(TypeConvertingTest::smallShortC); + testSmallShort(TypeConvertingTest::bigShortC); + testSmallShort(TypeConvertingTest::smallIntC); + testSmallShort(TypeConvertingTest::smallLongC); + testSmallShort(TypeConvertingTest::smallFloatC); + testSmallShort(TypeConvertingTest::smallDoubleC); + testSmallShort(TypeConvertingTest::numberC); + + testSmallShort(TypeConvertingTest::smallShortS); + testSmallShort(TypeConvertingTest::bigShortS); + } + + @Test + void testSmallChar() { + testSmallChar(TypeConvertingTest::smallCharC); + testSmallChar(TypeConvertingTest::bigCharC); + testSmallChar(TypeConvertingTest::smallIntC); + testSmallChar(TypeConvertingTest::smallLongC); + testSmallChar(TypeConvertingTest::smallFloatC); + testSmallChar(TypeConvertingTest::smallDoubleC); + + testSmallChar(TypeConvertingTest::smallCharS); + testSmallChar(TypeConvertingTest::bigCharS); + } + + @Test + void testSmallInt() { + testSmallInt(TypeConvertingTest::smallIntC); + testSmallInt(TypeConvertingTest::bigIntC); + testSmallInt(TypeConvertingTest::smallLongC); + testSmallInt(TypeConvertingTest::smallFloatC); + testSmallInt(TypeConvertingTest::smallDoubleC); + testSmallInt(TypeConvertingTest::numberC); + + testSmallInt(TypeConvertingTest::smallIntS); + testSmallInt(TypeConvertingTest::bigIntS); + } + + @Test + void testSmallLong() { + testSmallLong(TypeConvertingTest::smallLongC); + testSmallLong(TypeConvertingTest::bigLongC); + testSmallLong(TypeConvertingTest::smallFloatC); + testSmallLong(TypeConvertingTest::smallDoubleC); + testSmallLong(TypeConvertingTest::numberC); + + testSmallLong(TypeConvertingTest::smallLongS); + testSmallLong(TypeConvertingTest::bigLongS); + } + + @Test + void testSmallFloat() { + testSmallFloat(TypeConvertingTest::smallFloatC); + testSmallFloat(TypeConvertingTest::bigFloatC); + testSmallFloat(TypeConvertingTest::smallDoubleC); + testSmallFloat(TypeConvertingTest::numberC); + + testSmallFloat(TypeConvertingTest::smallFloatS); + testSmallFloat(TypeConvertingTest::bigFloatS); + } + + @Test + void testSmallDouble() { + testSmallDouble(TypeConvertingTest::smallDoubleC); + testSmallDouble(TypeConvertingTest::bigDoubleC); + testSmallDouble(TypeConvertingTest::numberC); + + testSmallDouble(TypeConvertingTest::smallDoubleS); + testSmallDouble(TypeConvertingTest::bigDoubleS); + } + + @Test + void testBigBoolean() { + testBigBoolean(TypeConvertingTest::smallBooleanC); + testBigBoolean(TypeConvertingTest::bigBooleanC); + + testBigBoolean(TypeConvertingTest::smallBooleanS); + testBigBoolean(TypeConvertingTest::bigBooleanS); + } + + @Test + void testBigByte() { + testBigByte(TypeConvertingTest::smallByteC); + testBigByte(TypeConvertingTest::bigByteC); + testBigByte(TypeConvertingTest::smallShortC); + testBigByte(TypeConvertingTest::smallIntC); + testBigByte(TypeConvertingTest::smallLongC); + testBigByte(TypeConvertingTest::smallFloatC); + testBigByte(TypeConvertingTest::smallDoubleC); + testBigByte(TypeConvertingTest::numberC); + + testBigByte(TypeConvertingTest::smallByteS); + testBigByte(TypeConvertingTest::bigByteS); + } + + @Test + void testBigShort() { + testBigShort(TypeConvertingTest::smallShortC); + testBigShort(TypeConvertingTest::bigShortC); + testBigShort(TypeConvertingTest::smallIntC); + testBigShort(TypeConvertingTest::smallLongC); + testBigShort(TypeConvertingTest::smallFloatC); + testBigShort(TypeConvertingTest::smallDoubleC); + testBigShort(TypeConvertingTest::numberC); + + testBigShort(TypeConvertingTest::smallShortS); + testBigShort(TypeConvertingTest::bigShortS); + } + + @Test + void testBigChar() { + testBigChar(TypeConvertingTest::smallCharC); + testBigChar(TypeConvertingTest::bigCharC); + testBigChar(TypeConvertingTest::smallIntC); + testBigChar(TypeConvertingTest::smallLongC); + testBigChar(TypeConvertingTest::smallFloatC); + testBigChar(TypeConvertingTest::smallDoubleC); + + testBigChar(TypeConvertingTest::smallCharS); + testBigChar(TypeConvertingTest::bigCharS); + } + + @Test + void testBigInt() { + testBigInt(TypeConvertingTest::smallIntC); + testBigInt(TypeConvertingTest::bigIntC); + testBigInt(TypeConvertingTest::smallLongC); + testBigInt(TypeConvertingTest::smallFloatC); + testBigInt(TypeConvertingTest::smallDoubleC); + testBigInt(TypeConvertingTest::numberC); + + testBigInt(TypeConvertingTest::smallIntS); + testBigInt(TypeConvertingTest::bigIntS); + } + + @Test + void testBigLong() { + testBigLong(TypeConvertingTest::smallLongC); + testBigLong(TypeConvertingTest::bigLongC); + testBigLong(TypeConvertingTest::smallFloatC); + testBigLong(TypeConvertingTest::smallDoubleC); + testBigLong(TypeConvertingTest::numberC); + + testBigLong(TypeConvertingTest::smallLongS); + testBigLong(TypeConvertingTest::bigLongS); + } + + @Test + void testBigFloat() { + testBigFloat(TypeConvertingTest::smallFloatC); + testBigFloat(TypeConvertingTest::bigFloatC); + testBigFloat(TypeConvertingTest::smallDoubleC); + testBigFloat(TypeConvertingTest::numberC); + + testBigFloat(TypeConvertingTest::smallFloatS); + testBigFloat(TypeConvertingTest::bigFloatS); + } + + @Test + void testBigDouble() { + testBigDouble(TypeConvertingTest::smallDoubleC); + testBigDouble(TypeConvertingTest::bigDoubleC); + testBigDouble(TypeConvertingTest::numberC); + + testBigDouble(TypeConvertingTest::smallDoubleS); + testBigDouble(TypeConvertingTest::bigDoubleS); + } + + @Test + void testBigNumber() { + testBigNumber(TypeConvertingTest::numberC); + + testBigNumber(TypeConvertingTest::numberS); + } +} From 2f4f6cc34c10c5519c74abbce8d1715013b50d5d Mon Sep 17 00:00:00 2001 From: Arseny Bochkarev Date: Mon, 1 Jul 2024 12:19:49 +0000 Subject: [PATCH 114/288] 8317721: RISC-V: Implement CRC32 intrinsic Reviewed-by: vkempik, rehn --- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 17 +- .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 74 +++++- .../cpu/riscv/macroAssembler_riscv.cpp | 169 +++++++++++++ .../cpu/riscv/macroAssembler_riscv.hpp | 10 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 52 ++++ src/hotspot/cpu/riscv/stubRoutines_riscv.cpp | 222 ++++++++++++++++++ src/hotspot/cpu/riscv/stubRoutines_riscv.hpp | 3 + src/hotspot/cpu/riscv/vm_version_riscv.cpp | 10 +- 8 files changed, 553 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 9804eee61ffee..b2489268611b7 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1607,7 +1607,22 @@ void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ la(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } -void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { Unimplemented(); } +void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { + assert(op->crc()->is_single_cpu(), "crc must be register"); + assert(op->val()->is_single_cpu(), "byte value must be register"); + assert(op->result_opr()->is_single_cpu(), "result must be register"); + Register crc = op->crc()->as_register(); + Register val = op->val()->as_register(); + Register res = op->result_opr()->as_register(); + + assert_different_registers(val, crc, res); + __ la(res, ExternalAddress(StubRoutines::crc_table_addr())); + + __ notr(crc, crc); // ~crc + __ zero_extend(crc, crc, 32); + __ update_byte_crc32(crc, val, res); + __ notr(res, crc); // ~crc +} void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass, Register tmp, Label &next, Label &none, diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index 8017c0fc802d5..409e8dc0a0d95 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -781,7 +781,79 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { } void LIRGenerator::do_update_CRC32(Intrinsic* x) { - ShouldNotReachHere(); + assert(UseCRC32Intrinsics, "why are we here?"); + // Make all state_for calls early since they can emit code + LIR_Opr result = rlock_result(x); + switch (x->id()) { + case vmIntrinsics::_updateCRC32: { + LIRItem crc(x->argument_at(0), this); + LIRItem val(x->argument_at(1), this); + // val is destroyed by update_crc32 + val.set_destroys_register(); + crc.load_item(); + val.load_item(); + __ update_crc32(crc.result(), val.result(), result); + break; + } + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: { + bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32); + + LIRItem crc(x->argument_at(0), this); + LIRItem buf(x->argument_at(1), this); + LIRItem off(x->argument_at(2), this); + LIRItem len(x->argument_at(3), this); + buf.load_item(); + off.load_nonconstant(); + + LIR_Opr index = off.result(); + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + if (off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; + offset += off.result()->as_jint(); + } + LIR_Opr base_op = buf.result(); + + if (index->is_valid()) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + index = tmp; + } + + if (offset) { + LIR_Opr tmp = new_pointer_register(); + __ add(base_op, LIR_OprFact::intConst(offset), tmp); + base_op = tmp; + offset = 0; + } + + LIR_Address* a = new LIR_Address(base_op, + index, + offset, + T_BYTE); + BasicTypeList signature(3); + signature.append(T_INT); + signature.append(T_ADDRESS); + signature.append(T_INT); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + const LIR_Opr result_reg = result_register_for(x->type()); + + LIR_Opr addr = new_pointer_register(); + __ leal(LIR_OprFact::address(a), addr); + + crc.load_item_force(cc->at(0)); + __ move(addr, cc->at(1)); + len.load_item_force(cc->at(2)); + + __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), getThreadTemp(), result_reg, cc->args()); + __ move(result_reg, result); + + break; + } + default: { + ShouldNotReachHere(); + } + } } void LIRGenerator::do_update_CRC32C(Intrinsic* x) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 0e6a9099265ce..b707b20f6692a 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1428,6 +1428,175 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack) { return count; } +static const int64_t right_32_bits = right_n_bits(32); +static const int64_t right_8_bits = right_n_bits(8); + +/** + * Emits code to update CRC-32 with a byte value according to constants in table + * + * @param [in,out]crc Register containing the crc. + * @param [in]val Register containing the byte to fold into the CRC. + * @param [in]table Register containing the table of crc constants. + * + * uint32_t crc; + * val = crc_table[(val ^ crc) & 0xFF]; + * crc = val ^ (crc >> 8); + * + */ +void MacroAssembler::update_byte_crc32(Register crc, Register val, Register table) { + assert_different_registers(crc, val, table); + + xorr(val, val, crc); + andi(val, val, right_8_bits); + shadd(val, val, table, val, 2); + lwu(val, Address(val)); + srli(crc, crc, 8); + xorr(crc, val, crc); +} + +/** + * Emits code to update CRC-32 with a 32-bit value according to tables 0 to 3 + * + * @param [in,out]crc Register containing the crc. + * @param [in]v Register containing the 32-bit to fold into the CRC. + * @param [in]table0 Register containing table 0 of crc constants. + * @param [in]table1 Register containing table 1 of crc constants. + * @param [in]table2 Register containing table 2 of crc constants. + * @param [in]table3 Register containing table 3 of crc constants. + * + * uint32_t crc; + * v = crc ^ v + * crc = table3[v&0xff]^table2[(v>>8)&0xff]^table1[(v>>16)&0xff]^table0[v>>24] + * + */ +void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp1, Register tmp2, Register tmp3, + Register table0, Register table1, Register table2, Register table3, bool upper) { + assert_different_registers(crc, v, tmp1, tmp2, tmp3, table0, table1, table2, table3); + + if (upper) + srli(v, v, 32); + xorr(v, v, crc); + + andi(tmp1, v, right_8_bits); + shadd(tmp1, tmp1, table3, tmp2, 2); + lwu(crc, Address(tmp1)); + + slli(tmp1, v, 16); + slli(tmp3, v, 8); + + srliw(tmp1, tmp1, 24); + srliw(tmp3, tmp3, 24); + + shadd(tmp1, tmp1, table2, tmp1, 2); + lwu(tmp2, Address(tmp1)); + + shadd(tmp3, tmp3, table1, tmp3, 2); + xorr(crc, crc, tmp2); + + lwu(tmp2, Address(tmp3)); + if (upper) { + tmp1 = v; + srli(tmp1, v, 24); + } + else + srliw(tmp1, v, 24); + + // no need to clear bits other than lowest two + shadd(tmp1, tmp1, table0, tmp1, 2); + xorr(crc, crc, tmp2); + lwu(tmp2, Address(tmp1)); + xorr(crc, crc, tmp2); +} + +/** + * @param crc register containing existing CRC (32-bit) + * @param buf register pointing to input byte buffer (byte*) + * @param len register containing number of bytes + * @param table register that will contain address of CRC table + * @param tmp scratch registers + */ +void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, + Register table0, Register table1, Register table2, Register table3, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6) { + assert_different_registers(crc, buf, len, table0, table1, table2, table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + Label L_by16_loop, L_unroll_loop, L_unroll_loop_entry, L_by4, L_by4_loop, L_by1, L_by1_loop, L_exit; + + const int64_t unroll = 16; + const int64_t unroll_words = unroll*wordSize; + mv(tmp5, right_32_bits); + subw(len, len, unroll_words); + andn(crc, tmp5, crc); + + const ExternalAddress table_addr = StubRoutines::crc_table_addr(); + la(table0, table_addr); + add(table1, table0, 1*256*sizeof(juint), tmp1); + add(table2, table0, 2*256*sizeof(juint), tmp1); + add(table3, table2, 1*256*sizeof(juint), tmp1); + + bge(len, zr, L_unroll_loop_entry); + addiw(len, len, unroll_words-4); + bge(len, zr, L_by4_loop); + addiw(len, len, 4); + bgt(len, zr, L_by1_loop); + j(L_exit); + + align(CodeEntryAlignment); + bind(L_unroll_loop_entry); + const Register buf_end = tmp3; + add(buf_end, buf, len); // buf_end will be used as endpoint for loop below + andi(len, len, unroll_words-1); // len = (len % unroll_words) + sub(len, len, unroll_words); // Length after all iterations + bind(L_unroll_loop); + for (int i = 0; i < unroll; i++) { + ld(tmp1, Address(buf, i*wordSize)); + update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, false); + update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, true); + } + + addi(buf, buf, unroll_words); + ble(buf, buf_end, L_unroll_loop); + addiw(len, len, unroll_words-4); + bge(len, zr, L_by4_loop); + addiw(len, len, 4); + bgt(len, zr, L_by1_loop); + j(L_exit); + + bind(L_by4_loop); + lwu(tmp1, Address(buf)); + update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, false); + subw(len, len, 4); + addi(buf, buf, 4); + bge(len, zr, L_by4_loop); + addiw(len, len, 4); + ble(len, zr, L_exit); + + bind(L_by1_loop); + subw(len, len, 1); + lwu(tmp1, Address(buf)); + andi(tmp2, tmp1, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + ble(len, zr, L_exit); + + subw(len, len, 1); + srli(tmp2, tmp1, 8); + andi(tmp2, tmp2, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + ble(len, zr, L_exit); + + subw(len, len, 1); + srli(tmp2, tmp1, 16); + andi(tmp2, tmp2, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + ble(len, zr, L_exit); + + srli(tmp2, tmp1, 24); + andi(tmp2, tmp2, right_8_bits); + update_byte_crc32(crc, tmp2, table0); + + bind(L_exit); + andn(crc, tmp5, crc); +} + #ifdef COMPILER2 // Push vector registers in the bitset supplied. // Return the number of words pushed diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 4373ebada146a..ddd3c48a93e10 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1288,6 +1288,15 @@ class MacroAssembler: public Assembler { void compute_match_mask(Register src, Register pattern, Register match_mask, Register mask1, Register mask2); + // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. + void kernel_crc32(Register crc, Register buf, Register len, + Register table0, Register table1, Register table2, Register table3, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6); + void update_word_crc32(Register crc, Register v, Register tmp1, Register tmp2, Register tmp3, + Register table0, Register table1, Register table2, Register table3, + bool upper); + void update_byte_crc32(Register crc, Register val, Register table); + #ifdef COMPILER2 void mul_add(Register out, Register in, Register offset, Register len, Register k, Register tmp); @@ -1317,6 +1326,7 @@ class MacroAssembler: public Assembler { Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register product_hi); + #endif void inflate_lo32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 3a34e87c14006..61c7a8668f55a 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -5313,6 +5313,52 @@ static const int64_t right_3_bits = right_n_bits(3); #endif // COMPILER2 + /** + * Arguments: + * + * Inputs: + * c_rarg0 - int crc + * c_rarg1 - byte* buf + * c_rarg2 - int length + * + * Output: + * c_rarg0 - int crc result + */ + address generate_updateBytesCRC32() { + assert(UseCRC32Intrinsics, "what are we doing here?"); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32"); + + address start = __ pc(); + + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + const Register table0 = c_rarg3; // crc_table address + const Register table1 = c_rarg4; + const Register table2 = c_rarg5; + const Register table3 = c_rarg6; + + const Register tmp1 = c_rarg7; + const Register tmp2 = t2; + const Register tmp3 = x28; // t3 + const Register tmp4 = x29; // t4 + const Register tmp5 = x30; // t5 + const Register tmp6 = x31; // t6 + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ kernel_crc32(crc, buf, len, table0, table1, table2, + table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(); + + return start; + } + #if INCLUDE_JFR static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { @@ -5559,6 +5605,12 @@ static const int64_t right_3_bits = right_n_bits(3); generate_throw_exception("delayed StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); + + if (UseCRC32Intrinsics) { + // set table address before stub generation which use it + StubRoutines::_crc_table_adr = (address)StubRoutines::riscv::_crc_table; + StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); + } } void generate_continuation_stubs() { diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp index 39068a9a026ac..05bdeaf757078 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -55,3 +55,225 @@ address StubRoutines::riscv::_string_indexof_linear_ul = nullptr; address StubRoutines::riscv::_large_byte_array_inflate = nullptr; bool StubRoutines::riscv::_completed = false; + +/** + * crc_table[] from jdk/src/java.base/share/native/libzip/zlib/crc32.h + */ +ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] = +{ + // Table 0 + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL, + + // Table 1 + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL, + + // Table 2 + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL, + + // Table 3 + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL, +}; diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp index 90a7e0967b240..46b5461d7770f 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp @@ -153,6 +153,9 @@ class riscv { static void set_completed() { _completed = true; } + +private: + static juint _crc_table[]; }; #endif // CPU_RISCV_STUBROUTINES_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index b9467bb2245da..b7517bc3f3f0c 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -131,8 +131,14 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } - if (UseCRC32Intrinsics) { - warning("CRC32 intrinsics are not available on this CPU."); + if (UseZba) { + if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { + FLAG_SET_DEFAULT(UseCRC32Intrinsics, true); + } + } else { + if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { + warning("CRC32 intrinsic requires Zba instructions (not available on this CPU)"); + } FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } From ee4720a75d815c84039055902c88b360737a1f9c Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 1 Jul 2024 20:38:55 +0000 Subject: [PATCH 115/288] 8333306: gc/arguments/TestParallelGCErgo.java fails when largepage are enabled Reviewed-by: ayang, zgu --- test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java index a84ebc5fe5cc6..63c51c25149e6 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java @@ -27,6 +27,7 @@ * @test TestParallelGCErgo * @bug 8272364 * @requires vm.gc.Parallel + * @requires vm.opt.UseLargePages == null | !vm.opt.UseLargePages * @summary Verify ParallelGC minimum young and old ergonomics are setup correctly * @modules java.base/jdk.internal.misc * @library /test/lib From 5fe07b36d9eb296661692d903ed0b9b5afefba0f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 2 Jul 2024 03:39:43 +0000 Subject: [PATCH 116/288] 5021949: JSplitPane setEnabled(false) shouldn't be partially functional Reviewed-by: abhiscxk, achung, aivanov --- .../share/classes/javax/swing/JSplitPane.java | 14 ++- .../plaf/basic/BasicSplitPaneDivider.java | 16 +++ .../JSplitPane/TestSplitPaneEnableTest.java | 109 ++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JSplitPane.java b/src/java.desktop/share/classes/javax/swing/JSplitPane.java index 14f62565d400d..7d4482af07ea8 100644 --- a/src/java.desktop/share/classes/javax/swing/JSplitPane.java +++ b/src/java.desktop/share/classes/javax/swing/JSplitPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.plaf.SplitPaneUI; +import javax.swing.plaf.basic.BasicSplitPaneUI; /** * JSplitPane is used to divide two (and only two) @@ -361,6 +362,17 @@ public JSplitPane(int newOrientation, } + /** + * {@inheritDoc} + * @param enabled {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (this.getUI() instanceof BasicSplitPaneUI) { + ((BasicSplitPaneUI)(this.getUI())).getDivider().setEnabled(enabled); + } + } /** * Sets the L&F object that renders this component. diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java index 3018de4fd9352..188e675388776 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -360,6 +360,20 @@ else if (e.getPropertyName() == JSplitPane. } } + /** + * {@inheritDoc} + * @param enabled {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + if (splitPane.isOneTouchExpandable() && + rightButton != null && + leftButton != null) { + + rightButton.setEnabled(enabled); + leftButton.setEnabled(enabled); + } + } /** * Paints the divider. @@ -472,6 +486,7 @@ public boolean isFocusTraversable() { b.setFocusPainted(false); b.setBorderPainted(false); b.setRequestFocusEnabled(false); + b.setEnabled(splitPane.isEnabled()); return b; } @@ -529,6 +544,7 @@ public boolean isFocusTraversable() { b.setFocusPainted(false); b.setBorderPainted(false); b.setRequestFocusEnabled(false); + b.setEnabled(splitPane.isEnabled()); return b; } diff --git a/test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java b/test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java new file mode 100644 index 0000000000000..0172e4b524297 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/TestSplitPaneEnableTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 5021949 + * @summary Verifies JSplitPane setEnabled(false) disables one touch expandable clicks + * @run main TestSplitPaneEnableTest + */ + +import java.awt.Point; +import java.awt.event.InputEvent; +import javax.swing.JButton; +import javax.swing.JSplitPane; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class TestSplitPaneEnableTest { + private static JButton leftOneTouchButton; + private static JButton rightOneTouchButton; + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + if (laf.getClassName().toLowerCase().contains("gtk")) { + continue; + } + System.out.println("Testing LAF : " + laf.getClassName()); + + SwingUtilities.invokeAndWait(() -> { + setLookAndFeel(laf); + JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + new JButton("Left"), new JButton("Right")); + jsp.setUI(new TestSplitPaneUI()); + jsp.setOneTouchExpandable(true); + jsp.setEnabled(false); + if (leftOneTouchButton.isEnabled()) { + throw new RuntimeException("leftButton is enabled for disabled JSplitPane"); + } + if (rightOneTouchButton.isEnabled()) { + throw new RuntimeException("rightButton is enabled for disabled JSplitPane"); + } + + }); + } + } + + static class TestSplitPaneUI extends BasicSplitPaneUI { + + public TestSplitPaneUI() { + super(); + } + + public BasicSplitPaneDivider createDefaultDivider() { + return new TestSplitPaneDivider(this); + } + } + + static class TestSplitPaneDivider extends BasicSplitPaneDivider { + + public TestSplitPaneDivider(BasicSplitPaneUI ui) { + super(ui); + } + + protected JButton createLeftOneTouchButton() { + leftOneTouchButton = super.createLeftOneTouchButton(); + return leftOneTouchButton; + } + + protected JButton createRightOneTouchButton() { + rightOneTouchButton = super.createRightOneTouchButton(); + return rightOneTouchButton; + } + } +} + From 318d9acadf305f9d7d0cd8bb54b41506dd9914a8 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 2 Jul 2024 05:56:21 +0000 Subject: [PATCH 117/288] 8335369: Fix -Wzero-as-null-pointer-constant warnings in ImmutableOopMapBuilder Reviewed-by: kvn, jwaters --- src/hotspot/share/compiler/oopMap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 80832cdacd4cb..634fb8b0bfae7 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -411,7 +411,7 @@ class ImmutableOopMapBuilder { Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(nullptr) {} - void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { + void set(kind_t kind, int offset, int size, const OopMap* map, const OopMap* other = nullptr) { _kind = kind; _offset = offset; _size = size; From 9046d7aee3082b6cbf79876efc1c508cb893caad Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 2 Jul 2024 08:20:26 +0000 Subject: [PATCH 118/288] 8335390: C2 MergeStores: wrong result with Unsafe Reviewed-by: thartmann, chagedorn, kvn --- src/hotspot/share/opto/memnode.cpp | 7 +- .../jtreg/compiler/c2/TestMergeStores.java | 5 +- .../c2/TestMergeStoresUnsafeArrayPointer.java | 132 ++++++++++++++++++ 3 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index d0b6c59637f13..ad3a948793fa1 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2984,6 +2984,9 @@ StoreNode* MergePrimitiveArrayStores::run() { type2aelembytes(bt) != _store->memory_size()) { return nullptr; } + if (_store->is_unsafe_access()) { + return nullptr; + } // The _store must be the "last" store in a chain. If we find a use we could merge with // then that use or a store further down is the "last" store. @@ -3017,11 +3020,13 @@ bool MergePrimitiveArrayStores::is_compatible_store(const StoreNode* other_store int opc = _store->Opcode(); assert(opc == Op_StoreB || opc == Op_StoreC || opc == Op_StoreI, "precondition"); assert(_store->adr_type()->isa_aryptr() != nullptr, "must be array store"); + assert(!_store->is_unsafe_access(), "no unsafe accesses"); if (other_store == nullptr || _store->Opcode() != other_store->Opcode() || other_store->adr_type() == nullptr || - other_store->adr_type()->isa_aryptr() == nullptr) { + other_store->adr_type()->isa_aryptr() == nullptr || + other_store->is_unsafe_access()) { return false; } diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index 0e86045618b9a..a94004d8e26c3 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -611,8 +611,9 @@ static Object[] test1e(byte[] a) { } @Test - @IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, - applyIf = {"UseUnalignedAccesses", "true"}) + // Disabled by JDK-8335390, to be enabled again by JDK-8335392. + // @IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, + // applyIf = {"UseUnalignedAccesses", "true"}) static Object[] test1f(byte[] a) { UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 0, (byte)0xbe); UNSAFE.putByte(a, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 1, (byte)0xba); diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java b/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java new file mode 100644 index 0000000000000..dbfdfe6895766 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStoresUnsafeArrayPointer.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8335390 + * @summary Test merge stores for some Unsafe store address patterns. + * @modules java.base/jdk.internal.misc + * @requires vm.bits == 64 + * @requires os.maxMemory > 8G + * @run main/othervm -XX:CompileCommand=compileonly,compiler.c2.TestMergeStoresUnsafeArrayPointer::test* + * -Xbatch + * -Xmx8g + * compiler.c2.TestMergeStoresUnsafeArrayPointer + * @run main/othervm -Xmx8g + * compiler.c2.TestMergeStoresUnsafeArrayPointer + */ + +package compiler.c2; +import jdk.internal.misc.Unsafe; + +public class TestMergeStoresUnsafeArrayPointer { + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + // We allocate a big int array of length: + static final int SIZE = (1 << 30) + 100; + + // This gives us a memory region of 4x as many bytes: + static final long BYTE_SIZE = 4L * SIZE; // = 1L << 32 + 400L + + // We set an "anchor" in the middle of this memory region, in bytes: + static final long ANCHOR = BYTE_SIZE / 2; + + static int four = 4; + + public static void main(String[] args) { + System.out.println("Allocate big array of SIZE = " + SIZE); + int[] big = new int[SIZE]; + + // Each test is executed a few times, so that we can see the difference between + // interpreter and compiler. + int errors = 0; + + long val = 0; + System.out.println("test1"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test1(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test1 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + val = 0; + System.out.println("test2"); + for (int i = 0; i < 100_000; i++) { + testClear(big); + test2(big, ANCHOR); + long sum = testSum(big); + if (i == 0) { + val = sum; + } else { + if (sum != val) { + System.out.println("ERROR: test2 had wrong value: " + val + " != " + sum); + errors++; + break; + } + } + } + + if (errors > 0) { + throw new RuntimeException("ERRORS: " + errors); + } + System.out.println("PASSED"); + } + + // Only clear and sum over relevant parts of array to make the test fast. + static void testClear(int[] a) { + for (int j = 0 ; j < 100; j++) { a[j] = j; } + for (int j = a.length/2 - 100; j < a.length/2 + 100; j++) { a[j] = j; } + for (int j = a.length - 100; j < a.length + 0; j++) { a[j] = j; } + } + + static long testSum(int[] a) { + long sum = 0; + for (int j = 0 ; j < 100; j++) { sum += a[j]; } + for (int j = a.length/2 - 100; j < a.length/2 + 100; j++) { sum += a[j]; } + for (int j = a.length - 100; j < a.length + 0; j++) { sum += a[j]; } + return sum; + } + + // Reference: expected to merge. + static void test1(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + anchor; + UNSAFE.putInt(a, base + 0, 0x42424242); + UNSAFE.putInt(a, base + 4, 0x66666666); + } + + // Test: if MergeStores is applied this can lead to wrong results + static void test2(int[] a, long anchor) { + long base = UNSAFE.ARRAY_INT_BASE_OFFSET + ANCHOR; + UNSAFE.putInt(a, base + 0 + (long)(four + Integer.MAX_VALUE), 0x42424242); + UNSAFE.putInt(a, base + Integer.MAX_VALUE + (long)(four + 4 ), 0x66666666); + } +} From 4060b35b1d00fccbec4b20353063f77c43ecc686 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 2 Jul 2024 08:58:20 +0000 Subject: [PATCH 119/288] 8335298: Fix -Wzero-as-null-pointer-constant warning in G1CardSetContainers Reviewed-by: iwalulya, ayang --- .../share/gc/g1/g1CardSetContainers.hpp | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 43e6c8a3bf7eb..84e6e3e9274a3 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,12 +86,22 @@ class G1CardSetInlinePtr : public StackObj { uint find(uint const card_idx, uint const bits_per_card, uint start_at, uint num_cards); + static ContainerPtr empty_card_set() { + // Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114573 + // gcc issues -Wzero-as-null-pointer-constant here, even though + // ContainerInlinePtr is a *non-literal* constant 0. We cast a non-const + // copy, and let the compiler's constant propagation optimize into + // equivalent code. + static_assert(G1CardSet::ContainerInlinePtr == 0, "unnecessary warning dodge"); + auto value = G1CardSet::ContainerInlinePtr; + return reinterpret_cast(value); + } + public: - G1CardSetInlinePtr() : _value_addr(nullptr), _value((ContainerPtr)G1CardSet::ContainerInlinePtr) { } + G1CardSetInlinePtr() : G1CardSetInlinePtr(empty_card_set()) {} - G1CardSetInlinePtr(ContainerPtr value) : _value_addr(nullptr), _value(value) { - assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); - } + explicit G1CardSetInlinePtr(ContainerPtr value) : + G1CardSetInlinePtr(nullptr, value) {} G1CardSetInlinePtr(ContainerPtr volatile* value_addr, ContainerPtr value) : _value_addr(value_addr), _value(value) { assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); From a537e87d2d2c6bff63f63bb436e3e919740221ce Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 2 Jul 2024 11:50:21 +0000 Subject: [PATCH 120/288] 8335530: Java file extension missing in AuthenticatorTest Reviewed-by: cstein, jpai --- ...thenticatorTest => AuthenticatorTest.java} | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) rename test/jdk/com/sun/net/httpserver/{AuthenticatorTest => AuthenticatorTest.java} (75%) diff --git a/test/jdk/com/sun/net/httpserver/AuthenticatorTest b/test/jdk/com/sun/net/httpserver/AuthenticatorTest.java similarity index 75% rename from test/jdk/com/sun/net/httpserver/AuthenticatorTest rename to test/jdk/com/sun/net/httpserver/AuthenticatorTest.java index 1fe7f3830356f..1456af618faf6 100644 --- a/test/jdk/com/sun/net/httpserver/AuthenticatorTest +++ b/test/jdk/com/sun/net/httpserver/AuthenticatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,36 +25,36 @@ * @test * @bug 8251496 * @summary Tests for methods in Authenticator - * @run testng/othervm AuthenticatorTest + * @run junit AuthenticatorTest */ import com.sun.net.httpserver.Authenticator; -import com.sun.net.httpserver.BasicAuthenticator; import com.sun.net.httpserver.HttpPrincipal; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class AuthenticatorTest { @Test public void testFailure() { var failureResult = new Authenticator.Failure(666); - assertEquals(failureResult.getResponseCode(), 666); + assertEquals(666, failureResult.getResponseCode()); } @Test public void testRetry() { var retryResult = new Authenticator.Retry(333); - assertEquals(retryResult.getResponseCode(), 333); + assertEquals(333, retryResult.getResponseCode()); } @Test - public void TestSuccess() { + public void testSuccess() { var principal = new HttpPrincipal("test", "123"); var successResult = new Authenticator.Success(principal); - assertEquals(successResult.getPrincipal(), principal); - assertEquals("test", principal.getName()); + assertEquals(principal, successResult.getPrincipal()); + assertEquals("test", principal.getUsername()); assertEquals("123", principal.getRealm()); } } From dd74e7f8c1570ed34c89f4aca184f5668e4471db Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Jul 2024 12:15:02 +0000 Subject: [PATCH 121/288] 8335147: Serial: Refactor TenuredGeneration::promote Reviewed-by: tschatzl, iwalulya --- .../share/gc/serial/defNewGeneration.cpp | 20 +++++++++---------- .../share/gc/serial/tenuredGeneration.cpp | 10 ++-------- .../share/gc/serial/tenuredGeneration.hpp | 5 ++--- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index b66681170c63c..593977030cbf1 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -768,25 +768,25 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { bool new_obj_is_tenured = false; // Otherwise try allocating obj tenured if (obj == nullptr) { - obj = _old_gen->promote(old, s); + obj = _old_gen->allocate_for_promotion(old, s); if (obj == nullptr) { handle_promotion_failure(old); return old; } - ContinuationGCSupport::transform_stack_chunk(obj); - new_obj_is_tenured = true; - } else { - // Prefetch beyond obj - const intx interval = PrefetchCopyIntervalInBytes; - Prefetch::write(obj, interval); + } + + // Prefetch beyond obj + const intx interval = PrefetchCopyIntervalInBytes; + Prefetch::write(obj, interval); - // Copy obj - Copy::aligned_disjoint_words(cast_from_oop(old), cast_from_oop(obj), s); + // Copy obj + Copy::aligned_disjoint_words(cast_from_oop(old), cast_from_oop(obj), s); - ContinuationGCSupport::transform_stack_chunk(obj); + ContinuationGCSupport::transform_stack_chunk(obj); + if (!new_obj_is_tenured) { // Increment age if obj still in new generation obj->incr_age(); age_table()->add(obj, s); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index 1cddce2dc514e..f1389b48557f8 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -387,7 +387,7 @@ bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) return res; } -oop TenuredGeneration::promote(oop obj, size_t obj_size) { +oop TenuredGeneration::allocate_for_promotion(oop obj, size_t obj_size) { assert(obj_size == obj->size(), "bad obj_size passed in"); #ifndef PRODUCT @@ -401,15 +401,9 @@ oop TenuredGeneration::promote(oop obj, size_t obj_size) { if (result == nullptr) { // Promotion of obj into gen failed. Try to expand and allocate. result = expand_and_allocate(obj_size, false); - if (result == nullptr) { - return nullptr; - } } - // Copy to new location. - Copy::aligned_disjoint_words(cast_from_oop(obj), result, obj_size); - oop new_obj = cast_to_oop(result); - return new_obj; + return cast_to_oop(result); } HeapWord* diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index dc2730eaf419d..bcb2d668213e8 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -163,12 +163,11 @@ class TenuredGeneration: public Generation { bool promotion_attempt_is_safe(size_t max_promoted_in_bytes) const; // "obj" is the address of an object in young-gen. Allocate space for "obj" - // in the old-gen, and copy "obj" into the newly allocated space, if - // possible, returning the result (or null if the allocation failed). + // in the old-gen, returning the result (or null if the allocation failed). // // The "obj_size" argument is just obj->size(), passed along so the caller can // avoid repeating the virtual call to retrieve it. - oop promote(oop obj, size_t obj_size); + oop allocate_for_promotion(oop obj, size_t obj_size); virtual void verify(); virtual void print_on(outputStream* st) const; From 685e5878b823fa5e3ae88ffd76de6507d6057af2 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan Date: Tue, 2 Jul 2024 14:36:29 +0000 Subject: [PATCH 122/288] 8334816: compiler/c2/irTests/TestIfMinMax.java fails after 8334629 Reviewed-by: thartmann, chagedorn --- test/hotspot/jtreg/ProblemList.txt | 1 - .../compiler/c2/irTests/TestIfMinMax.java | 24 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 0f574f7168a0c..2d1311e3ac127 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -53,7 +53,6 @@ compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all -compiler/c2/irTests/TestIfMinMax.java 8334816 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/codecache/CheckLargePages.java 8332654 linux-x64 diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index de0b41e73ea86..41402036aea0e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -181,19 +181,19 @@ static Object[] setupIntArrays() { int[] a = new int[512]; int[] b = new int[512]; - // Fill from 1 to 50 - for (int i = 0; i < 50; i++) { + // Fill from 1 to 125 + for (int i = 0; i < 125; i++) { a[i] = i + 1; b[i] = 1; } - // Fill from -1 to -50 - for (int i = 50; i < 100; i++) { - a[i] = -(i - 49); + // Fill from -1 to -125 + for (int i = 125; i < 250; i++) { + a[i] = -(i - 124); b[i] = 1; } - for (int i = 100; i < 512; i++) { + for (int i = 250; i < 512; i++) { a[i] = RANDOM.nextInt(); b[i] = 1; } @@ -206,19 +206,19 @@ static Object[] setupLongArrays() { long[] a = new long[512]; long[] b = new long[512]; - // Fill from 1 to 50 - for (int i = 0; i < 50; i++) { + // Fill from 1 to 125 + for (int i = 0; i < 125; i++) { a[i] = i + 1; b[i] = 1; } - // Fill from -1 to -50 - for (int i = 50; i < 100; i++) { - a[i] = -(i - 49); + // Fill from -1 to -125 + for (int i = 125; i < 250; i++) { + a[i] = -(i - 124); b[i] = 1; } - for (int i = 100; i < 512; i++) { + for (int i = 250; i < 512; i++) { a[i] = RANDOM.nextLong(); b[i] = 1; } From 153b12b9df87fdf8122cae3bf7f13078f55f7101 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 2 Jul 2024 15:38:54 +0000 Subject: [PATCH 123/288] 8331560: Refactor Hotspot container detection code so that subsystem delegates to controllers Reviewed-by: jsjolen, stuefe --- .../os/linux/cgroupSubsystem_linux.cpp | 123 ++++++++------- .../os/linux/cgroupSubsystem_linux.hpp | 59 +++++--- src/hotspot/os/linux/cgroupUtil_linux.cpp | 48 ++++++ src/hotspot/os/linux/cgroupUtil_linux.hpp | 37 +++++ .../os/linux/cgroupV1Subsystem_linux.cpp | 141 ++++++++++-------- .../os/linux/cgroupV1Subsystem_linux.hpp | 120 +++++++++------ .../os/linux/cgroupV2Subsystem_linux.cpp | 133 ++++++++++------- .../os/linux/cgroupV2Subsystem_linux.hpp | 114 +++++++++----- 8 files changed, 511 insertions(+), 264 deletions(-) create mode 100644 src/hotspot/os/linux/cgroupUtil_linux.cpp create mode 100644 src/hotspot/os/linux/cgroupUtil_linux.hpp diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 0dbd6ffd52be7..1da0e44dbf48e 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -28,6 +28,7 @@ #include "cgroupSubsystem_linux.hpp" #include "cgroupV1Subsystem_linux.hpp" #include "cgroupV2Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "os_linux.hpp" @@ -41,7 +42,7 @@ static const char* cg_controller_name[] = { "cpu", "cpuset", "cpuacct", "memory" CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupV1MemoryController* memory = nullptr; CgroupV1Controller* cpuset = nullptr; - CgroupV1Controller* cpu = nullptr; + CgroupV1CpuController* cpu = nullptr; CgroupV1Controller* cpuacct = nullptr; CgroupV1Controller* pids = nullptr; CgroupInfo cg_infos[CG_INFO_LENGTH]; @@ -61,14 +62,18 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { if (is_cgroup_v2(&cg_type_flags)) { // Cgroups v2 case, we have all the info we need. // Construct the subsystem, free resources and return - // Note: any index in cg_infos will do as the path is the same for - // all controllers. - CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, - cg_infos[MEMORY_IDX]._cgroup_path, - cg_infos[MEMORY_IDX]._read_only); + // Note: We use the memory for non-cpu non-memory controller look-ups. + // Perhaps we ought to have separate controllers for all. + CgroupV2Controller mem_other = CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, + cg_infos[MEMORY_IDX]._cgroup_path, + cg_infos[MEMORY_IDX]._read_only); + CgroupV2MemoryController* memory = new CgroupV2MemoryController(mem_other); + CgroupV2CpuController* cpu = new CgroupV2CpuController(CgroupV2Controller(cg_infos[CPU_IDX]._mount_path, + cg_infos[CPU_IDX]._cgroup_path, + cg_infos[CPU_IDX]._read_only)); log_debug(os, container)("Detected cgroups v2 unified hierarchy"); cleanup(cg_infos); - return new CgroupV2Subsystem(unified); + return new CgroupV2Subsystem(memory, cpu, mem_other); } /* @@ -102,13 +107,13 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupInfo info = cg_infos[i]; if (info._data_complete) { // pids controller might have incomplete data if (strcmp(info._name, "memory") == 0) { - memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path, info._read_only); + memory = new CgroupV1MemoryController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only)); memory->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuset") == 0) { cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); cpuset->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpu") == 0) { - cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); + cpu = new CgroupV1CpuController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only)); cpu->set_subsystem_path(info._cgroup_path); } else if (strcmp(info._name, "cpuacct") == 0) { cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only); @@ -556,13 +561,13 @@ void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) { */ int CgroupSubsystem::active_processor_count() { int quota_count = 0; - int cpu_count, limit_count; + int cpu_count; int result; // We use a cache with a timeout to avoid performing expensive // computations in the event this function is called frequently. // [See 8227006]. - CachingCgroupController* contrl = cpu_controller(); + CachingCgroupController* contrl = cpu_controller(); CachedMetric* cpu_limit = contrl->metrics_cache(); if (!cpu_limit->should_check_metric()) { int val = (int)cpu_limit->value(); @@ -570,23 +575,8 @@ int CgroupSubsystem::active_processor_count() { return val; } - cpu_count = limit_count = os::Linux::active_processor_count(); - int quota = cpu_quota(); - int period = cpu_period(); - - if (quota > -1 && period > 0) { - quota_count = ceilf((float)quota / (float)period); - log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); - } - - // Use quotas - if (quota_count != 0) { - limit_count = quota_count; - } - - result = MIN2(cpu_count, limit_count); - log_trace(os, container)("OSContainer::active_processor_count: %d", result); - + cpu_count = os::Linux::active_processor_count(); + result = CgroupUtil::processor_count(contrl->controller(), cpu_count); // Update cached metric to avoid re-reading container settings too often cpu_limit->set_value(result, OSCONTAINER_CACHE_TIMEOUT); @@ -603,35 +593,14 @@ int CgroupSubsystem::active_processor_count() { * OSCONTAINER_ERROR for not supported */ jlong CgroupSubsystem::memory_limit_in_bytes() { - CachingCgroupController* contrl = memory_controller(); + CachingCgroupController* contrl = memory_controller(); CachedMetric* memory_limit = contrl->metrics_cache(); if (!memory_limit->should_check_metric()) { return memory_limit->value(); } jlong phys_mem = os::Linux::physical_memory(); log_trace(os, container)("total physical memory: " JLONG_FORMAT, phys_mem); - jlong mem_limit = read_memory_limit_in_bytes(); - - if (mem_limit <= 0 || mem_limit >= phys_mem) { - jlong read_mem_limit = mem_limit; - const char *reason; - if (mem_limit >= phys_mem) { - // Exceeding physical memory is treated as unlimited. Cg v1's implementation - // of read_memory_limit_in_bytes() caps this at phys_mem since Cg v1 has no - // value to represent 'max'. Cg v2 may return a value >= phys_mem if e.g. the - // container engine was started with a memory flag exceeding it. - reason = "ignored"; - mem_limit = -1; - } else if (OSCONTAINER_ERROR == mem_limit) { - reason = "failed"; - } else { - assert(mem_limit == -1, "Expected unlimited"); - reason = "unlimited"; - } - log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, - reason, read_mem_limit, phys_mem); - } - + jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem); // Update cached metric to avoid re-reading container settings too often memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT); return mem_limit; @@ -796,3 +765,55 @@ jlong CgroupController::limit_from_str(char* limit_str) { } return (jlong)limit; } + +// CgroupSubsystem implementations + +jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + julong host_swap = os::Linux::host_swap(); + return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap); +} + +jlong CgroupSubsystem::memory_and_swap_usage_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + julong host_swap = os::Linux::host_swap(); + return memory_controller()->controller()->memory_and_swap_usage_in_bytes(phys_mem, host_swap); +} + +jlong CgroupSubsystem::memory_soft_limit_in_bytes() { + julong phys_mem = os::Linux::physical_memory(); + return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem); +} + +jlong CgroupSubsystem::memory_usage_in_bytes() { + return memory_controller()->controller()->memory_usage_in_bytes(); +} + +jlong CgroupSubsystem::memory_max_usage_in_bytes() { + return memory_controller()->controller()->memory_max_usage_in_bytes(); +} + +jlong CgroupSubsystem::rss_usage_in_bytes() { + return memory_controller()->controller()->rss_usage_in_bytes(); +} + +jlong CgroupSubsystem::cache_usage_in_bytes() { + return memory_controller()->controller()->cache_usage_in_bytes(); +} + +int CgroupSubsystem::cpu_quota() { + return cpu_controller()->controller()->cpu_quota(); +} + +int CgroupSubsystem::cpu_period() { + return cpu_controller()->controller()->cpu_period(); +} + +int CgroupSubsystem::cpu_shares() { + return cpu_controller()->controller()->cpu_shares(); +} + +void CgroupSubsystem::print_version_specific_info(outputStream* st) { + julong phys_mem = os::Linux::physical_memory(); + memory_controller()->controller()->print_version_specific_info(st, phys_mem); +} diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 00419c77570ae..4d5fa5d487900 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -180,48 +180,73 @@ class CachedMetric : public CHeapObj{ } }; +template class CachingCgroupController : public CHeapObj { private: - CgroupController* _controller; + T* _controller; CachedMetric* _metrics_cache; public: - CachingCgroupController(CgroupController* cont) { + CachingCgroupController(T* cont) { _controller = cont; _metrics_cache = new CachedMetric(); } CachedMetric* metrics_cache() { return _metrics_cache; } - CgroupController* controller() { return _controller; } + T* controller() { return _controller; } }; -class CgroupSubsystem: public CHeapObj { +// Pure virtual class representing version agnostic CPU controllers +class CgroupCpuController: public CHeapObj { public: - jlong memory_limit_in_bytes(); - int active_processor_count(); - virtual int cpu_quota() = 0; virtual int cpu_period() = 0; virtual int cpu_shares() = 0; - virtual jlong pids_max() = 0; - virtual jlong pids_current() = 0; + virtual bool is_read_only() = 0; +}; + +// Pure virtual class representing version agnostic memory controllers +class CgroupMemoryController: public CHeapObj { + public: + virtual jlong read_memory_limit_in_bytes(julong upper_bound) = 0; virtual jlong memory_usage_in_bytes() = 0; - virtual jlong memory_and_swap_limit_in_bytes() = 0; - virtual jlong memory_and_swap_usage_in_bytes() = 0; - virtual jlong memory_soft_limit_in_bytes() = 0; + virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0; + virtual jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) = 0; + virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0; virtual jlong memory_max_usage_in_bytes() = 0; virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; + virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0; + virtual bool is_read_only() = 0; +}; + +class CgroupSubsystem: public CHeapObj { + public: + jlong memory_limit_in_bytes(); + int active_processor_count(); + + virtual jlong pids_max() = 0; + virtual jlong pids_current() = 0; virtual bool is_containerized() = 0; virtual char * cpu_cpuset_cpus() = 0; virtual char * cpu_cpuset_memory_nodes() = 0; - virtual jlong read_memory_limit_in_bytes() = 0; virtual const char * container_type() = 0; - virtual CachingCgroupController* memory_controller() = 0; - virtual CachingCgroupController* cpu_controller() = 0; - - virtual void print_version_specific_info(outputStream* st) = 0; + virtual CachingCgroupController* memory_controller() = 0; + virtual CachingCgroupController* cpu_controller() = 0; + + int cpu_quota(); + int cpu_period(); + int cpu_shares(); + + jlong memory_usage_in_bytes(); + jlong memory_and_swap_limit_in_bytes(); + jlong memory_and_swap_usage_in_bytes(); + jlong memory_soft_limit_in_bytes(); + jlong memory_max_usage_in_bytes(); + jlong rss_usage_in_bytes(); + jlong cache_usage_in_bytes(); + void print_version_specific_info(outputStream* st); }; // Utility class for storing info retrieved from /proc/cgroups, diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp new file mode 100644 index 0000000000000..24046991905ee --- /dev/null +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 "cgroupUtil_linux.hpp" + +int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { + assert(host_cpus > 0, "physical host cpus must be positive"); + int limit_count = host_cpus; + int quota = cpu_ctrl->cpu_quota(); + int period = cpu_ctrl->cpu_period(); + int quota_count = 0; + int result = 0; + + if (quota > -1 && period > 0) { + quota_count = ceilf((float)quota / (float)period); + log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); + } + + // Use quotas + if (quota_count != 0) { + limit_count = quota_count; + } + + result = MIN2(host_cpus, limit_count); + log_trace(os, container)("OSContainer::active_processor_count: %d", result); + return result; +} diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp new file mode 100644 index 0000000000000..fdcc4806c3b93 --- /dev/null +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 CGROUP_UTIL_LINUX_HPP +#define CGROUP_UTIL_LINUX_HPP + +#include "utilities/globalDefinitions.hpp" +#include "cgroupSubsystem_linux.hpp" + +class CgroupUtil: AllStatic { + + public: + static int processor_count(CgroupCpuController* cpu, int host_cpus); +}; + +#endif // CGROUP_UTIL_LINUX_HPP diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 3f6ae813810f2..d7f9918afdad8 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -26,6 +26,7 @@ #include #include #include "cgroupV1Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "runtime/globals.hpp" @@ -76,42 +77,62 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { */ jlong CgroupV1MemoryController::uses_mem_hierarchy() { julong use_hierarchy; - CONTAINER_READ_NUMBER_CHECKED(this, "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy); return (jlong)use_hierarchy; } void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { - CgroupV1Controller::set_subsystem_path(cgroup_path); + reader()->set_subsystem_path(cgroup_path); jlong hierarchy = uses_mem_hierarchy(); if (hierarchy > 0) { set_hierarchical(true); } } -jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { +static inline +void verbose_log(julong read_mem_limit, julong host_mem) { + if (log_is_enabled(Debug, os, container)) { + jlong mem_limit = (jlong)read_mem_limit; // account for negative values + if (mem_limit < 0 || read_mem_limit >= host_mem) { + const char *reason; + if (mem_limit == OSCONTAINER_ERROR) { + reason = "failed"; + } else if (mem_limit == -1) { + reason = "unlimited"; + } else { + assert(read_mem_limit >= host_mem, "Expected read value exceeding host_mem"); + // Exceeding physical memory is treated as unlimited. This implementation + // caps it at host_mem since Cg v1 has no value to represent 'max'. + reason = "ignored"; + } + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, + reason, mem_limit, host_mem); + } + } +} + +jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { julong memlimit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.limit_in_bytes", "Memory Limit", memlimit); - if (memlimit >= os::Linux::physical_memory()) { + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit); + if (memlimit >= phys_mem) { log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); - CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); - if (mem_controller->is_hierarchical()) { + if (is_hierarchical()) { julong hier_memlimit; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - "hierarchical_memory_limit", - &hier_memlimit); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "hierarchical_memory_limit", &hier_memlimit); if (!is_ok) { return OSCONTAINER_ERROR; } log_trace(os, container)("Hierarchical Memory Limit is: " JULONG_FORMAT, hier_memlimit); - if (hier_memlimit >= os::Linux::physical_memory()) { - log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); - } else { + if (hier_memlimit < phys_mem) { + verbose_log(hier_memlimit, phys_mem); return (jlong)hier_memlimit; } + log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); } + verbose_log(memlimit, phys_mem); return (jlong)-1; - } - else { + } else { + verbose_log(memlimit, phys_mem); return (jlong)memlimit; } } @@ -128,20 +149,17 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { * * -1 if there isn't any limit in place (note: includes values which exceed a physical * upper bound) */ -jlong CgroupV1Subsystem::read_mem_swap() { - julong host_total_memsw; +jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) { julong hier_memswlimit; julong memswlimit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); - host_total_memsw = os::Linux::host_swap() + os::Linux::physical_memory(); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); if (memswlimit >= host_total_memsw) { log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); - CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); - if (mem_controller->is_hierarchical()) { + if (is_hierarchical()) { const char* matchline = "hierarchical_memsw_limit"; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - matchline, - &hier_memswlimit); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", + matchline, + &hier_memswlimit); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -158,8 +176,8 @@ jlong CgroupV1Subsystem::read_mem_swap() { } } -jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { - jlong memory_swap = read_mem_swap(); +jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) { + jlong memory_swap = read_mem_swap(host_mem + host_swap); if (memory_swap == -1) { return memory_swap; } @@ -168,7 +186,7 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { // supported. jlong swappiness = read_mem_swappiness(); if (swappiness == 0 || memory_swap == OSCONTAINER_ERROR) { - jlong memlimit = read_memory_limit_in_bytes(); + jlong memlimit = read_memory_limit_in_bytes(host_mem); if (memory_swap == OSCONTAINER_ERROR) { log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swap is not supported", memlimit); } else { @@ -186,28 +204,28 @@ jlong memory_swap_usage_impl(CgroupController* ctrl) { return (jlong)memory_swap_usage; } -jlong CgroupV1Subsystem::memory_and_swap_usage_in_bytes() { - jlong memory_sw_limit = memory_and_swap_limit_in_bytes(); - jlong memory_limit = CgroupSubsystem::memory_limit_in_bytes(); +jlong CgroupV1MemoryController::memory_and_swap_usage_in_bytes(julong phys_mem, julong host_swap) { + jlong memory_sw_limit = memory_and_swap_limit_in_bytes(phys_mem, host_swap); + jlong memory_limit = read_memory_limit_in_bytes(phys_mem); if (memory_sw_limit > 0 && memory_limit > 0) { jlong delta_swap = memory_sw_limit - memory_limit; if (delta_swap > 0) { - return memory_swap_usage_impl(_memory->controller()); + return memory_swap_usage_impl(reader()); } } return memory_usage_in_bytes(); } -jlong CgroupV1Subsystem::read_mem_swappiness() { +jlong CgroupV1MemoryController::read_mem_swappiness() { julong swappiness; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.swappiness", "Swappiness", swappiness); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.swappiness", "Swappiness", swappiness); return (jlong)swappiness; } -jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { +jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { julong memsoftlimit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); - if (memsoftlimit >= os::Linux::physical_memory()) { + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); + if (memsoftlimit >= phys_mem) { log_trace(os, container)("Memory Soft Limit is: Unlimited"); return (jlong)-1; } else { @@ -235,9 +253,9 @@ bool CgroupV1Subsystem::is_containerized() { * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupV1Subsystem::memory_usage_in_bytes() { +jlong CgroupV1MemoryController::memory_usage_in_bytes() { julong memusage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.usage_in_bytes", "Memory Usage", memusage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.usage_in_bytes", "Memory Usage", memusage); return (jlong)memusage; } @@ -249,17 +267,15 @@ jlong CgroupV1Subsystem::memory_usage_in_bytes() { * max memory usage in bytes or * OSCONTAINER_ERROR for not supported */ -jlong CgroupV1Subsystem::memory_max_usage_in_bytes() { +jlong CgroupV1MemoryController::memory_max_usage_in_bytes() { julong memmaxusage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.max_usage_in_bytes", "Maximum Memory Usage", memmaxusage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.max_usage_in_bytes", "Maximum Memory Usage", memmaxusage); return (jlong)memmaxusage; } -jlong CgroupV1Subsystem::rss_usage_in_bytes() { +jlong CgroupV1MemoryController::rss_usage_in_bytes() { julong rss; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - "rss", - &rss); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "rss", &rss); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -267,11 +283,9 @@ jlong CgroupV1Subsystem::rss_usage_in_bytes() { return (jlong)rss; } -jlong CgroupV1Subsystem::cache_usage_in_bytes() { +jlong CgroupV1MemoryController::cache_usage_in_bytes() { julong cache; - bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", - "cache", - &cache); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "cache", &cache); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -279,30 +293,30 @@ jlong CgroupV1Subsystem::cache_usage_in_bytes() { return cache; } -jlong CgroupV1Subsystem::kernel_memory_usage_in_bytes() { +jlong CgroupV1MemoryController::kernel_memory_usage_in_bytes() { julong kmem_usage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.usage_in_bytes", "Kernel Memory Usage", kmem_usage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.usage_in_bytes", "Kernel Memory Usage", kmem_usage); return (jlong)kmem_usage; } -jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { +jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong phys_mem) { julong kmem_limit; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); - if (kmem_limit >= os::Linux::physical_memory()) { + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); + if (kmem_limit >= phys_mem) { return (jlong)-1; } return (jlong)kmem_limit; } -jlong CgroupV1Subsystem::kernel_memory_max_usage_in_bytes() { +jlong CgroupV1MemoryController::kernel_memory_max_usage_in_bytes() { julong kmem_max_usage; - CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.max_usage_in_bytes", "Maximum Kernel Memory Usage", kmem_max_usage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.max_usage_in_bytes", "Maximum Kernel Memory Usage", kmem_max_usage); return (jlong)kmem_max_usage; } -void CgroupV1Subsystem::print_version_specific_info(outputStream* st) { +void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { jlong kmem_usage = kernel_memory_usage_in_bytes(); - jlong kmem_limit = kernel_memory_limit_in_bytes(); + jlong kmem_limit = kernel_memory_limit_in_bytes(phys_mem); jlong kmem_max_usage = kernel_memory_max_usage_in_bytes(); OSContainer::print_container_helper(st, kmem_usage, "kernel_memory_usage_in_bytes"); @@ -332,10 +346,9 @@ char* CgroupV1Subsystem::cpu_cpuset_memory_nodes() { * -1 for no quota * OSCONTAINER_ERROR for not supported */ -int CgroupV1Subsystem::cpu_quota() { +int CgroupV1CpuController::cpu_quota() { julong quota; - bool is_ok = _cpu->controller()-> - read_number("/cpu.cfs_quota_us", "a); + bool is_ok = reader()->read_number("/cpu.cfs_quota_us", "a); if (!is_ok) { log_trace(os, container)("CPU Quota failed: %d", OSCONTAINER_ERROR); return OSCONTAINER_ERROR; @@ -347,9 +360,9 @@ int CgroupV1Subsystem::cpu_quota() { return quota_int; } -int CgroupV1Subsystem::cpu_period() { +int CgroupV1CpuController::cpu_period() { julong period; - CONTAINER_READ_NUMBER_CHECKED(_cpu->controller(), "/cpu.cfs_period_us", "CPU Period", period); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.cfs_period_us", "CPU Period", period); return (int)period; } @@ -363,9 +376,9 @@ int CgroupV1Subsystem::cpu_period() { * -1 for no share setup * OSCONTAINER_ERROR for not supported */ -int CgroupV1Subsystem::cpu_shares() { +int CgroupV1CpuController::cpu_shares() { julong shares; - CONTAINER_READ_NUMBER_CHECKED(_cpu->controller(), "/cpu.shares", "CPU Shares", shares); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.shares", "CPU Shares", shares); int shares_int = (int)shares; // Convert 1024 to no shares setup if (shares_int == 1024) return -1; diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 2b67678c2e8da..251fbde85f0bb 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -34,31 +34,60 @@ class CgroupV1Controller: public CgroupController { private: /* mountinfo contents */ - char *_root; - char *_mount_point; + char* _root; + char* _mount_point; bool _read_only; /* Constructed subsystem directory */ - char *_path; + char* _path; public: - CgroupV1Controller(char *root, char *mountpoint, bool ro) { - _root = os::strdup(root); - _mount_point = os::strdup(mountpoint); - _path = nullptr; - _read_only = ro; + CgroupV1Controller(char *root, + char *mountpoint, + bool ro) : _root(os::strdup(root)), + _mount_point(os::strdup(mountpoint)), + _read_only(ro), + _path(nullptr) { + } + // Shallow copy constructor + CgroupV1Controller(const CgroupV1Controller& o) : _root(o._root), + _mount_point(o._mount_point), + _read_only(o._read_only), + _path(o._path) { + } + ~CgroupV1Controller() { + // At least one subsystem controller exists with paths to malloc'd path + // names } - virtual void set_subsystem_path(char *cgroup_path); - char *subsystem_path() { return _path; } + void set_subsystem_path(char *cgroup_path); + char *subsystem_path() override { return _path; } bool is_read_only() { return _read_only; } }; -class CgroupV1MemoryController: public CgroupV1Controller { +class CgroupV1MemoryController final : public CgroupMemoryController { + private: + CgroupV1Controller _reader; + CgroupV1Controller* reader() { return &_reader; } public: bool is_hierarchical() { return _uses_mem_hierarchy; } void set_subsystem_path(char *cgroup_path); + jlong read_memory_limit_in_bytes(julong upper_bound) override; + jlong memory_usage_in_bytes() override; + jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override; + jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) override; + jlong memory_soft_limit_in_bytes(julong upper_bound) override; + jlong memory_max_usage_in_bytes() override; + jlong rss_usage_in_bytes() override; + jlong cache_usage_in_bytes() override; + jlong kernel_memory_usage_in_bytes(); + jlong kernel_memory_limit_in_bytes(julong host_mem); + jlong kernel_memory_max_usage_in_bytes(); + void print_version_specific_info(outputStream* st, julong host_mem) override; + bool is_read_only() override { + return reader()->is_read_only(); + } private: /* Some container runtimes set limits via cgroup * hierarchy. If set to true consider also memory.stat @@ -66,26 +95,41 @@ class CgroupV1MemoryController: public CgroupV1Controller { bool _uses_mem_hierarchy; jlong uses_mem_hierarchy(); void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } + jlong read_mem_swappiness(); + jlong read_mem_swap(julong host_total_memsw); public: - CgroupV1MemoryController(char *root, char *mountpoint, bool ro) : CgroupV1Controller(root, mountpoint, ro) { - _uses_mem_hierarchy = false; + CgroupV1MemoryController(const CgroupV1Controller& reader) + : _reader(reader), + _uses_mem_hierarchy(false) { } }; -class CgroupV1Subsystem: public CgroupSubsystem { +class CgroupV1CpuController final : public CgroupCpuController { + + private: + CgroupV1Controller _reader; + CgroupV1Controller* reader() { return &_reader; } + public: + int cpu_quota() override; + int cpu_period() override; + int cpu_shares() override; + void set_subsystem_path(char *cgroup_path) { + reader()->set_subsystem_path(cgroup_path); + } + bool is_read_only() override { + return reader()->is_read_only(); + } public: - jlong read_memory_limit_in_bytes(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_and_swap_usage_in_bytes(); - jlong memory_soft_limit_in_bytes(); - jlong memory_usage_in_bytes(); - jlong memory_max_usage_in_bytes(); - jlong rss_usage_in_bytes(); - jlong cache_usage_in_bytes(); + CgroupV1CpuController(const CgroupV1Controller& reader) : _reader(reader) { + } +}; + +class CgroupV1Subsystem: public CgroupSubsystem { + public: jlong kernel_memory_usage_in_bytes(); jlong kernel_memory_limit_in_bytes(); jlong kernel_memory_max_usage_in_bytes(); @@ -93,45 +137,35 @@ class CgroupV1Subsystem: public CgroupSubsystem { char * cpu_cpuset_cpus(); char * cpu_cpuset_memory_nodes(); - int cpu_quota(); - int cpu_period(); - - int cpu_shares(); - jlong pids_max(); jlong pids_current(); bool is_containerized(); - void print_version_specific_info(outputStream* st); - const char * container_type() { return "cgroupv1"; } - CachingCgroupController * memory_controller() { return _memory; } - CachingCgroupController * cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() { return _memory; } + CachingCgroupController* cpu_controller() { return _cpu; } private: /* controllers */ - CachingCgroupController* _memory = nullptr; + CachingCgroupController* _memory = nullptr; CgroupV1Controller* _cpuset = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _cpu = nullptr; CgroupV1Controller* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; - jlong read_mem_swappiness(); - jlong read_mem_swap(); - public: CgroupV1Subsystem(CgroupV1Controller* cpuset, - CgroupV1Controller* cpu, + CgroupV1CpuController* cpu, CgroupV1Controller* cpuacct, CgroupV1Controller* pids, - CgroupV1MemoryController* memory) { - _cpuset = cpuset; - _cpu = new CachingCgroupController(cpu); - _cpuacct = cpuacct; - _pids = pids; - _memory = new CachingCgroupController(memory); + CgroupV1MemoryController* memory) : + _memory(new CachingCgroupController(memory)), + _cpuset(cpuset), + _cpu(new CachingCgroupController(cpu)), + _cpuacct(cpuacct), + _pids(pids) { } }; diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 1f97b0212395c..8f7e12d095474 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -23,6 +23,7 @@ */ #include "cgroupV2Subsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" /* cpu_shares * @@ -34,9 +35,9 @@ * -1 for no share setup * OSCONTAINER_ERROR for not supported */ -int CgroupV2Subsystem::cpu_shares() { +int CgroupV2CpuController::cpu_shares() { julong shares; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/cpu.weight", "Raw value for CPU Shares", shares); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpu.weight", "Raw value for CPU Shares", shares); int shares_int = (int)shares; // Convert default value of 100 to no shares setup if (shares_int == 100) { @@ -83,9 +84,9 @@ int CgroupV2Subsystem::cpu_shares() { * -1 for no quota * OSCONTAINER_ERROR for not supported */ -int CgroupV2Subsystem::cpu_quota() { +int CgroupV2CpuController::cpu_quota() { jlong quota_val; - bool is_ok = _unified->read_numerical_tuple_value("/cpu.max", true /* use_first */, "a_val); + bool is_ok = reader()->read_numerical_tuple_value("/cpu.max", true /* use_first */, "a_val); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -95,24 +96,26 @@ int CgroupV2Subsystem::cpu_quota() { } bool CgroupV2Subsystem::is_containerized() { - return _unified->is_read_only(); + return _unified.is_read_only() && + _memory->controller()->is_read_only() && + _cpu->controller()->is_read_only(); } char* CgroupV2Subsystem::cpu_cpuset_cpus() { char cpus[1024]; - CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); + CONTAINER_READ_STRING_CHECKED(unified(), "/cpuset.cpus", "cpuset.cpus", cpus, 1024); return os::strdup(cpus); } char* CgroupV2Subsystem::cpu_cpuset_memory_nodes() { char mems[1024]; - CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.mems", "cpuset.mems", mems, 1024); + CONTAINER_READ_STRING_CHECKED(unified(), "/cpuset.mems", "cpuset.mems", mems, 1024); return os::strdup(mems); } -int CgroupV2Subsystem::cpu_period() { +int CgroupV2CpuController::cpu_period() { jlong period_val; - bool is_ok = _unified->read_numerical_tuple_value("/cpu.max", false /* use_first */, &period_val); + bool is_ok = reader()->read_numerical_tuple_value("/cpu.max", false /* use_first */, &period_val); if (!is_ok) { log_trace(os, container)("CPU Period failed: %d", OSCONTAINER_ERROR); return OSCONTAINER_ERROR; @@ -131,28 +134,27 @@ int CgroupV2Subsystem::cpu_period() { * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupV2Subsystem::memory_usage_in_bytes() { +jlong CgroupV2MemoryController::memory_usage_in_bytes() { julong memusage; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/memory.current", "Memory Usage", memusage); + CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.current", "Memory Usage", memusage); return (jlong)memusage; } -jlong CgroupV2Subsystem::memory_soft_limit_in_bytes() { +jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { jlong mem_soft_limit; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.low", "Memory Soft Limit", mem_soft_limit); + CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.low", "Memory Soft Limit", mem_soft_limit); return mem_soft_limit; } -jlong CgroupV2Subsystem::memory_max_usage_in_bytes() { +jlong CgroupV2MemoryController::memory_max_usage_in_bytes() { // Log this string at trace level so as to make tests happy. log_trace(os, container)("Maximum Memory Usage is not supported."); return OSCONTAINER_ERROR; // not supported } -jlong CgroupV2Subsystem::rss_usage_in_bytes() { +jlong CgroupV2MemoryController::rss_usage_in_bytes() { julong rss; - bool is_ok = _memory->controller()-> - read_numerical_key_value("/memory.stat", "anon", &rss); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "anon", &rss); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -160,10 +162,9 @@ jlong CgroupV2Subsystem::rss_usage_in_bytes() { return (jlong)rss; } -jlong CgroupV2Subsystem::cache_usage_in_bytes() { +jlong CgroupV2MemoryController::cache_usage_in_bytes() { julong cache; - bool is_ok = _memory->controller()-> - read_numerical_key_value("/memory.stat", "file", &cache); + bool is_ok = reader()->read_numerical_key_value("/memory.stat", "file", &cache); if (!is_ok) { return OSCONTAINER_ERROR; } @@ -176,18 +177,19 @@ jlong CgroupV2Subsystem::cache_usage_in_bytes() { // respectively. In order to properly report a cgroup v1 like // compound value we need to sum the two values. Setting a swap limit // without also setting a memory limit is not allowed. -jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { +jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong phys_mem, + julong host_swap /* unused in cg v2 */) { jlong swap_limit; - bool is_ok = _memory->controller()->read_number_handle_max("/memory.swap.max", &swap_limit); + bool is_ok = reader()->read_number_handle_max("/memory.swap.max", &swap_limit); if (!is_ok) { // Some container tests rely on this trace logging to happen. log_trace(os, container)("Swap Limit failed: %d", OSCONTAINER_ERROR); // swap disabled at kernel level, treat it as no swap - return read_memory_limit_in_bytes(); + return read_memory_limit_in_bytes(phys_mem); } log_trace(os, container)("Swap Limit is: " JLONG_FORMAT, swap_limit); if (swap_limit >= 0) { - jlong memory_limit = read_memory_limit_in_bytes(); + jlong memory_limit = read_memory_limit_in_bytes(phys_mem); assert(memory_limit >= 0, "swap limit without memory limit?"); return memory_limit + swap_limit; } @@ -195,29 +197,31 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { return swap_limit; } -jlong CgroupV2Subsystem::memory_and_swap_usage_in_bytes() { - jlong memory_usage = memory_usage_in_bytes(); - if (memory_usage >= 0) { - jlong swap_current = mem_swp_current_val(); - return memory_usage + (swap_current >= 0 ? swap_current : 0); - } - return memory_usage; // not supported or unlimited case +// memory.swap.current : total amount of swap currently used by the cgroup and its descendants +static +jlong memory_swap_current_value(CgroupV2Controller* ctrl) { + julong swap_current; + CONTAINER_READ_NUMBER_CHECKED(ctrl, "/memory.swap.current", "Swap currently used", swap_current); + return (jlong)swap_current; } -jlong CgroupV2Subsystem::mem_swp_limit_val() { - jlong swap_limit; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.swap.max", "Swap Limit", swap_limit); - return swap_limit; +jlong CgroupV2MemoryController::memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) { + jlong memory_usage = memory_usage_in_bytes(); + if (memory_usage >= 0) { + jlong swap_current = memory_swap_current_value(reader()); + return memory_usage + (swap_current >= 0 ? swap_current : 0); + } + return memory_usage; // not supported or unlimited case } -// memory.swap.current : total amount of swap currently used by the cgroup and its descendants -jlong CgroupV2Subsystem::mem_swp_current_val() { - julong swap_current; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/memory.swap.current", "Swap currently used", swap_current); - return (jlong)swap_current; +static +jlong memory_limit_value(CgroupV2Controller* ctrl) { + jlong memory_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(ctrl, "/memory.max", "Memory Limit", memory_limit); + return memory_limit; } -/* memory_limit_in_bytes +/* read_memory_limit_in_bytes * * Return the limit of available memory for this process. * @@ -225,15 +229,44 @@ jlong CgroupV2Subsystem::mem_swp_current_val() { * memory limit in bytes or * -1 for unlimited, OSCONTAINER_ERROR for an error */ -jlong CgroupV2Subsystem::read_memory_limit_in_bytes() { - jlong memory_limit; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.max", "Memory Limit", memory_limit); - return memory_limit; +jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) { + jlong limit = memory_limit_value(reader()); + if (log_is_enabled(Trace, os, container)) { + if (limit == -1) { + log_trace(os, container)("Memory Limit is: Unlimited"); + } else { + log_trace(os, container)("Memory Limit is: " JLONG_FORMAT, limit); + } + } + if (log_is_enabled(Debug, os, container)) { + julong read_limit = (julong)limit; // avoid signed/unsigned compare + if (limit < 0 || read_limit >= phys_mem) { + const char* reason; + if (limit == -1) { + reason = "unlimited"; + } else if (limit == OSCONTAINER_ERROR) { + reason = "failed"; + } else { + assert(read_limit >= phys_mem, "Expected mem limit to exceed host memory"); + reason = "ignored"; + } + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, + reason, limit, phys_mem); + } + } + return limit; +} + +static +jlong memory_swap_limit_value(CgroupV2Controller* ctrl) { + jlong swap_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(ctrl, "/memory.swap.max", "Swap Limit", swap_limit); + return swap_limit; } -void CgroupV2Subsystem::print_version_specific_info(outputStream* st) { - jlong swap_current = mem_swp_current_val(); - jlong swap_limit = mem_swp_limit_val(); +void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { + jlong swap_current = memory_swap_current_value(reader()); + jlong swap_limit = memory_swap_limit_value(reader()); OSContainer::print_container_helper(st, swap_current, "memory_swap_current_in_bytes"); OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes"); @@ -259,7 +292,7 @@ char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { */ jlong CgroupV2Subsystem::pids_max() { jlong pids_max; - CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/pids.max", "Maximum number of tasks", pids_max); + CONTAINER_READ_NUMBER_CHECKED_MAX(unified(), "/pids.max", "Maximum number of tasks", pids_max); return pids_max; } @@ -273,6 +306,6 @@ jlong CgroupV2Subsystem::pids_max() { */ jlong CgroupV2Subsystem::pids_current() { julong pids_current; - CONTAINER_READ_NUMBER_CHECKED(_unified, "/pids.current", "Current number of tasks", pids_current); + CONTAINER_READ_NUMBER_CHECKED(unified(), "/pids.current", "Current number of tasks", pids_current); return pids_current; } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 8e06466a138a5..02774fb70aec8 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -40,60 +40,96 @@ class CgroupV2Controller: public CgroupController { static char* construct_path(char* mount_path, char *cgroup_path); public: - CgroupV2Controller(char * mount_path, char *cgroup_path, bool ro) { - _mount_path = mount_path; - _cgroup_path = os::strdup(cgroup_path); - _path = construct_path(mount_path, cgroup_path); - _read_only = ro; + CgroupV2Controller(char* mount_path, + char *cgroup_path, + bool ro) : _mount_path(os::strdup(mount_path)), + _cgroup_path(os::strdup(cgroup_path)), + _read_only(ro), + _path(construct_path(mount_path, cgroup_path)) { + } + // Shallow copy constructor + CgroupV2Controller(const CgroupV2Controller& o) : + _mount_path(o._mount_path), + _cgroup_path(o._cgroup_path), + _read_only(o._read_only), + _path(o._path) { + } + ~CgroupV2Controller() { + // At least one controller exists with references to the paths } - char *subsystem_path() { return _path; } - bool is_read_only() { return _read_only; } + char *subsystem_path() override { return _path; } + bool is_read_only() override { return _read_only; } +}; + +class CgroupV2CpuController: public CgroupCpuController { + private: + CgroupV2Controller _reader; + CgroupV2Controller* reader() { return &_reader; } + public: + CgroupV2CpuController(const CgroupV2Controller& reader) : _reader(reader) { + } + int cpu_quota() override; + int cpu_period() override; + int cpu_shares() override; + bool is_read_only() override { + return reader()->is_read_only(); + } +}; + +class CgroupV2MemoryController final: public CgroupMemoryController { + private: + CgroupV2Controller _reader; + CgroupV2Controller* reader() { return &_reader; } + public: + CgroupV2MemoryController(const CgroupV2Controller& reader) : _reader(reader) { + } + + jlong read_memory_limit_in_bytes(julong upper_bound) override; + jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override; + jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swp) override; + jlong memory_soft_limit_in_bytes(julong upper_bound) override; + jlong memory_usage_in_bytes() override; + jlong memory_max_usage_in_bytes() override; + jlong rss_usage_in_bytes() override; + jlong cache_usage_in_bytes() override; + void print_version_specific_info(outputStream* st, julong host_mem) override; + bool is_read_only() override { + return reader()->is_read_only(); + } }; class CgroupV2Subsystem: public CgroupSubsystem { private: /* One unified controller */ - CgroupController* _unified = nullptr; + CgroupV2Controller _unified; /* Caching wrappers for cpu/memory metrics */ - CachingCgroupController* _memory = nullptr; - CachingCgroupController* _cpu = nullptr; + CachingCgroupController* _memory = nullptr; + CachingCgroupController* _cpu = nullptr; - jlong mem_swp_limit_val(); - jlong mem_swp_current_val(); + CgroupV2Controller* unified() { return &_unified; } public: - CgroupV2Subsystem(CgroupController * unified) { - _unified = unified; - _memory = new CachingCgroupController(unified); - _cpu = new CachingCgroupController(unified); + CgroupV2Subsystem(CgroupV2MemoryController* memory, + CgroupV2CpuController* cpu, + CgroupV2Controller unified) : + _unified(unified), + _memory(new CachingCgroupController(memory)), + _cpu(new CachingCgroupController(cpu)) { } - jlong read_memory_limit_in_bytes(); - int cpu_quota(); - int cpu_period(); - int cpu_shares(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_and_swap_usage_in_bytes(); - jlong memory_soft_limit_in_bytes(); - jlong memory_usage_in_bytes(); - jlong memory_max_usage_in_bytes(); - jlong rss_usage_in_bytes(); - jlong cache_usage_in_bytes(); - - char * cpu_cpuset_cpus(); - char * cpu_cpuset_memory_nodes(); - jlong pids_max(); - jlong pids_current(); - - bool is_containerized(); - void print_version_specific_info(outputStream* st); - - const char * container_type() { + char * cpu_cpuset_cpus() override; + char * cpu_cpuset_memory_nodes() override; + jlong pids_max() override; + jlong pids_current() override; + + bool is_containerized() override; + + const char * container_type() override { return "cgroupv2"; } - CachingCgroupController * memory_controller() { return _memory; } - CachingCgroupController * cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() { return _memory; } + CachingCgroupController* cpu_controller() { return _cpu; } }; #endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP From a3479576c9b3e557cdc04e0984da6350e985dcc9 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 2 Jul 2024 18:13:50 +0000 Subject: [PATCH 124/288] 8335291: Problem list all SA core file tests on macosx-aarch64 due to JDK-8318754 Reviewed-by: kevinw, amenkov --- test/hotspot/jtreg/ProblemList.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 2d1311e3ac127..c55790de5ca58 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -129,13 +129,13 @@ serviceability/jvmti/vthread/GetSetLocalTest/GetSetLocalTest.java 8286836 generi serviceability/jvmti/vthread/CarrierThreadEventNotification/CarrierThreadEventNotification.java 8333681 generic-all serviceability/dcmd/gc/RunFinalizationTest.java 8227120 generic-all -serviceability/sa/ClhsdbCDSCore.java 8267433 macosx-x64 -serviceability/sa/ClhsdbFindPC.java#xcomp-core 8267433 macosx-x64 -serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8267433 macosx-x64 -serviceability/sa/ClhsdbPmap.java#core 8267433 macosx-x64 -serviceability/sa/ClhsdbPstack.java#core 8267433 macosx-x64 -serviceability/sa/TestJmapCore.java 8267433 macosx-x64 -serviceability/sa/TestJmapCoreMetaspace.java 8267433 macosx-x64 +serviceability/sa/ClhsdbCDSCore.java 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbFindPC.java#xcomp-core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbPmap.java#core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/ClhsdbPstack.java#core 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/TestJmapCore.java 8267433,8318754 macosx-x64,macosx-aarch64 +serviceability/sa/TestJmapCoreMetaspace.java 8267433,8318754 macosx-x64,macosx-aarch64 serviceability/attach/ConcAttachTest.java 8290043 linux-all From 27982c8f5dad0e2d080846f803055c84bac9fddd Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 2 Jul 2024 20:27:52 +0000 Subject: [PATCH 125/288] 8327854: Test java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java failed with RuntimeException Reviewed-by: psandoz --- .../openjdk/tests/java/util/stream/WhileOpStatefulTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java index c980e17d05f9c..07348841b1e4a 100644 --- a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java +++ b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java @@ -256,7 +256,7 @@ private void testWhileMulti(Map>> sources, EXECUTION_TIME_LIMIT); return s.peek(e -> { if (!isWithinExecutionPeriod.getAsBoolean()) { - throw new RuntimeException(); + throw new RuntimeException("Execution time limit exceeded!"); } }); }); @@ -266,7 +266,7 @@ private void testWhileMulti(Map>> sources, return s.parallel() .peek(e -> { if (!isWithinExecutionPeriod.getAsBoolean()) { - throw new RuntimeException(); + throw new RuntimeException("Execution time limit exceeded!"); } }); }); From 1ef34c183315b70ddc27c177a2867e30132609f5 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 2 Jul 2024 23:15:31 +0000 Subject: [PATCH 126/288] 8335475: ClassBuilder incorrectly calculates max_locals in some cases Reviewed-by: asotona --- .../classfile/impl/StackMapGenerator.java | 2 +- test/jdk/jdk/classfile/StackMapsTest.java | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 0f1f6fb69de26..5b103a21f8a73 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1046,7 +1046,7 @@ private void setLocalRawInternal(int index, Type type) { void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { int localsSize = 0; // Pre-emptively create a locals array that encompass all parameter slots - checkLocal(methodDesc.parameterCount() + (isStatic ? 0 : -1)); + checkLocal(methodDesc.parameterCount() + (isStatic ? -1 : 0)); if (!isStatic) { localsSize++; if (OBJECT_INITIALIZER_NAME.equals(name) && !CD_Object.equals(thisKlass.sym)) { diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index b3df31291bcf0..f72c237aa8ff3 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @summary Testing Classfile stack maps generator. - * @bug 8305990 8320222 8320618 + * @bug 8305990 8320222 8320618 8335475 * @build testdata.* * @run junit StackMapsTest */ @@ -36,6 +36,10 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import static java.lang.constant.ConstantDescs.MTD_void; import static org.junit.jupiter.api.Assertions.*; import static helpers.TestUtil.assertEmpty; import static java.lang.classfile.ClassFile.ACC_STATIC; @@ -238,7 +242,7 @@ void testClassVersions() throws Exception { @Test void testInvalidAALOADStack() { ClassFile.of().build(ClassDesc.of("Test"), clb - -> clb.withMethodBody("test", ConstantDescs.MTD_void, 0, cob + -> clb.withMethodBody("test", MTD_void, 0, cob -> cob.bipush(10) .anewarray(ConstantDescs.CD_Object) .lconst_1() //long on stack caused NPE, see 8320618 @@ -312,4 +316,28 @@ void testInvalidStack() throws Exception { cb.pop(); }))); } + + @ParameterizedTest + @EnumSource(ClassFile.StackMapsOption.class) + void testEmptyCounters(ClassFile.StackMapsOption option) { + var cf = ClassFile.of(option); + var bytes = cf.build(ClassDesc.of("Test"), clb -> clb + .withMethodBody("a", MTD_void, ACC_STATIC, CodeBuilder::return_) + .withMethodBody("b", MTD_void, 0, CodeBuilder::return_) + ); + + var cm = ClassFile.of().parse(bytes); + for (var method : cm.methods()) { + var name = method.methodName(); + var code = method.code().orElseThrow(); + if (name.equalsString("a")) { + assertEquals(0, code.maxLocals()); // static method + assertEquals(0, code.maxStack()); + } else { + assertTrue(name.equalsString("b")); + assertEquals(1, code.maxLocals()); // instance method + assertEquals(0, code.maxStack()); + } + } + } } From f187c92befbe63e23b11eb0401e5095c44c24389 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 02:19:54 +0000 Subject: [PATCH 127/288] 8335370: Fix -Wzero-as-null-pointer-constant warning in jvmti_common.hpp Reviewed-by: jwaters, amenkov, sspitsyn --- test/lib/jdk/test/lib/jvmti/jvmti_common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp index 693baf98d1fa5..f16b9fefb99ec 100644 --- a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp +++ b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp @@ -239,7 +239,7 @@ print_method(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method, jint depth) { check_jvmti_status(jni, err, "print_method: error in JVMTI GetMethodName"); LOG("%2d: %s: %s%s\n", depth, cname, mname, msign); - fflush(0); + fflush(nullptr); deallocate(jvmti, jni, (void*)cname); deallocate(jvmti, jni, (void*)mname); deallocate(jvmti, jni, (void*)msign); From 3a2d426489ead9672512e0c5a6862284a54734ba Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 02:42:06 +0000 Subject: [PATCH 128/288] 8334726: Remove accidentally exposed individual methods from Class-File API Reviewed-by: asotona --- .../lang/classfile/attribute/ModuleAttribute.java | 12 +++--------- .../lang/classfile/components/CodeRelabeler.java | 10 +--------- .../classfile/constantpool/ConstantPoolBuilder.java | 10 +--------- .../internal/classfile/impl/CodeRelabelerImpl.java | 3 +-- .../classfile/impl/ModuleAttributeBuilderImpl.java | 3 +-- .../internal/classfile/impl/SplitConstantPool.java | 1 - .../classfile/impl/TemporaryConstantPool.java | 5 ----- 7 files changed, 7 insertions(+), 37 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index 721719d285129..9a4c58478addb 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,7 +153,7 @@ static ModuleAttribute of(ModuleDesc moduleName, Consumer attrHandler) { var mb = new ModuleAttributeBuilderImpl(moduleName); attrHandler.accept(mb); - return mb.build(); + return mb.build(); } /** @@ -166,7 +166,7 @@ static ModuleAttribute of(ModuleEntry moduleName, Consumer attrHandler) { var mb = new ModuleAttributeBuilderImpl(moduleName); attrHandler.accept(mb); - return mb.build(); + return mb.build(); } /** @@ -319,11 +319,5 @@ default ModuleAttributeBuilder opens(PackageDesc pkge, Collection op * @return this builder */ ModuleAttributeBuilder provides(ModuleProvideInfo provides); - - /** - * Builds module attribute. - * @return the module attribute - */ - ModuleAttribute build(); } } diff --git a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java index a0ef4d4de9c5a..ca5ad90389c5c 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java +++ b/src/java.base/share/classes/java/lang/classfile/components/CodeRelabeler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,12 +74,4 @@ static CodeRelabeler of(Map map) { static CodeRelabeler of(BiFunction mapFunction) { return new CodeRelabelerImpl(mapFunction); } - - /** - * Access method to internal re-labeling function. - * @param label source label - * @param codeBuilder builder to create new labels - * @return target label - */ - Label relabel(Label label, CodeBuilder codeBuilder); } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index db388c1c73b62..a43e6f102ed72 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,14 +92,6 @@ static ConstantPoolBuilder of() { */ boolean canWriteDirect(ConstantPool constantPool); - /** - * Writes associated bootstrap method entries to the specified writer - * - * @param buf the writer - * @return false when no bootstrap method entry has been written - */ - boolean writeBootstrapMethods(BufWriter buf); - /** * {@return A {@link Utf8Entry} describing the provided {@linkplain String}} * If a UTF8 entry in the pool already describes this string, it is returned; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java index f191cbf3c1f04..e60a906e189fc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeRelabelerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ public record CodeRelabelerImpl(BiFunction mapFunction) implements CodeRelabeler { - @Override public Label relabel(Label label, CodeBuilder cob) { return mapFunction.apply(label, cob); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java index 1aad47cfd86c2..873b32e4ad649 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,6 @@ public ModuleAttributeBuilderImpl(ModuleDesc moduleName) { this(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.name()))); } - @Override public ModuleAttribute build() { return new UnboundAttribute.UnboundModuleAttribute(moduleEntry, moduleFlags, moduleVersion, requires, exports, opens, uses, provides); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index b034328fdcc55..6c5a8a266c0d1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -135,7 +135,6 @@ public boolean canWriteDirect(ConstantPool other) { return this == other || parent == other; } - @Override public boolean writeBootstrapMethods(BufWriter buf) { if (bsmSize == 0) return false; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java index 7b15489ace703..e5f7d9cca799f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java @@ -190,11 +190,6 @@ public boolean canWriteDirect(ConstantPool constantPool) { return false; } - @Override - public boolean writeBootstrapMethods(BufWriter buf) { - throw new UnsupportedOperationException(); - } - @Override public void writeTo(BufWriter buf) { throw new UnsupportedOperationException(); From 8a664a4c359deefd7237f3672b62d7d8c1ffb453 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 02:43:41 +0000 Subject: [PATCH 129/288] 8334734: Remove specialized readXxxEntry methods from ClassReader Reviewed-by: asotona --- .../java/lang/classfile/ClassReader.java | 75 ------------------- .../classfile/impl/AbstractInstruction.java | 8 +- .../classfile/impl/AnnotationReader.java | 13 ++-- .../classfile/impl/BoundAttribute.java | 41 +++++----- .../impl/BoundRecordComponentInfo.java | 6 +- .../internal/classfile/impl/ClassImpl.java | 2 +- .../classfile/impl/ClassReaderImpl.java | 69 +++++------------ .../internal/classfile/impl/FieldImpl.java | 6 +- .../internal/classfile/impl/MethodImpl.java | 6 +- 9 files changed, 58 insertions(+), 168 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassReader.java b/src/java.base/share/classes/java/lang/classfile/ClassReader.java index 7b181180c6fc9..ef4a36729e679 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java @@ -27,10 +27,6 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolException; -import java.lang.classfile.constantpool.MethodHandleEntry; -import java.lang.classfile.constantpool.ModuleEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; -import java.lang.classfile.constantpool.PackageEntry; import java.lang.classfile.constantpool.PoolEntry; import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.ClassReaderImpl; @@ -130,77 +126,6 @@ public sealed interface ClassReader extends ConstantPool */ T readEntryOrNull(int offset, Class cls); - /** - * {@return the UTF8 entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a UTF8 entry - */ - Utf8Entry readUtf8Entry(int offset); - - /** - * {@return the UTF8 entry whose index is given at the specified - * offset within the classfile, or null if the index at the specified - * offset is zero} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or the index does not correspond to - * a UTF8 entry - */ - Utf8Entry readUtf8EntryOrNull(int offset); - - /** - * {@return the module entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a module entry - */ - ModuleEntry readModuleEntry(int offset); - - /** - * {@return the package entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a package entry - */ - PackageEntry readPackageEntry(int offset); - - /** - * {@return the class entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a class entry - */ - ClassEntry readClassEntry(int offset); - - /** - * {@return the name-and-type entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a name-and-type entry - */ - NameAndTypeEntry readNameAndTypeEntry(int offset); - - /** - * {@return the method handle entry whose index is given at the specified - * offset within the classfile} - * @param offset the offset of the index within the classfile - * @throws ConstantPoolException if the index is out of range of the - * constant pool size, or zero, or the index does not correspond to - * a method handle entry - */ - MethodHandleEntry readMethodHandleEntry(int offset); - /** * {@return the unsigned byte at the specified offset within the classfile} * @param offset the offset within the classfile diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 0e528cd01fd87..48e1f0990b2ee 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -529,7 +529,7 @@ public static final class BoundNewObjectInstruction @Override public ClassEntry className() { if (classEntry == null) - classEntry = code.classReader.readClassEntry(pos + 1); + classEntry = code.classReader.readEntry(pos + 1, ClassEntry.class); return classEntry; } @@ -576,7 +576,7 @@ public BoundNewReferenceArrayInstruction(Opcode op, CodeImpl code, int pos) { @Override public ClassEntry componentType() { - return code.classReader.readClassEntry(pos + 1); + return code.classReader.readEntry(pos + 1, ClassEntry.class); } @Override @@ -607,7 +607,7 @@ public int dimensions() { @Override public ClassEntry arrayType() { - return code.classReader.readClassEntry(pos + 1); + return code.classReader.readEntry(pos + 1, ClassEntry.class); } @Override @@ -636,7 +636,7 @@ public BoundTypeCheckInstruction(Opcode op, CodeImpl code, int pos) { @Override public ClassEntry type() { if (typeEntry == null) - typeEntry = code.classReader.readClassEntry(pos + 1); + typeEntry = code.classReader.readEntry(pos + 1, ClassEntry.class); return typeEntry; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index c082878abd4b1..7b5920b3e7853 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -66,9 +66,10 @@ public static AnnotationValue readElementValue(ClassReader classReader, int p) { case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readUtf8Entry(p)); - case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readUtf8Entry(p), classReader.readUtf8Entry(p + 2)); - case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readUtf8Entry(p)); + case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readEntry(p, Utf8Entry.class)); + case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readEntry(p, Utf8Entry.class), + classReader.readEntry(p + 2, Utf8Entry.class)); + case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readEntry(p, Utf8Entry.class)); case AEV_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); case AEV_ARRAY -> { int numValues = classReader.readU2(p); @@ -127,7 +128,7 @@ private static int skipElementValue(ClassReader classReader, int p) { } private static Annotation readAnnotation(ClassReader classReader, int p) { - Utf8Entry annotationClass = classReader.entryByIndex(classReader.readU2(p), Utf8Entry.class); + Utf8Entry annotationClass = classReader.readEntry(p, Utf8Entry.class); p += 2; List elems = readAnnotationElementValuePairs(classReader, p); return new AnnotationImpl(annotationClass, elems); @@ -150,7 +151,7 @@ private static List readAnnotationElementValuePairs(ClassRead p += 2; var annotationElements = new Object[numElementValuePairs]; for (int i = 0; i < numElementValuePairs; ++i) { - Utf8Entry elementName = classReader.readUtf8Entry(p); + Utf8Entry elementName = classReader.readEntry(p, Utf8Entry.class); p += 2; AnnotationValue value = readElementValue(classReader, p); annotationElements[i] = new AnnotationImpl.AnnotationElementImpl(elementName, value); @@ -239,7 +240,7 @@ private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, }; } // the annotation info for this annotation - Utf8Entry type = classReader.readUtf8Entry(p); + Utf8Entry type = classReader.readEntry(p, Utf8Entry.class); p += 2; return TypeAnnotation.of(targetInfo, List.of(typePath), type, readAnnotationElementValuePairs(classReader, p)); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index 45e0c092c3e0a..21a01becec2d4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -135,7 +135,7 @@ public static List> readAttributes(AttributedElement enclosing, Cla int cfLen = reader.classfileLength(); var apo = ((ClassReaderImpl)reader).context().attributesProcessingOption(); for (int i = 0; i < size; ++i) { - Utf8Entry name = reader.readUtf8Entry(p); + Utf8Entry name = reader.readEntry(p, Utf8Entry.class); int len = reader.readInt(p + 2); p += 6; if (len < 0 || len > cfLen - p) { @@ -347,7 +347,7 @@ public List parameters() { int p = payloadStart + 1; int pEnd = p + (cnt * 4); for (int i = 0; p < pEnd; p += 4, i++) { - Utf8Entry name = classReader.readUtf8EntryOrNull(p); + Utf8Entry name = classReader.readEntryOrNull(p, Utf8Entry.class); int accessFlags = classReader.readU2(p + 2); elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags); } @@ -367,7 +367,7 @@ public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper hashes() { int p = payloadStart + 4; //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt); for (int i = 0; i < cnt; ++i) { - ModuleEntry module = classReader.readModuleEntry(p); + ModuleEntry module = classReader.readEntry(p, ModuleEntry.class); int hashLength = classReader.readU2(p + 2); //System.err.printf("%5d: [%d] module = %s, hashLength = %d%n", p, i, module, hashLength); p += 4; @@ -430,7 +430,7 @@ public BoundSignatureAttribute(ClassReader cf, AttributeMapper @Override public ClassEntry nestHost() { - return classReader.readClassEntry(payloadStart); + return classReader.readEntry(payloadStart, ClassEntry.class); } } @@ -498,7 +498,7 @@ public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper @Override public Utf8Entry sourceId() { - return classReader.readUtf8Entry(payloadStart); + return classReader.readEntry(payloadStart, Utf8Entry.class); } } @@ -569,7 +569,7 @@ public BoundModuleAttribute(ClassReader cf, AttributeMapper map @Override public ModuleEntry moduleName() { - return classReader.readModuleEntry(payloadStart); + return classReader.readEntry(payloadStart, ModuleEntry.class); } @Override @@ -579,7 +579,7 @@ public int moduleFlagsMask() { @Override public Optional moduleVersion() { - return Optional.ofNullable(classReader.readUtf8EntryOrNull(payloadStart + 4)); + return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 4, Utf8Entry.class)); } @Override @@ -630,7 +630,7 @@ private void structure() { ModuleRequireInfo[] elements = new ModuleRequireInfo[cnt]; int end = p + (cnt * 6); for (int i = 0; p < end; p += 6, i++) { - elements[i] = ModuleRequireInfo.of(classReader.readModuleEntry(p), + elements[i] = ModuleRequireInfo.of(classReader.readEntry(p, ModuleEntry.class), classReader.readU2(p + 2), classReader.readEntryOrNull(p + 4, Utf8Entry.class)); } @@ -642,7 +642,7 @@ private void structure() { p += 2; ModuleExportInfo[] elements = new ModuleExportInfo[cnt]; for (int i = 0; i < cnt; i++) { - PackageEntry pe = classReader.readPackageEntry(p); + PackageEntry pe = classReader.readEntry(p, PackageEntry.class); int exportFlags = classReader.readU2(p + 2); p += 4; List exportsTo = readEntryList(p); @@ -657,7 +657,7 @@ private void structure() { p += 2; ModuleOpenInfo[] elements = new ModuleOpenInfo[cnt]; for (int i = 0; i < cnt; i++) { - PackageEntry po = classReader.readPackageEntry(p); + PackageEntry po = classReader.readEntry(p, PackageEntry.class); int opensFlags = classReader.readU2(p + 2); p += 4; List opensTo = readEntryList(p); @@ -675,7 +675,7 @@ private void structure() { ModuleProvideInfo[] elements = new ModuleProvideInfo[cnt]; provides = new ArrayList<>(cnt); for (int i = 0; i < cnt; i++) { - ClassEntry c = classReader.readClassEntry(p); + ClassEntry c = classReader.readEntry(p, ClassEntry.class); p += 2; List providesWith = readEntryList(p); p += 2 + providesWith.size() * 2; @@ -743,8 +743,7 @@ public List bootstrapMethods() { BootstrapMethodEntry[] bs = new BootstrapMethodEntry[size]; int p = payloadStart + 2; for (int i = 0; i < size; ++i) { - final AbstractPoolEntry.MethodHandleEntryImpl handle - = (AbstractPoolEntry.MethodHandleEntryImpl) classReader.readMethodHandleEntry(p); + final var handle = classReader.readEntry(p, AbstractPoolEntry.MethodHandleEntryImpl.class); final List args = readEntryList(p + 2); p += 4 + args.size() * 2; int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args); @@ -771,7 +770,7 @@ public List classes() { int p = payloadStart + 2; InnerClassInfo[] elements = new InnerClassInfo[cnt]; for (int i = 0; i < cnt; i++) { - ClassEntry innerClass = classReader.readClassEntry(p); + ClassEntry innerClass = classReader.readEntry(p, ClassEntry.class); var outerClass = classReader.readEntryOrNull(p + 2, ClassEntry.class); var innerName = classReader.readEntryOrNull(p + 4, Utf8Entry.class); int flags = classReader.readU2(p + 6); @@ -792,7 +791,7 @@ public BoundEnclosingMethodAttribute(ClassReader cf, AttributeMapper interfaces() { pos += 2; var arr = new Object[cnt]; for (int i = 0; i < cnt; ++i) { - arr[i] = reader.readClassEntry(pos); + arr[i] = reader.readEntry(pos, ClassEntry.class); pos += 2; } this.interfaces = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(arr); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index b8a262ce41c40..25d4e2e68e8e8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -151,7 +151,7 @@ public int flags() { @Override public ClassEntry thisClassEntry() { if (thisClass == null) { - thisClass = readClassEntry(thisClassPos); + thisClass = readEntry(thisClassPos, ClassEntry.class); } return thisClass; } @@ -395,23 +395,23 @@ public T entryByIndex(int index, Class cls) { case TAG_FLOAT -> new AbstractPoolEntry.FloatEntryImpl(this, index, readFloat(q)); case TAG_LONG -> new AbstractPoolEntry.LongEntryImpl(this, index, readLong(q)); case TAG_DOUBLE -> new AbstractPoolEntry.DoubleEntryImpl(this, index, readDouble(q)); - case TAG_CLASS -> new AbstractPoolEntry.ClassEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_STRING -> new AbstractPoolEntry.StringEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_FIELDREF -> new AbstractPoolEntry.FieldRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), - (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), - (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), - (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q), - (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q + 2)); + case TAG_CLASS -> new AbstractPoolEntry.ClassEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_STRING -> new AbstractPoolEntry.StringEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_FIELDREF -> new AbstractPoolEntry.FieldRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class), + readEntry(q + 2, AbstractPoolEntry.Utf8EntryImpl.class)); case TAG_METHODHANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), readEntry(q + 1, AbstractPoolEntry.AbstractMemberRefEntry.class)); - case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); - case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); - case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); default -> throw new ConstantPoolException( "Bad tag (" + tag + ") at index (" + index + ") position (" + offset + ")"); }; @@ -428,7 +428,7 @@ public int skipAttributeHolder(int offset) { int len = readInt(p + 2); p += 6; if (len < 0 || len > classfileLength - p) { - throw new IllegalArgumentException("attribute " + readUtf8Entry(p - 6).stringValue() + " too big to handle"); + throw new IllegalArgumentException("attribute " + readEntry(p - 6, Utf8Entry.class).stringValue() + " too big to handle"); } p += len; } @@ -465,41 +465,6 @@ public T readEntryOrNull(int offset, Class cls) { return entryByIndex(index, cls); } - @Override - public Utf8Entry readUtf8Entry(int pos) { - return readEntry(pos, Utf8Entry.class); - } - - @Override - public Utf8Entry readUtf8EntryOrNull(int pos) { - return readEntryOrNull(pos, Utf8Entry.class); - } - - @Override - public ModuleEntry readModuleEntry(int pos) { - return readEntry(pos, ModuleEntry.class); - } - - @Override - public PackageEntry readPackageEntry(int pos) { - return readEntry(pos, PackageEntry.class); - } - - @Override - public ClassEntry readClassEntry(int pos) { - return readEntry(pos, ClassEntry.class); - } - - @Override - public NameAndTypeEntry readNameAndTypeEntry(int pos) { - return readEntry(pos, NameAndTypeEntry.class); - } - - @Override - public MethodHandleEntry readMethodHandleEntry(int pos) { - return readEntry(pos, MethodHandleEntry.class); - } - @Override public boolean compare(BufWriter bufWriter, int bufWriterOffset, diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java index 6645ddb9396ab..fb072ae563868 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,12 +61,12 @@ public Optional parent() { @Override public Utf8Entry fieldName() { - return reader.readUtf8Entry(startPos + 2); + return reader.readEntry(startPos + 2, Utf8Entry.class); } @Override public Utf8Entry fieldType() { - return reader.readUtf8Entry(startPos + 4); + return reader.readEntry(startPos + 4, Utf8Entry.class); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 9a96e586c5501..3bc811634ee18 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,12 +64,12 @@ public Optional parent() { @Override public Utf8Entry methodName() { - return reader.readUtf8Entry(startPos + 2); + return reader.readEntry(startPos + 2, Utf8Entry.class); } @Override public Utf8Entry methodType() { - return reader.readUtf8Entry(startPos + 4); + return reader.readEntry(startPos + 4, Utf8Entry.class); } @Override From f7af4504a804711d93208b763b3e41eafcf61735 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 02:49:43 +0000 Subject: [PATCH 130/288] 8335110: Fix instruction name and API spec inconsistencies in CodeBuilder Reviewed-by: asotona --- .../java/lang/classfile/CodeBuilder.java | 114 +++++++++++++++++- .../classfile/attribute/CodeAttribute.java | 6 +- .../java/lang/runtime/SwitchBootstraps.java | 2 +- .../internal/classfile/impl/LabelImpl.java | 2 +- .../jfr/internal/EventInstrumentation.java | 8 +- .../helpers/RebuildingTransformation.java | 4 +- 6 files changed, 120 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index e954be079fa54..cffa560bef305 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,6 +97,27 @@ * #with(ClassFileElement)} or concretely by calling the various {@code withXxx} * methods. * + *

    Instruction Factories

    + * {@code CodeBuilder} provides convenience methods to create instructions (See + * JVMS {@jvms 6.5} Instructions) by their mnemonic, taking necessary operands. + *
      + *
    • Instructions that encode their operands in their opcode, such as {@code + * aload_}, share their factories with their generic version like {@link + * #aload aload}. Note that some constant instructions, such as {@link #iconst_1 + * iconst_1}, do not have generic versions, and thus have their own factories. + *
    • Instructions that accept wide operands, such as {@code ldc2_w} or {@code + * wide}, share their factories with their regular version like {@link #ldc}. Note + * that {@link #goto_w goto_w} has its own factory to avoid {@linkplain + * ClassFile.ShortJumpsOption short jumps}. + *
    • The {@code goto}, {@code instanceof}, {@code new}, and {@code return} + * instructions' factories are named {@link #goto_ goto_}, {@link #instanceOf + * instanceOf}, {@link #new_ new_}, and {@link #return_() return_} respectively, + * due to clashes with keywords in the Java programming language. + *
    • Factories are not provided for instructions {@code jsr}, {@code jsr_w}, + * {@code ret}, and {@code wide ret}, which cannot appear in class files with + * major version {@value ClassFile#JAVA_7_VERSION} or higher. (JVMS {@jvms 4.9.1}) + *
    + * * @see CodeTransform * * @since 22 @@ -130,7 +151,7 @@ public sealed interface CodeBuilder /** * {@return the local variable slot associated with the receiver}. * - * @throws IllegalStateException if this is not a static method + * @throws IllegalStateException if this is a static method */ int receiverSlot(); @@ -699,7 +720,7 @@ default CodeBuilder lineNumber(int line) { * @return this builder */ default CodeBuilder exceptionCatch(Label start, Label end, Label handler, ClassEntry catchType) { - return with(ExceptionCatch.of(handler, start, end, Optional.of(catchType))); + return with(ExceptionCatch.of(handler, start, end, Optional.ofNullable(catchType))); } /** @@ -837,6 +858,10 @@ default CodeBuilder aastore() { /** * Generate an instruction to load a reference from a local variable + * + *

    This may also generate {@code aload_} and + * {@code wide aload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -881,6 +906,10 @@ default CodeBuilder arraylength() { /** * Generate an instruction to store a reference into a local variable + * + *

    This may also generate {@code astore_} and + * {@code wide astore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1046,6 +1075,10 @@ default CodeBuilder ddiv() { /** * Generate an instruction to load a double from a local variable + * + *

    This may also generate {@code dload_} and + * {@code wide dload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1087,6 +1120,10 @@ default CodeBuilder dreturn() { /** * Generate an instruction to store a double into a local variable + * + *

    This may also generate {@code dstore_} and + * {@code wide dstore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1250,6 +1287,10 @@ default CodeBuilder fdiv() { /** * Generate an instruction to load a float from a local variable + * + *

    This may also generate {@code fload_} and + * {@code wide fload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1291,6 +1332,10 @@ default CodeBuilder freturn() { /** * Generate an instruction to store a float into a local variable + * + *

    This may also generate {@code fstore_} and + * {@code wide fstore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1350,6 +1395,15 @@ default CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) { /** * Generate an instruction to branch always + * + *

    This may also generate {@code goto_w} instructions if the {@link + * ClassFile.ShortJumpsOption#FIX_SHORT_JUMPS FIX_SHORT_JUMPS} option + * is set. + * + * @apiNote The instruction's name is {@code goto}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @param target the branch target * @return this builder */ @@ -1587,7 +1641,7 @@ default CodeBuilder if_icmpne(Label target) { * @param target the branch target * @return this builder */ - default CodeBuilder if_nonnull(Label target) { + default CodeBuilder ifnonnull(Label target) { return branch(Opcode.IFNONNULL, target); } @@ -1596,7 +1650,7 @@ default CodeBuilder if_nonnull(Label target) { * @param target the branch target * @return this builder */ - default CodeBuilder if_null(Label target) { + default CodeBuilder ifnull(Label target) { return branch(Opcode.IFNULL, target); } @@ -1666,6 +1720,10 @@ default CodeBuilder iinc(int slot, int val) { /** * Generate an instruction to load an int from a local variable + * + *

    This may also generate {@code iload_} and + * {@code wide iload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -1691,6 +1749,11 @@ default CodeBuilder ineg() { /** * Generate an instruction to determine if an object is of the given type + * + * @apiNote The instruction's name is {@code instanceof}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with camel case instead. + * * @param target the target type * @return this builder * @since 23 @@ -1701,6 +1764,11 @@ default CodeBuilder instanceOf(ClassEntry target) { /** * Generate an instruction to determine if an object is of the given type + * + * @apiNote The instruction's name is {@code instanceof}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with camel case instead. + * * @param target the target type * @return this builder * @throws IllegalArgumentException if {@code target} represents a primitive type @@ -1910,6 +1978,10 @@ default CodeBuilder ishr() { /** * Generate an instruction to store an int into a local variable + * + *

    This may also generate {@code istore_} and + * {@code wide istore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -2033,6 +2105,12 @@ default CodeBuilder lconst_1() { /** * Generate an instruction pushing an item from the run-time constant pool onto the operand stack + * + *

    This may also generate {@code ldc_w} and {@code ldc2_w} instructions. + * + * @apiNote {@link #loadConstant(ConstantDesc) loadConstant} generates more optimal instructions + * and should be used for general constants if an {@code ldc} instruction is not strictly required. + * * @param value the constant value * @return this builder */ @@ -2042,6 +2120,9 @@ default CodeBuilder ldc(ConstantDesc value) { /** * Generate an instruction pushing an item from the run-time constant pool onto the operand stack + * + *

    This may also generate {@code ldc_w} and {@code ldc2_w} instructions. + * * @param entry the constant value * @return this builder */ @@ -2062,6 +2143,10 @@ default CodeBuilder ldiv() { /** * Generate an instruction to load a long from a local variable + * + *

    This may also generate {@code lload_} and + * {@code wide lload} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -2127,6 +2212,10 @@ default CodeBuilder lshr() { /** * Generate an instruction to store a long into a local variable + * + *

    This may also generate {@code lstore_} and + * {@code wide lstore} instructions. + * * @param slot the local variable slot * @return this builder */ @@ -2197,6 +2286,11 @@ default CodeBuilder multianewarray(ClassDesc array, int dims) { /** * Generate an instruction to create a new object + * + * @apiNote The instruction's name is {@code new}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @param clazz the new class type * @return this builder */ @@ -2206,6 +2300,11 @@ default CodeBuilder new_(ClassEntry clazz) { /** * Generate an instruction to create a new object + * + * @apiNote The instruction's name is {@code new}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @param clazz the new class type * @return this builder * @throws IllegalArgumentException if {@code clazz} represents a primitive type @@ -2283,6 +2382,11 @@ default CodeBuilder putstatic(ClassDesc owner, String name, ClassDesc type) { /** * Generate an instruction to return void from the method + * + * @apiNote The instruction's name is {@code return}, which coincides with a + * reserved keyword of the Java programming language, thus this method is + * named with an extra {@code _} suffix instead. + * * @return this builder */ default CodeBuilder return_() { diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java index 1a57cf4f37f95..02cbcee810f64 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,9 +58,9 @@ public sealed interface CodeAttribute extends Attribute, CodeMode byte[] codeArray(); /** - * {@return the position of the {@code Label} in the {@code codeArray} - * or -1 if the {@code Label} does not point to the {@code codeArray}} + * {@return the position of the {@code label} in the {@link #codeArray codeArray}} * @param label a marker for a position within this {@code CodeAttribute} + * @throws IllegalArgumentException if the {@code label} is not from this attribute */ int labelToBci(Label label); } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 24ee48c1f4735..ccb33a0e4dbd1 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -422,7 +422,7 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto cb.pop(); cb.aload(SELECTOR_OBJ); Label nonNullLabel = cb.newLabel(); - cb.if_nonnull(nonNullLabel); + cb.ifnonnull(nonNullLabel); cb.iconst_m1(); cb.ireturn(); cb.labelBinding(nonNullLabel); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java index b316c5a6dd176..2aaf5f033c0b6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java @@ -51,7 +51,7 @@ public final class LabelImpl private final LabelContext labelContext; private int bci; - public LabelImpl(LabelContext labelContext, int bci) { + public LabelImpl(LabelContext labelContext, int bci) { this.labelContext = Objects.requireNonNull(labelContext); this.bci = bci; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index cf7e162a42e43..d8f5e689ca18c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -461,7 +461,7 @@ private void makeInstrumented() { catchAllHandler.dup(); // stack: [ex] [EW] [EW] Label rethrow = catchAllHandler.newLabel(); - catchAllHandler.if_null(rethrow); + catchAllHandler.ifnull(rethrow); // stack: [ex] [EW] catchAllHandler.dup(); // stack: [ex] [EW] [EW] @@ -486,7 +486,7 @@ private void makeInstrumented() { Label fail = codeBuilder.newLabel(); if (guardEventConfiguration) { getEventConfiguration(codeBuilder); - codeBuilder.if_null(fail); + codeBuilder.ifnull(fail); } // if (!eventConfiguration.shouldCommit(duration) goto fail; getEventConfiguration(codeBuilder); @@ -525,7 +525,7 @@ private void makeInstrumented() { if (guardEventConfiguration) { // if (eventConfiguration == null) goto fail; getEventConfiguration(codeBuilder); - codeBuilder.if_null(fail); + codeBuilder.ifnull(fail); } // return eventConfiguration.shouldCommit(duration); getEventConfiguration(codeBuilder); @@ -738,7 +738,7 @@ private void updateEnabledMethod(MethodDesc method) { Label nullLabel = codeBuilder.newLabel(); if (guardEventConfiguration) { getEventConfiguration(codeBuilder); - codeBuilder.if_null(nullLabel); + codeBuilder.ifnull(nullLabel); } getEventConfiguration(codeBuilder); invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 0c9b771c3ef62..7905a79fd40bf 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -257,8 +257,8 @@ public void accept(CodeBuilder cob, CodeElement coe) { case IF_ICMPLE -> cob.if_icmple(target); case IF_ICMPLT -> cob.if_icmplt(target); case IF_ICMPNE -> cob.if_icmpne(target); - case IFNONNULL -> cob.if_nonnull(target); - case IFNULL -> cob.if_null(target); + case IFNONNULL -> cob.ifnonnull(target); + case IFNULL -> cob.ifnull(target); case IFEQ -> cob.ifeq(target); case IFGE -> cob.ifge(target); case IFGT -> cob.ifgt(target); From f9b4ea13e693da268c9aee27dee49f9c7f798bb1 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Jul 2024 02:56:17 +0000 Subject: [PATCH 131/288] 8334220: Optimize Klass layout after JDK-8180450 Reviewed-by: coleenp, stuefe, dholmes --- src/hotspot/share/oops/klass.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 2923235e2f3d2..6ec6ac889be71 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -159,11 +159,6 @@ class Klass : public Metadata { // Provide access the corresponding instance java.lang.ClassLoader. ClassLoaderData* _class_loader_data; - // Bitmap and hash code used by hashed secondary supers. - uintx _bitmap; - uint8_t _hash_slot; - - static uint8_t compute_hash_slot(Symbol* s); int _vtable_len; // vtable length. This field may be read very often when we // have lots of itable dispatches (e.g., lambdas and streams). @@ -173,6 +168,10 @@ class Klass : public Metadata { JFR_ONLY(DEFINE_TRACE_ID_FIELD;) + // Bitmap and hash code used by hashed secondary supers. + uintx _bitmap; + uint8_t _hash_slot; + private: // This is an index into FileMapHeader::_shared_path_table[], to // associate this class with the JAR file where it's loaded from during @@ -392,6 +391,7 @@ class Klass : public Metadata { void set_next_sibling(Klass* s); private: + static uint8_t compute_hash_slot(Symbol* s); static void hash_insert(Klass* klass, GrowableArray* secondaries, uintx& bitmap); static uintx hash_secondary_supers(Array* secondaries, bool rewrite); From fac74b118f5fda4ec297e46238d34ce5b9be1e21 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Jul 2024 03:01:06 +0000 Subject: [PATCH 132/288] 8334229: Optimize InterpreterOopMap layout Reviewed-by: coleenp, dholmes --- src/hotspot/share/interpreter/oopMapCache.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index a3f5c395f589a..7037b2c7d1fcf 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -83,21 +83,21 @@ class InterpreterOopMap: ResourceObj { private: Method* _method; // the method for which the mask is valid - unsigned short _bci; // the bci for which the mask is valid int _mask_size; // the mask size in bits (USHRT_MAX if invalid) int _expression_stack_size; // the size of the expression stack in slots + unsigned short _bci; // the bci for which the mask is valid protected: +#ifdef ASSERT + bool _resource_allocate_bit_mask; +#endif + int _num_oops; intptr_t _bit_mask[N]; // the bit mask if // mask_size <= small_mask_limit, // ptr to bit mask otherwise // "protected" so that sub classes can // access it without using trickery in // method bit_mask(). - int _num_oops; -#ifdef ASSERT - bool _resource_allocate_bit_mask; -#endif // access methods Method* method() const { return _method; } From d51141e5fc84f9f933e78d0eb25af86e41798ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 3 Jul 2024 04:36:32 +0000 Subject: [PATCH 133/288] 8321274: Rename ZipEntry.extraAttributes to ZipEntry.externalFileAttributes Reviewed-by: lancea, jpai --- .../share/classes/java/util/zip/ZipEntry.java | 4 +-- .../share/classes/java/util/zip/ZipFile.java | 10 +++---- .../java/util/zip/ZipOutputStream.java | 4 +-- .../access/JavaUtilZipFileAccess.java | 6 ++--- .../jdk/security/jarsigner/JarSigner.java | 16 +++++------- .../sun/security/tools/jarsigner/Main.java | 14 +++++----- .../security/tools/jarsigner/Resources.java | 4 +-- .../tools/jarsigner/Resources_de.java | 4 +-- .../tools/jarsigner/Resources_ja.java | 4 +-- .../tools/jarsigner/Resources_zh_CN.java | 4 +-- .../classes/jdk/nio/zipfs/ZipFileSystem.java | 26 +++++++++---------- .../security/tools/jarsigner/SymLinkTest.java | 12 ++++----- 12 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java index 85bd6155fa817..d97760d950ab3 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -59,7 +59,7 @@ public class ZipEntry implements ZipConstants, Cloneable { int flag = 0; // general purpose flag byte[] extra; // optional extra field data for entry String comment; // optional comment string for entry - int extraAttributes = -1; // e.g. POSIX permissions, sym links. + int externalFileAttributes = -1; // File type, setuid, setgid, sticky, POSIX permissions /** * Compression method for uncompressed entries. */ @@ -134,7 +134,7 @@ public ZipEntry(ZipEntry e) { flag = e.flag; extra = e.extra; comment = e.comment; - extraAttributes = e.extraAttributes; + externalFileAttributes = e.externalFileAttributes; } /** diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 4f4c410a83e9d..da8ab730873f2 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -697,7 +697,7 @@ private ZipEntry getZipEntry(String name, int pos) { e.method = CENHOW(cen, pos); if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) { // read all bits in this field, including sym link attributes - e.extraAttributes = CENATX_PERMS(cen, pos) & 0xFFFF; + e.externalFileAttributes = CENATX_PERMS(cen, pos) & 0xFFFF; } if (elen != 0) { @@ -1165,12 +1165,12 @@ public Stream entryNameStream(ZipFile zip) { return zip.entryNameStream(); } @Override - public int getExtraAttributes(ZipEntry ze) { - return ze.extraAttributes; + public int getExternalFileAttributes(ZipEntry ze) { + return ze.externalFileAttributes; } @Override - public void setExtraAttributes(ZipEntry ze, int extraAttrs) { - ze.extraAttributes = extraAttrs; + public void setExternalFileAttributes(ZipEntry ze, int externalFileAttributes) { + ze.externalFileAttributes = externalFileAttributes; } } diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index e1d403558600e..231e6629a54ae 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -541,7 +541,7 @@ private void writeEXT(ZipEntry e) throws IOException { * to a version value. */ private int versionMadeBy(ZipEntry e, int version) { - return (e.extraAttributes < 0) ? version : + return (e.externalFileAttributes < 0) ? version : VERSION_MADE_BY_BASE_UNIX | (version & 0xff); } @@ -637,7 +637,7 @@ private void writeCEN(XEntry xentry) throws IOException { writeShort(0); // starting disk number writeShort(0); // internal file attributes (unused) // extra file attributes, used for storing posix permissions etc. - writeInt(e.extraAttributes > 0 ? e.extraAttributes << 16 : 0); + writeInt(e.externalFileAttributes > 0 ? e.externalFileAttributes << 16 : 0); writeInt(offset); // relative offset of local header writeBytes(nameBytes, 0, nameBytes.length); diff --git a/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java index 3728a6c70d410..2c9d904005d80 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public interface JavaUtilZipFileAccess { public Enumeration entries(ZipFile zip); public Stream stream(ZipFile zip); public Stream entryNameStream(ZipFile zip); - public void setExtraAttributes(ZipEntry ze, int extraAttrs); - public int getExtraAttributes(ZipEntry ze); + public void setExternalFileAttributes(ZipEntry ze, int externalFileAttributes); + public int getExternalFileAttributes(ZipEntry ze); } diff --git a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java index 5dbaf6041ee25..3ff0f2663a223 100644 --- a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java +++ b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +31,6 @@ import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs.PKCS9Attributes; import sun.security.timestamp.HttpTimestamper; -import sun.security.tools.PathList; import sun.security.util.Event; import sun.security.util.ManifestDigester; import sun.security.util.SignatureFileVerifier; @@ -39,11 +38,8 @@ import sun.security.x509.AlgorithmId; import java.io.*; -import java.lang.reflect.InvocationTargetException; import java.net.SocketTimeoutException; import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; import java.security.*; import java.security.cert.CertPath; import java.security.cert.Certificate; @@ -492,7 +488,7 @@ public JarSigner build() { private final String tSADigestAlg; private final boolean sectionsonly; // do not "sign" the whole manifest private final boolean internalsf; // include the .SF inside the PKCS7 block - private boolean extraAttrsDetected; + private boolean externalFileAttributesDetected; private JarSigner(JarSigner.Builder builder) { @@ -936,12 +932,12 @@ private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze) ze2.setTime(ze.getTime()); ze2.setComment(ze.getComment()); ze2.setExtra(ze.getExtra()); - int extraAttrs = JUZFA.getExtraAttributes(ze); - if (!extraAttrsDetected && extraAttrs != -1) { - extraAttrsDetected = true; + int externalFileAttributes = JUZFA.getExternalFileAttributes(ze); + if (!externalFileAttributesDetected && externalFileAttributes != -1) { + externalFileAttributesDetected = true; Event.report(Event.ReporterCategory.ZIPFILEATTRS, "detected"); } - JUZFA.setExtraAttributes(ze2, extraAttrs); + JUZFA.setExternalFileAttributes(ze2, externalFileAttributes); if (ze.getMethod() == ZipEntry.STORED) { ze2.setSize(ze.getSize()); ze2.setCrc(ze.getCrc()); diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index e011145632dfa..78a03a4332d47 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ public class Main { private static final Set SIG_PRIMITIVE_SET = Collections .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); - private static boolean extraAttrsDetected; + private static boolean externalFileAttributesDetected; static final String VERSION = "1.0"; @@ -823,8 +823,8 @@ void verifyJar(String jarName) JarEntry je = e.nextElement(); String name = je.getName(); - if (!extraAttrsDetected && JUZFA.getExtraAttributes(je) != -1) { - extraAttrsDetected = true; + if (!externalFileAttributesDetected && JUZFA.getExternalFileAttributes(je) != -1) { + externalFileAttributesDetected = true; } hasSignature |= signatureRelated(name) && SignatureFileVerifier.isBlockOrSF(name); @@ -1311,8 +1311,8 @@ private void displayMessagesAndResult(boolean isSigning) { } } - if (extraAttrsDetected) { - warnings.add(rb.getString("extra.attributes.detected")); + if (externalFileAttributesDetected) { + warnings.add(rb.getString("external.file.attributes.detected")); } if ((strict) && (!errors.isEmpty())) { @@ -1946,7 +1946,7 @@ void signJar(String jarName, String alias) try { Event.setReportListener(Event.ReporterCategory.ZIPFILEATTRS, - (t, o) -> extraAttrsDetected = true); + (t, o) -> externalFileAttributesDetected = true); builder.build().sign(zipFile, fos); } catch (JarSignerException e) { failedCause = e.getCause(); diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index d982f618600f3..6a86b72ad1b10 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources extends java.util.ListResourceBundle { {"key.bit.disabled", "%d-bit key (disabled)"}, {"key.bit.eccurve.disabled", "%1$d-bit %2$s key (disabled)"}, {"unknown.size", "unknown size"}, - {"extra.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, + {"external.file.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java index 06c8a901cd264..b11c491be1492 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_de.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources_de extends java.util.ListResourceBundle { {"key.bit.disabled", "%d-Bit-Schl\u00FCssel (deaktiviert)"}, {"key.bit.eccurve.disabled", "%1$d-Bit-%2$s-Schl\u00FCssel (deaktiviert)"}, {"unknown.size", "unbekannte Gr\u00F6\u00DFe"}, - {"extra.attributes.detected", "POSIX-Dateiberechtigung und/oder Symlink-Attribute erkannt. Diese Attribute werden bei der Signatur ignoriert und sind nicht durch die Signatur gesch\u00FCtzt."}, + {"external.file.attributes.detected", "POSIX-Dateiberechtigung und/oder Symlink-Attribute erkannt. Diese Attribute werden bei der Signatur ignoriert und sind nicht durch die Signatur gesch\u00FCtzt."}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java index 1d8e7c54a3c29..3754d864ce107 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_ja.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources_ja extends java.util.ListResourceBundle { {"key.bit.disabled", "%d\u30D3\u30C3\u30C8\u30FB\u30AD\u30FC (\u7121\u52B9)"}, {"key.bit.eccurve.disabled", "%1$d\u30D3\u30C3\u30C8%2$s\u30AD\u30FC(\u7121\u52B9)"}, {"unknown.size", "\u4E0D\u660E\u30B5\u30A4\u30BA"}, - {"extra.attributes.detected", "POSIX\u30D5\u30A1\u30A4\u30EB\u6A29\u9650\u307E\u305F\u306Fsymlink(\u3042\u308B\u3044\u306F\u305D\u306E\u4E21\u65B9)\u306E\u5C5E\u6027\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\u3002\u7F72\u540D\u4E2D\u306F\u3053\u308C\u3089\u306E\u5C5E\u6027\u306F\u7121\u8996\u3055\u308C\u3001\u7F72\u540D\u306B\u3088\u3063\u3066\u4FDD\u8B77\u3055\u308C\u307E\u305B\u3093\u3002"}, + {"external.file.attributes.detected", "POSIX\u30D5\u30A1\u30A4\u30EB\u6A29\u9650\u307E\u305F\u306Fsymlink(\u3042\u308B\u3044\u306F\u305D\u306E\u4E21\u65B9)\u306E\u5C5E\u6027\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\u3002\u7F72\u540D\u4E2D\u306F\u3053\u308C\u3089\u306E\u5C5E\u6027\u306F\u7121\u8996\u3055\u308C\u3001\u7F72\u540D\u306B\u3088\u3063\u3066\u4FDD\u8B77\u3055\u308C\u307E\u305B\u3093\u3002"}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java index 2b4059ea877c5..9e76346fca278 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources_zh_CN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ public class Resources_zh_CN extends java.util.ListResourceBundle { {"key.bit.disabled", "%d \u4F4D\u5BC6\u94A5\uFF08\u7981\u7528\uFF09"}, {"key.bit.eccurve.disabled", "%1$d \u4F4D %2$s \u5BC6\u94A5\uFF08\u7981\u7528\uFF09"}, {"unknown.size", "\u672A\u77E5\u5927\u5C0F"}, - {"extra.attributes.detected", "\u68C0\u6D4B\u5230 POSIX \u6587\u4EF6\u6743\u9650\u548C/\u6216 symlink \u5C5E\u6027\u3002\u8FD9\u4E9B\u5C5E\u6027\u5728\u8FDB\u884C\u7B7E\u540D\u65F6\u4F1A\u88AB\u5FFD\u7565\uFF0C\u4E0D\u53D7\u8BE5\u7B7E\u540D\u7684\u4FDD\u62A4\u3002"}, + {"external.file.attributes.detected", "\u68C0\u6D4B\u5230 POSIX \u6587\u4EF6\u6743\u9650\u548C/\u6216 symlink \u5C5E\u6027\u3002\u8FD9\u4E9B\u5C5E\u6027\u5728\u8FDB\u884C\u7B7E\u540D\u65F6\u4F1A\u88AB\u5FFD\u7565\uFF0C\u4E0D\u53D7\u8BE5\u7B7E\u540D\u7684\u4FDD\u62A4\u3002"}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index cecb8b86a2dc8..5e5b665790f96 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -645,12 +645,12 @@ void setPermissions(byte[] path, Set perms) throws IOExcept e.type = Entry.COPY; // copy e } if (perms == null) { - e.posixPerms = -1; - } else if (e.posixPerms == -1) { - e.posixPerms = ZipUtils.permsToFlags(perms); + e.externalFileAttributes = -1; + } else if (e.externalFileAttributes == -1) { + e.externalFileAttributes = ZipUtils.permsToFlags(perms); } else { - e.posixPerms = ZipUtils.permsToFlags(perms) | - (e.posixPerms & 0xFE00); // Preserve unrelated bits + e.externalFileAttributes = ZipUtils.permsToFlags(perms) | + (e.externalFileAttributes & 0xFE00); // Preserve unrelated bits } update(e); } finally { @@ -2887,7 +2887,7 @@ static class Entry extends IndexNode implements ZipFileAttributes { // entry attributes int version; int flag; - int posixPerms = -1; // posix permissions + int externalFileAttributes = -1; // file type, setuid, setgid, sticky, posix permissions int method = -1; // compression method long mtime = -1; // last modification time (in DOS time) long atime = -1; // last access time @@ -2923,7 +2923,7 @@ static class Entry extends IndexNode implements ZipFileAttributes { for (FileAttribute attr : attrs) { String attrName = attr.name(); if (attrName.equals("posix:permissions")) { - posixPerms = ZipUtils.permsToFlags((Set)attr.value()); + externalFileAttributes = ZipUtils.permsToFlags((Set)attr.value()); } } } @@ -2958,7 +2958,7 @@ static class Entry extends IndexNode implements ZipFileAttributes { */ this.locoff = e.locoff; this.comment = e.comment; - this.posixPerms = e.posixPerms; + this.externalFileAttributes = e.externalFileAttributes; this.type = type; } @@ -2988,7 +2988,7 @@ else if (method == METHOD_STORED) * to a version value. */ private int versionMadeBy(int version) { - return (posixPerms < 0) ? version : + return (externalFileAttributes < 0) ? version : VERSION_MADE_BY_BASE_UNIX | (version & 0xff); } @@ -3015,7 +3015,7 @@ private void readCEN(ZipFileSystem zipfs, IndexNode inode) throws IOException { attrsEx = CENATX(cen, pos); */ if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) { - posixPerms = (CENATX_PERMS(cen, pos) & 0xFFFF); // 16 bits for file type, setuid, setgid, sticky + perms + externalFileAttributes = (CENATX_PERMS(cen, pos) & 0xFFFF); // 16 bits for file type, setuid, setgid, sticky + perms } locoff = CENOFF(cen, pos); pos += CENHDR; @@ -3105,7 +3105,7 @@ private int writeCEN(OutputStream os) throws IOException { } writeShort(os, 0); // starting disk number writeShort(os, 0); // internal file attributes (unused) - writeInt(os, posixPerms > 0 ? posixPerms << 16 : 0); // external file + writeInt(os, externalFileAttributes > 0 ? externalFileAttributes << 16 : 0); // external file // attributes, used for storing posix // permissions writeInt(os, locoff0); // relative offset of local header @@ -3528,10 +3528,10 @@ public byte[] comment() { @Override public Optional> storedPermissions() { Set perms = null; - if (posixPerms != -1) { + if (externalFileAttributes != -1) { perms = HashSet.newHashSet(PosixFilePermission.values().length); for (PosixFilePermission perm : PosixFilePermission.values()) { - if ((posixPerms & ZipUtils.permToFlag(perm)) != 0) { + if ((externalFileAttributes & ZipUtils.permToFlag(perm)) != 0) { perms.add(perm); } } diff --git a/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java b/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java index c96eeeeb74d0d..db9811d4ec349 100644 --- a/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java +++ b/test/jdk/sun/security/tools/jarsigner/SymLinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +57,7 @@ public static void main(String[] args) throws Exception { Files.write(Path.of(ZIPFILENAME), ZIPBYTES); // check attributes before signing - verifyExtraAttrs(ZIPFILENAME); + verifyExternalFileAttributes(ZIPFILENAME); // generate key for signing SecurityTools.keytool( @@ -82,7 +82,7 @@ public static void main(String[] args) throws Exception { .shouldContain(WARNING_MSG); // recheck attributes after signing - verifyExtraAttrs(ZIPFILENAME); + verifyExternalFileAttributes(ZIPFILENAME); // verify zip file - expect warning SecurityTools.jarsigner( @@ -95,8 +95,8 @@ public static void main(String[] args) throws Exception { .shouldContain(WARNING_MSG); } - private static void verifyExtraAttrs(String zipFileName) throws IOException { - // the 16 bit extra attributes value should equal 0xa1ff - look for that pattern. + private static void verifyExternalFileAttributes(String zipFileName) throws IOException { + // the 16 bit 'external file attributes' value should equal 0xa1ff - look for that pattern. // Such values can be read from zip file via 'unzip -Z -l -v ' try (FileInputStream fis = new FileInputStream(ZIPFILENAME)) { byte[] b = fis.readAllBytes(); @@ -107,7 +107,7 @@ private static void verifyExtraAttrs(String zipFileName) throws IOException { return; } } - throw new RuntimeException("extra attribute value not detected"); + throw new RuntimeException("external file attribute value not detected"); } } From 0db9bc57de07f8f1d0bf657621cb1b8fd7b01211 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Jul 2024 05:03:56 +0000 Subject: [PATCH 134/288] 8335290: Rename ClassFile::transform to ClassFile::transformClass Reviewed-by: asotona --- .../share/classes/java/lang/Module.java | 6 +-- .../java/lang/classfile/ClassFile.java | 15 ++++---- .../lang/classfile/ClassFileTransform.java | 2 +- .../classfile/components/ClassRemapper.java | 2 +- .../snippet-files/PackageSnippets.java | 8 ++-- .../snippet-files/PackageSnippets.java | 6 +-- .../classfile/impl/ClassFileImpl.java | 2 +- .../internal/module/ModuleInfoExtender.java | 2 +- .../StripJavaDebugAttributesPlugin.java | 2 +- .../internal/plugins/VersionPropsPlugin.java | 2 +- .../execution/LocalExecutionControl.java | 2 +- .../records/BadCanonicalCtrTest.java | 6 +-- .../records/ProhibitedMethods.java | 4 +- .../records/SerialPersistentFieldsTest.java | 4 +- .../lang/ModuleTests/AnnotationsTest.java | 4 +- .../lang/instrument/asmlib/Instrumentor.java | 4 +- .../java/lang/invoke/8022701/BogoLoader.java | 4 +- .../accessProtectedSuper/BogoLoader.java | 4 +- test/jdk/jdk/classfile/AdaptCodeTest.java | 8 ++-- .../AdvancedTransformationsTest.java | 6 +-- test/jdk/jdk/classfile/BSMTest.java | 4 +- test/jdk/jdk/classfile/ClassBuildingTest.java | 4 +- .../jdk/classfile/ClassHierarchyInfoTest.java | 4 +- test/jdk/jdk/classfile/CorpusTest.java | 6 +-- .../DiscontinuedInstructionsTest.java | 10 ++--- test/jdk/jdk/classfile/LvtTest.java | 4 +- .../jdk/classfile/MassAdaptCopyCodeTest.java | 4 +- .../MassAdaptCopyPrimitiveMatchCodeTest.java | 4 +- test/jdk/jdk/classfile/OptionsTest.java | 6 +-- test/jdk/jdk/classfile/ShortJumpsFixTest.java | 18 ++++----- test/jdk/jdk/classfile/StackMapsTest.java | 4 +- .../jdk/classfile/TestRecordComponent.java | 8 ++-- test/jdk/jdk/classfile/TransformTests.java | 14 +++---- test/jdk/jdk/classfile/VerifierSelfTest.java | 4 +- .../examples/AnnotationsExamples.java | 12 +++--- .../classfile/examples/ExampleGallery.java | 38 +++++++++---------- .../ExperimentalTransformExamples.java | 4 +- .../classfile/examples/TransformExamples.java | 12 +++--- .../jdk/jdk/classfile/helpers/Transforms.java | 10 ++--- .../jdk/jfr/event/io/TestInstrumentation.java | 2 +- .../javaagent/TestEventInstrumentation.java | 2 +- .../separate/ClassToInterfaceConverter.java | 4 +- .../tools/javac/MethodParametersTest.java | 6 +-- .../classreader/8171132/BadConstantValue.java | 3 +- .../javac/classreader/BadMethodParameter.java | 3 +- .../javac/defaultMethods/BadClassfile.java | 4 +- .../javac/launcher/SourceLauncherTest.java | 2 +- .../tools/javac/modules/IncubatingTest.java | 4 +- .../tools/javac/modules/JavaBaseTest.java | 4 +- .../tools/javac/modules/OpenModulesTest.java | 4 +- .../createsymbols/CreateSymbolsTestImpl.java | 4 +- .../processing/model/element/TestOrigin.java | 4 +- .../tools/javap/UndefinedAccessFlagTest.java | 2 +- .../bench/jdk/classfile/AdHocAdapt.java | 4 +- .../jdk/classfile/ClassfileBenchmark.java | 8 ++-- .../bench/jdk/classfile/ParseOptions.java | 8 ++-- .../jdk/classfile/RebuildMethodBodies.java | 4 +- .../bench/jdk/classfile/Transforms.java | 10 ++--- 58 files changed, 171 insertions(+), 174 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index 82dae27efa039..d7a7081861834 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -54,13 +54,9 @@ import java.util.stream.Stream; import java.lang.classfile.AccessFlags; import java.lang.classfile.Attribute; -import java.lang.classfile.ClassModel; -import java.lang.classfile.ClassTransform; import java.lang.classfile.ClassFile; -import java.lang.classfile.attribute.ModuleAttribute; import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import jdk.internal.javac.PreviewFeature; import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; @@ -1588,7 +1584,7 @@ private Class loadModuleInfoClass() { private Class loadModuleInfoClass(InputStream in) throws IOException { final String MODULE_INFO = "module-info"; var cc = ClassFile.of(ClassFile.ConstantPoolSharingOption.NEW_POOL); - byte[] bytes = cc.transform(cc.parse(in.readAllBytes()), (clb, cle) -> { + byte[] bytes = cc.transformClass(cc.parse(in.readAllBytes()), (clb, cle) -> { switch (cle) { case AccessFlags af -> clb.withFlags(AccessFlag.INTERFACE, AccessFlag.ABSTRACT, AccessFlag.SYNTHETIC); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index 1997ffb487ce0..08745f7e1bafc 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -32,7 +32,6 @@ import java.util.function.Function; import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.UnknownAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.Utf8Entry; @@ -435,15 +434,15 @@ default void buildModuleTo(Path path, * This method behaves as if: * {@snippet lang=java : * this.build(model.thisClass(), ConstantPoolBuilder.of(model), - * b -> b.transform(model, transform)); + * clb -> clb.transform(model, transform)); * } * * @param model the class model to transform * @param transform the transform * @return the bytes of the new class */ - default byte[] transform(ClassModel model, ClassTransform transform) { - return transform(model, model.thisClass(), transform); + default byte[] transformClass(ClassModel model, ClassTransform transform) { + return transformClass(model, model.thisClass(), transform); } /** @@ -458,8 +457,8 @@ default byte[] transform(ClassModel model, ClassTransform transform) { * @param transform the transform * @return the bytes of the new class */ - default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransform transform) { - return transform(model, TemporaryConstantPool.INSTANCE.classEntry(newClassName), transform); + default byte[] transformClass(ClassModel model, ClassDesc newClassName, ClassTransform transform) { + return transformClass(model, TemporaryConstantPool.INSTANCE.classEntry(newClassName), transform); } /** @@ -473,7 +472,7 @@ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransfor * This method behaves as if: * {@snippet lang=java : * this.build(newClassName, ConstantPoolBuilder.of(model), - * b -> b.transform(model, transform)); + * clb -> clb.transform(model, transform)); * } * * @param model the class model to transform @@ -481,7 +480,7 @@ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransfor * @param transform the transform * @return the bytes of the new class */ - byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform); + byte[] transformClass(ClassModel model, ClassEntry newClassName, ClassTransform transform); /** * Verify a classfile. Any verification errors found will be returned. diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java index 677478ec650a4..f67da06a36de0 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java @@ -33,7 +33,7 @@ /** * A transformation on streams of elements. Transforms are used during * transformation of classfile entities; a transform is provided to a method like - * {@link ClassFile#transform(ClassModel, ClassTransform)}, and the elements of the class, + * {@link ClassFile#transformClass(ClassModel, ClassTransform)}, and the elements of the class, * along with a builder, are presented to the transform. * *

    The subtypes of {@linkplain diff --git a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java index c69806b18c4c0..d3ae180dde573 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java +++ b/src/java.base/share/classes/java/lang/classfile/components/ClassRemapper.java @@ -107,6 +107,6 @@ static ClassRemapper of(Function mapFunction) { * @return re-mapped class file bytes */ default byte[] remapClass(ClassFile context, ClassModel clm) { - return context.transform(clm, map(clm.thisClass().asSymbol()), this); + return context.transformClass(clm, map(clm.thisClass().asSymbol()), this); } } diff --git a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java index f96be4e0cdf01..b53e921381333 100644 --- a/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/java/lang/classfile/components/snippet-files/PackageSnippets.java @@ -130,7 +130,7 @@ void allPackageRemap(ClassModel... allMyClasses) { void codeLocalsShifting(ClassModel classModel) { // @start region="codeLocalsShifting" - byte[] newBytes = ClassFile.of().transform( + byte[] newBytes = ClassFile.of().transformClass( classModel, (classBuilder, classElement) -> { if (classElement instanceof MethodModel method) @@ -145,7 +145,7 @@ void codeLocalsShifting(ClassModel classModel) { void codeRelabeling(ClassModel classModel) { // @start region="codeRelabeling" - byte[] newBytes = ClassFile.of().transform( + byte[] newBytes = ClassFile.of().transformClass( classModel, ClassTransform.transformingMethodBodies( CodeTransform.ofStateful(CodeRelabeler::of))); @@ -160,7 +160,7 @@ byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicat var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); - return ClassFile.of().transform(target, + return ClassFile.of().transformClass(target, ClassTransform.transformingMethods( instrumentedMethodsFilter, (mb, me) -> { @@ -191,7 +191,7 @@ byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicat //inlined target locals must be shifted based on the actual instrumentor locals codeBuilder.block(inlinedBlockBuilder -> inlinedBlockBuilder - .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) + .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) .andThen(CodeRelabeler.of()) .andThen((innerBuilder, shiftedTargetCode) -> { //returns must be replaced with jump to the end of the inlined method diff --git a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java index 5073e108465ad..b80c1c8328411 100644 --- a/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/java/lang/classfile/snippet-files/PackageSnippets.java @@ -195,7 +195,7 @@ void stripDebugMethods2(byte[] bytes) { builder.with(element); }; var cc = ClassFile.of(); - byte[] newBytes = cc.transform(cc.parse(bytes), ct); + byte[] newBytes = cc.transformClass(cc.parse(bytes), ct); // @end } @@ -346,7 +346,7 @@ void fooToBarUnrolled(ClassModel classModel) { void codeRelabeling(ClassModel classModel) { // @start region="codeRelabeling" - byte[] newBytes = ClassFile.of().transform(classModel, + byte[] newBytes = ClassFile.of().transformClass(classModel, ClassTransform.transformingMethodBodies( CodeTransform.ofStateful(CodeRelabeler::of))); // @end @@ -360,7 +360,7 @@ byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicat var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); - return ClassFile.of().transform(target, + return ClassFile.of().transformClass(target, ClassTransform.transformingMethods( instrumentedMethodsFilter, (mb, me) -> { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index 8bffbd6de4f5d..e4408d6c7b27d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java @@ -115,7 +115,7 @@ public byte[] build(ClassEntry thisClassEntry, } @Override - public byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform) { + public byte[] transformClass(ClassModel model, ClassEntry newClassName, ClassTransform transform) { ConstantPoolBuilder constantPool = constantPoolSharingOption() == ConstantPoolSharingOption.SHARED_POOL ? ConstantPoolBuilder.of(model) : ConstantPoolBuilder.of(); diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java index c9d3fd0adb60e..6bc32d54a3063 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java @@ -153,7 +153,7 @@ public byte[] toByteArray() throws IOException { var cc = ClassFile.of(); var cm = cc.parse(in.readAllBytes()); Version v = ModuleInfoExtender.this.version; - return cc.transform(cm, ClassTransform.endHandler(clb -> { + return cc.transformClass(cm, ClassTransform.endHandler(clb -> { // ModuleMainClass attribute if (mainClass != null) { clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mainClass))); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java index 536c5100cd845..bbf2bfacd007c 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin.java @@ -67,7 +67,7 @@ public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { var clm = newClassReader(path, resource, ClassFile.DebugElementsOption.DROP_DEBUG, ClassFile.LineNumbersOption.DROP_LINE_NUMBERS); - byte[] content = ClassFile.of().transform(clm, ClassTransform + byte[] content = ClassFile.of().transformClass(clm, ClassTransform .dropping(cle -> cle instanceof SourceFileAttribute || cle instanceof SourceDebugExtensionAttribute) .andThen(ClassTransform.transformingMethods(MethodTransform diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java index 973fa4d126851..f9a5463609a9f 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java @@ -101,7 +101,7 @@ public void configure(Map config) { @SuppressWarnings("deprecation") private byte[] redefine(String path, byte[] classFile) { - return ClassFile.of().transform(newClassReader(path, classFile), + return ClassFile.of().transformClass(newClassReader(path, classFile), ClassTransform.transformingMethodBodies( mm -> mm.methodName().equalsString(""), new CodeTransform() { diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java index a89c91d3667e8..3076c0fa76dce 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java @@ -89,7 +89,7 @@ public void load(ClassBytecodes[] cbcs) private static byte[] instrument(byte[] classFile) { var cc = ClassFile.of(); - return cc.transform(cc.parse(classFile), + return cc.transformClass(cc.parse(classFile), ClassTransform.transformingMethodBodies((cob, coe) -> { if (coe instanceof BranchInstruction) cob.invokestatic(CD_Cancel, "stopCheck", ConstantDescs.MTD_void); diff --git a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java index ca31213b28f57..c9b757a7b5136 100644 --- a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java +++ b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,7 @@ protected Class resolveClass(ObjectStreamClass desc) */ static byte[] removeConstructor(byte[] classBytes) { var cf = ClassFile.of(); - return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce -> + return cf.transformClass(cf.parse(classBytes), ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME))); } @@ -217,7 +217,7 @@ static byte[] removeConstructor(byte[] classBytes) { */ static byte[] modifyConstructor(byte[] classBytes) { var cf = ClassFile.of(); - return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce -> + return cf.transformClass(cf.parse(classBytes), ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) .andThen(ClassTransform.endHandler(clb -> clb.withMethodBody(INIT_NAME, MethodTypeDesc.of(CD_void, CD_Object), ACC_PUBLIC, cob -> { diff --git a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java index 53252aaf5586c..3a66e46f83b82 100644 --- a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java +++ b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,7 +243,7 @@ static byte[] addReadObjectNoData(byte[] classBytes) { static byte[] addMethod(byte[] classBytes, String name, MethodTypeDesc desc) { var cf = ClassFile.of(); - return cf.transform(cf.parse(classBytes), ClassTransform.endHandler(clb -> { + return cf.transformClass(cf.parse(classBytes), ClassTransform.endHandler(clb -> { clb.withMethodBody(name, desc, ACC_PRIVATE, cob -> { cob.loadConstant(name + " should not be invoked"); cob.invokestatic(Assert.class.describeConstable().orElseThrow(), "fail", diff --git a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java index 4ff15aa84d48e..12a5fe8c40264 100644 --- a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,7 +231,7 @@ static byte[] addSerialPersistentFields(byte[] classBytes, ObjectStreamField[] spf) { var cf = ClassFile.of(); var model = cf.parse(classBytes); - return cf.transform(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf)); + return cf.transformClass(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf)); } /** A visitor that adds a serialPersistentFields field, and assigns it in clinit. */ diff --git a/test/jdk/java/lang/ModuleTests/AnnotationsTest.java b/test/jdk/java/lang/ModuleTests/AnnotationsTest.java index 60487584273c4..1fffe710ce570 100644 --- a/test/jdk/java/lang/ModuleTests/AnnotationsTest.java +++ b/test/jdk/java/lang/ModuleTests/AnnotationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ public void testWithModuleInfoResourceXXXX() throws IOException { static byte[] addDeprecated(byte[] bytes, boolean forRemoval, String since) { var cf = ClassFile.of(); var oldModel = cf.parse(bytes); - return cf.transform(oldModel, new ClassTransform() { + return cf.transformClass(oldModel, new ClassTransform() { boolean rvaaFound = false; @Override diff --git a/test/jdk/java/lang/instrument/asmlib/Instrumentor.java b/test/jdk/java/lang/instrument/asmlib/Instrumentor.java index 29f2740a874cf..77893ed8a11b6 100644 --- a/test/jdk/java/lang/instrument/asmlib/Instrumentor.java +++ b/test/jdk/java/lang/instrument/asmlib/Instrumentor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ public void atEnd(ClassBuilder builder) { } public synchronized byte[] apply() { - var bytes = ClassFile.of().transform(model, transform); + var bytes = ClassFile.of().transformClass(model, transform); return dirty.get() ? bytes : null; } diff --git a/test/jdk/java/lang/invoke/8022701/BogoLoader.java b/test/jdk/java/lang/invoke/8022701/BogoLoader.java index ac06718b42a55..e497c169c3aa0 100644 --- a/test/jdk/java/lang/invoke/8022701/BogoLoader.java +++ b/test/jdk/java/lang/invoke/8022701/BogoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,7 @@ protected Class loadClass(String name, boolean resolve) System.err.println("Replacing class " + name); } var cf = ClassFile.of(); - classData = cf.transform(cf.parse(classData), replaced.get(name)); + classData = cf.transformClass(cf.parse(classData), replaced.get(name)); } clazz = defineClass(name, classData, 0, classData.length); } catch (java.io.EOFException ioe) { diff --git a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java index 0f14995992820..9ed6422f01534 100644 --- a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java +++ b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ protected Class loadClass(String name, boolean resolve) System.err.println("Replacing class " + name); } var cf = ClassFile.of(); - classData = cf.transform(cf.parse(classData), replaced.get(name)); + classData = cf.transformClass(cf.parse(classData), replaced.get(name)); } clazz = defineClass(name, classData, 0, classData.length); } catch (java.io.EOFException ioe) { diff --git a/test/jdk/jdk/classfile/AdaptCodeTest.java b/test/jdk/jdk/classfile/AdaptCodeTest.java index 2a75cd7e02069..2b9dff588190a 100644 --- a/test/jdk/jdk/classfile/AdaptCodeTest.java +++ b/test/jdk/jdk/classfile/AdaptCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ void testNullAdaptIterator() throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(testClassPath); for (ClassTransform t : Transforms.noops) { - byte[] newBytes = cc.transform(cm, t); + byte[] newBytes = cc.transformClass(cm, t); String result = (String) new ByteArrayClassLoader(AdaptCodeTest.class.getClassLoader(), testClassName, newBytes) .getMethod(testClassName, "many") @@ -79,7 +79,7 @@ void testNullAdaptIterator2(String path) throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(fs.getPath(path)); for (ClassTransform t : Transforms.noops) { - byte[] newBytes = cc.transform(cm, t); + byte[] newBytes = cc.transformClass(cm, t); } } @@ -101,7 +101,7 @@ void testSevenOfThirteenIterator() throws Exception { } }); - byte[] newBytes = cc.transform(cm, transform); + byte[] newBytes = cc.transformClass(cm, transform); // Files.write(Path.of("foo.class"), newBytes); String result = (String) new ByteArrayClassLoader(AdaptCodeTest.class.getClassLoader(), testClassName, newBytes) diff --git a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java index 88792eedcf15f..6c7194271a477 100644 --- a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java +++ b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java @@ -77,7 +77,7 @@ void testShiftLocals() throws Exception { try (var in = StackMapGenerator.class.getResourceAsStream("StackMapGenerator.class")) { var cc = ClassFile.of(); var clm = cc.parse(in.readAllBytes()); - cc.verify(cc.transform(clm, (clb, cle) -> { + cc.verify(cc.transformClass(clm, (clb, cle) -> { if (cle instanceof MethodModel mm) { clb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel com) { @@ -303,7 +303,7 @@ private static byte[] instrument(ClassModel target, ClassModel instrumentor, Pre var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet()); var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet()); var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol())); - return ClassFile.of().transform(target, + return ClassFile.of().transformClass(target, ClassTransform.transformingMethods( instrumentedMethodsFilter, (mb, me) -> { @@ -334,7 +334,7 @@ private static byte[] instrument(ClassModel target, ClassModel instrumentor, Pre //inlined target locals must be shifted based on the actual instrumentor locals codeBuilder.block(inlinedBlockBuilder -> inlinedBlockBuilder - .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) + .transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol()) .andThen(CodeRelabeler.of()) .andThen((innerBuilder, shiftedTargetCode) -> { //returns must be replaced with jump to the end of the inlined method diff --git a/test/jdk/jdk/classfile/BSMTest.java b/test/jdk/jdk/classfile/BSMTest.java index 927549f021069..d0cc87d749373 100644 --- a/test/jdk/jdk/classfile/BSMTest.java +++ b/test/jdk/jdk/classfile/BSMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ public class BSMTest { void testSevenOfThirteenIterator() throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(testClassPath); - byte[] newBytes = cc.transform(cm, (cb, ce) -> { + byte[] newBytes = cc.transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { diff --git a/test/jdk/jdk/classfile/ClassBuildingTest.java b/test/jdk/jdk/classfile/ClassBuildingTest.java index 83c794ae87997..bf6380ae8feb0 100644 --- a/test/jdk/jdk/classfile/ClassBuildingTest.java +++ b/test/jdk/jdk/classfile/ClassBuildingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public void test() throws Throwable { transform = transform.andThen(ClassTransform.transformingMethods(MethodTransform.dropping(me -> me instanceof SignatureAttribute))); - MethodHandles.lookup().defineClass(cc.transform(cm, transform)); + MethodHandles.lookup().defineClass(cc.transformClass(cm, transform)); } } diff --git a/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java b/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java index b8eadeda5e12b..4065f1d5e2f9e 100644 --- a/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java +++ b/test/jdk/jdk/classfile/ClassHierarchyInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,7 +122,7 @@ void transformAndVerify(ClassHierarchyResolver res) throws Exception { void transformAndVerifySingle(ClassHierarchyResolver res) throws Exception { Path path = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules/java.base/java/util/HashMap.class"); var classModel = ClassFile.of().parse(path); - byte[] newBytes = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(res)).transform(classModel, + byte[] newBytes = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(res)).transformClass(classModel, (clb, cle) -> { if (cle instanceof MethodModel mm) { clb.transformMethod(mm, (mb, me) -> { diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index 64db67e6d8eb0..67a2ebabb31d2 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -79,7 +79,7 @@ class CorpusTest { static void splitTableAttributes(String sourceClassFile, String targetClassFile) throws IOException, URISyntaxException { var root = Paths.get(URI.create(CorpusTest.class.getResource("CorpusTest.class").toString())).getParent(); var cc = ClassFile.of(); - Files.write(root.resolve(targetClassFile), cc.transform(cc.parse(root.resolve(sourceClassFile)), ClassTransform.transformingMethodBodies((cob, coe) -> { + Files.write(root.resolve(targetClassFile), cc.transformClass(cc.parse(root.resolve(sourceClassFile)), ClassTransform.transformingMethodBodies((cob, coe) -> { var dcob = (DirectCodeBuilder)cob; var curPc = dcob.curPc(); switch (coe) { @@ -147,7 +147,7 @@ void testNullAdaptations(Path path) throws Exception { try { byte[] transformed = m.shared && m.classTransform != null ? ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS) - .transform(ClassFile.of().parse(bytes), m.classTransform) + .transformClass(ClassFile.of().parse(bytes), m.classTransform) : m.transform.apply(bytes); Map newDups = findDups(transformed); oldRecord = m.classRecord(bytes); @@ -210,7 +210,7 @@ void testNullAdaptations(Path path) throws Exception { //testing maxStack and maxLocals are calculated identically by StackMapGenerator and StackCounter byte[] noStackMaps = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS) - .transform(newModel, + .transformClass(newModel, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)); var noStackModel = cc.parse(noStackMaps); var itStack = newModel.methods().iterator(); diff --git a/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java b/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java index be7e425c694dd..9070f0b1d4513 100644 --- a/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java +++ b/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void testJsrAndRetProcessing() throws Exception { .invoke(null, list); assertEquals(list, List.of("Hello", "World")); - bytes = cc.transform(cc.parse(bytes), ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)); + bytes = cc.transformClass(cc.parse(bytes), ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)); new ByteArrayClassLoader(DiscontinuedInstructionsTest.class.getClassLoader(), testClass, bytes) .getMethod(testClass, testMethod) @@ -84,17 +84,17 @@ void testJsrAndRetProcessing() throws Exception { var clm = cc.parse(bytes); //test failover stack map generation - cc.transform(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) + cc.transformClass(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(JAVA_6_VERSION, 0)))); //test failure of stack map generation for Java 7 assertThrows(IllegalArgumentException.class, () -> - cc.transform(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) + cc.transformClass(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(JAVA_7_VERSION, 0))))); //test failure of stack map generation when enforced to generate assertThrows(IllegalArgumentException.class, () -> ClassFile.of(ClassFile.StackMapsOption.GENERATE_STACK_MAPS) - .transform(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL))); + .transformClass(clm, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL))); } } diff --git a/test/jdk/jdk/classfile/LvtTest.java b/test/jdk/jdk/classfile/LvtTest.java index 7c60d75823af4..7fb289cc175d0 100644 --- a/test/jdk/jdk/classfile/LvtTest.java +++ b/test/jdk/jdk/classfile/LvtTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ void buildLVTEntries() throws Exception { ClassModel c = cc.parse(fileBytes); // Compare transformed model and original with CodeBuilder filter - byte[] newClass = cc.transform(c, Transforms.threeLevelNoop); + byte[] newClass = cc.transformClass(c, Transforms.threeLevelNoop); ClassRecord orig = ClassRecord.ofClassModel(cc.parse(fileBytes), ClassRecord.CompatibilityFilter.By_ClassBuilder); ClassRecord transformed = ClassRecord.ofClassModel(cc.parse(newClass), ClassRecord.CompatibilityFilter.By_ClassBuilder); ClassRecord.assertEqualsDeep(transformed, orig); diff --git a/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java b/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java index 423ea91802aa3..067bce8b75fb3 100644 --- a/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java +++ b/test/jdk/jdk/classfile/MassAdaptCopyCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ void copy(String name, byte[] bytes) throws Exception { } public byte[] adaptCopy(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { diff --git a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java index 0ac9de70472ca..67e20be0ad3ee 100644 --- a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java +++ b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,7 @@ void copy(String name, byte[] bytes) throws Exception { Map m2b = new HashMap<>(); Map m2c = new HashMap<>(); byte[] resultBytes = - cc.transform(cm, (cb, e) -> { + cc.transformClass(cm, (cb, e) -> { if (e instanceof MethodModel mm) { Optional code = mm.code(); if (code.isPresent()) { diff --git a/test/jdk/jdk/classfile/OptionsTest.java b/test/jdk/jdk/classfile/OptionsTest.java index eecc2d7a3853e..10e3855b06085 100644 --- a/test/jdk/jdk/classfile/OptionsTest.java +++ b/test/jdk/jdk/classfile/OptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ static Path[] corpus() throws IOException, URISyntaxException { @MethodSource("corpus") void testAttributesProcessingOptionOnTransform(Path path) throws Exception { testNoUnstable(path, ClassFile.of().parse( - ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNSTABLE_ATRIBUTES).transform( + ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNSTABLE_ATRIBUTES).transformClass( ClassFile.of().parse(path), ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL)))); } @@ -108,7 +108,7 @@ void testUnknownAttribute() throws Exception { //test drop unknown at transform assertTrue(ClassFile.of().parse( - ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNKNOWN_ATTRIBUTES).transform( + ClassFile.of(ClassFile.AttributesProcessingOption.DROP_UNKNOWN_ATTRIBUTES).transformClass( ClassFile.of().parse(classBytes), ClassTransform.ACCEPT_ALL)).attributes().isEmpty()); } diff --git a/test/jdk/jdk/classfile/ShortJumpsFixTest.java b/test/jdk/jdk/classfile/ShortJumpsFixTest.java index a259795b5519d..63e9f0bf90452 100644 --- a/test/jdk/jdk/classfile/ShortJumpsFixTest.java +++ b/test/jdk/jdk/classfile/ShortJumpsFixTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,7 +136,7 @@ void testFailBackJumpsDirectGen(Sample sample) throws Exception { @MethodSource("provideFwd") void testFixFwdJumpsTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -145,7 +145,7 @@ void testFixFwdJumpsTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFixBackJumpsTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -154,7 +154,7 @@ void testFixBackJumpsTransform(Sample sample) throws Exception { @MethodSource("provideFwd") void testFailFwdJumpsTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -163,7 +163,7 @@ void testFailFwdJumpsTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFailBackJumpsTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), overflow())); } @@ -172,7 +172,7 @@ void testFailBackJumpsTransform(Sample sample) throws Exception { @MethodSource("provideFwd") void testFixFwdJumpsChainedTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } @@ -181,7 +181,7 @@ void testFixFwdJumpsChainedTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFixBackJumpsChainedTransform(Sample sample) throws Exception { assertFixed(sample, - CC_Fixed_Jumps.transform( + CC_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } @@ -190,7 +190,7 @@ void testFixBackJumpsChainedTransform(Sample sample) throws Exception { @MethodSource("provideFwd") void testFailFwdJumpsChainedTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateFwd(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } @@ -199,7 +199,7 @@ void testFailFwdJumpsChainedTransform(Sample sample) throws Exception { @MethodSource("provideBack") void testFailBackJumpsChainedTransform(Sample sample) throws Exception { assertThrows(IllegalArgumentException.class, () -> - CC_Not_Fixed_Jumps.transform( + CC_Not_Fixed_Jumps.transformClass( generateBack(CC_No_Stack_No_Patch, sample, false), ClassTransform.ACCEPT_ALL.andThen(overflow()))); //involve BufferedCodeBuilder here } diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index f72c237aa8ff3..137f5bac48613 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -225,7 +225,7 @@ void testClassVersions() throws Exception { var actualVersion = cc.parse(StackMapsTest.class.getResourceAsStream("/testdata/Pattern1.class").readAllBytes()); //test transformation to class version 49 with removal of StackMapTable attributes - var version49 = cc.parse(cc.transform( + var version49 = cc.parse(cc.transformClass( actualVersion, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(49, 0))))); @@ -233,7 +233,7 @@ void testClassVersions() throws Exception { .walk().anyMatch(n -> n.name().equals("stack map frames"))); //test transformation to class version 50 with re-generation of StackMapTable attributes - assertEmpty(cc.verify(cc.transform( + assertEmpty(cc.verify(cc.transformClass( version49, ClassTransform.transformingMethodBodies(CodeTransform.ACCEPT_ALL) .andThen(ClassTransform.endHandler(clb -> clb.withVersion(50, 0)))))); diff --git a/test/jdk/jdk/classfile/TestRecordComponent.java b/test/jdk/jdk/classfile/TestRecordComponent.java index 95d56ffae8d08..b39029154a022 100644 --- a/test/jdk/jdk/classfile/TestRecordComponent.java +++ b/test/jdk/jdk/classfile/TestRecordComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ void testAdapt() throws Exception { } else cb.with(ce); }; - ClassModel newModel = cc.parse(cc.transform(cm, xform)); + ClassModel newModel = cc.parse(cc.transformClass(cm, xform)); ClassRecord.assertEquals(newModel, cm); } @@ -74,7 +74,7 @@ void testPassThrough() throws Exception { var cc = ClassFile.of(); ClassModel cm = cc.parse(Files.readAllBytes(testClassPath)); ClassTransform xform = (cb, ce) -> cb.with(ce); - ClassModel newModel = cc.parse(cc.transform(cm, xform)); + ClassModel newModel = cc.parse(cc.transformClass(cm, xform)); ClassRecord.assertEquals(newModel, cm); } @@ -92,7 +92,7 @@ void testChagne() throws Exception { else cb.with(ce); }; - ClassModel newModel = cc.parse(cc.transform(cm, xform)); + ClassModel newModel = cc.parse(cc.transformClass(cm, xform)); RecordAttribute ra = newModel.findAttribute(Attributes.record()).orElseThrow(); assertEquals(ra.components().size(), 2, "Should have two components"); assertEquals(ra.components().get(0).name().stringValue(), "fooXYZ"); diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java index 13abca0ec5240..1df7b73bda56a 100644 --- a/test/jdk/jdk/classfile/TransformTests.java +++ b/test/jdk/jdk/classfile/TransformTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,8 +97,8 @@ void testSingleTransform() throws Exception { ClassModel cm = cc.parse(bytes); assertEquals(invoke(bytes), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2foo))), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2bar))), "bar"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2foo))), "foo"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2bar))), "bar"); } @Test @@ -110,7 +110,7 @@ void testSeq2() throws Exception { assertEquals(invoke(bytes), "foo"); ClassTransform transform = transformCode(foo2bar.andThen(bar2baz)); - assertEquals(invoke(cc.transform(cm, transform)), "baz"); + assertEquals(invoke(cc.transformClass(cm, transform)), "baz"); } @Test @@ -121,9 +121,9 @@ void testSeqN() throws Exception { ClassModel cm = cc.parse(bytes); assertEquals(invoke(bytes), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2foo)))), "foo"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2quux)))), "quux"); - assertEquals(invoke(cc.transform(cm, transformCode(foo2foo.andThen(foo2bar).andThen(bar2baz)))), "baz"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2foo)))), "foo"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2bar.andThen(bar2baz).andThen(baz2quux)))), "quux"); + assertEquals(invoke(cc.transformClass(cm, transformCode(foo2foo.andThen(foo2bar).andThen(bar2baz)))), "baz"); } public static class TestClass { diff --git a/test/jdk/jdk/classfile/VerifierSelfTest.java b/test/jdk/jdk/classfile/VerifierSelfTest.java index ef1bc3cab30ec..529edbf2b7961 100644 --- a/test/jdk/jdk/classfile/VerifierSelfTest.java +++ b/test/jdk/jdk/classfile/VerifierSelfTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void testFailed() throws IOException { var cc = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of( className -> ClassHierarchyResolver.ClassHierarchyInfo.ofClass(null))); var classModel = cc.parse(path); - byte[] brokenClassBytes = cc.transform(classModel, + byte[] brokenClassBytes = cc.transformClass(classModel, (clb, cle) -> { if (cle instanceof MethodModel mm) { clb.transformMethod(mm, (mb, me) -> { diff --git a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java index 846645d93a941..a43ab72556e9f 100644 --- a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java +++ b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ public class AnnotationsExamples { public byte[] addAnno(ClassModel m) { // @@@ Not correct List annos = List.of(Annotation.of(ClassDesc.of("java.lang.FunctionalInterface"))); - return ClassFile.of().transform(m, ClassTransform.endHandler(cb -> cb.with(RuntimeVisibleAnnotationsAttribute.of(annos)))); + return ClassFile.of().transformClass(m, ClassTransform.endHandler(cb -> cb.with(RuntimeVisibleAnnotationsAttribute.of(annos)))); } /** @@ -75,7 +75,7 @@ public void swapAnnotation(ClassModel m) { var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/annotation/Documented;")) { - m2 = cc.parse(cc.transform(m, SWAP_ANNO_TRANSFORM)); + m2 = cc.parse(cc.transformClass(m, SWAP_ANNO_TRANSFORM)); } } } @@ -119,7 +119,7 @@ public void addAnnotation(ClassModel m) { var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/FunctionalInterface;")) { - m2 = cc.parse(cc.transform(m, (cb, ce) -> { + m2 = cc.parse(cc.transformClass(m, (cb, ce) -> { if (ce instanceof RuntimeVisibleAnnotationsAttribute ra) { var oldAnnos = ra.annotations(); List newAnnos = new ArrayList<>(oldAnnos.size() + 1); @@ -145,7 +145,7 @@ public void addAnnotation(ClassModel m) { } public byte[] viaEndHandlerClassBuilderEdition(ClassModel m) { - return ClassFile.of().transform(m, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(m, ClassTransform.ofStateful(() -> new ClassTransform() { boolean found = false; @Override @@ -172,7 +172,7 @@ public void atEnd(ClassBuilder builder) { } public byte[] viaEndHandlerClassTransformEdition(ClassModel m) { - return ClassFile.of().transform(m, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(m, ClassTransform.ofStateful(() -> new ClassTransform() { boolean found = false; @Override diff --git a/test/jdk/jdk/classfile/examples/ExampleGallery.java b/test/jdk/jdk/classfile/examples/ExampleGallery.java index 736725eeebe84..7de4a78ffbf86 100644 --- a/test/jdk/jdk/classfile/examples/ExampleGallery.java +++ b/test/jdk/jdk/classfile/examples/ExampleGallery.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ */ public class ExampleGallery { public byte[] changeClassVersion(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case ClassFileVersion cv -> cb.withVersion(57, 0); default -> cb.with(ce); @@ -71,7 +71,7 @@ public byte[] changeClassVersion(ClassModel cm) { } public byte[] incrementClassVersion(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case ClassFileVersion cv -> cb.withVersion(cv.majorVersion() + 1, 0); default -> cb.with(ce); @@ -80,7 +80,7 @@ public byte[] incrementClassVersion(ClassModel cm) { } public byte[] changeSuperclass(ClassModel cm, ClassDesc superclass) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case Superclass sc -> cb.withSuperclass(superclass); default -> cb.with(ce); @@ -89,11 +89,11 @@ public byte[] changeSuperclass(ClassModel cm, ClassDesc superclass) { } public byte[] overrideSuperclass(ClassModel cm, ClassDesc superclass) { - return ClassFile.of().transform(cm, ClassTransform.endHandler(cb -> cb.withSuperclass(superclass))); + return ClassFile.of().transformClass(cm, ClassTransform.endHandler(cb -> cb.withSuperclass(superclass))); } public byte[] removeInterface(ClassModel cm, String internalName) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case Interfaces i -> cb.withInterfaces(i.interfaces().stream() .filter(e -> !e.asInternalName().equals(internalName)) @@ -104,7 +104,7 @@ public byte[] removeInterface(ClassModel cm, String internalName) { } public byte[] addInterface(ClassModel cm, ClassDesc newIntf) { - return ClassFile.of().transform(cm, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(cm, ClassTransform.ofStateful(() -> new ClassTransform() { boolean seen = false; @Override @@ -133,7 +133,7 @@ public void atEnd(ClassBuilder builder) { } public byte[] addInterface1(ClassModel cm, ClassDesc newIntf) { - return ClassFile.of().transform(cm, ClassTransform.ofStateful(() -> new ClassTransform() { + return ClassFile.of().transformClass(cm, ClassTransform.ofStateful(() -> new ClassTransform() { Interfaces interfaces; @Override @@ -160,11 +160,11 @@ public void atEnd(ClassBuilder builder) { } public byte[] removeSignature(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute)); + return ClassFile.of().transformClass(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute)); } public byte[] changeSignature(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case SignatureAttribute sa -> { String result = sa.signature().stringValue(); @@ -176,7 +176,7 @@ public byte[] changeSignature(ClassModel cm) { } public byte[] setSignature(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute) + return ClassFile.of().transformClass(cm, ClassTransform.dropping(e -> e instanceof SignatureAttribute) .andThen(ClassTransform.endHandler(b -> b.with(SignatureAttribute.of( ClassSignature.of( ClassTypeSig.of(ClassDesc.of("impl.Fox"), @@ -187,16 +187,16 @@ public byte[] setSignature(ClassModel cm) { // @@@ strip annos (class, all) public byte[] stripFields(ClassModel cm, Predicate filter) { - return ClassFile.of().transform(cm, ClassTransform.dropping(e -> e instanceof FieldModel fm + return ClassFile.of().transformClass(cm, ClassTransform.dropping(e -> e instanceof FieldModel fm && filter.test(fm.fieldName().stringValue()))); } public byte[] addField(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.endHandler(cb -> cb.withField("cool", ClassDesc.ofDescriptor("(I)D"), ClassFile.ACC_PUBLIC))); + return ClassFile.of().transformClass(cm, ClassTransform.endHandler(cb -> cb.withField("cool", ClassDesc.ofDescriptor("(I)D"), ClassFile.ACC_PUBLIC))); } public byte[] changeFieldSig(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingFields((fb, fe) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingFields((fb, fe) -> { if (fe instanceof SignatureAttribute sa) fb.with(SignatureAttribute.of(Signature.parseFrom(sa.signature().stringValue().replace("this/", "that/")))); else @@ -205,7 +205,7 @@ public byte[] changeFieldSig(ClassModel cm) { } public byte[] changeFieldFlags(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingFields((fb, fe) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingFields((fb, fe) -> { switch (fe) { case AccessFlags a -> fb.with(AccessFlags.ofField(a.flagsMask() & ~ClassFile.ACC_PUBLIC & ~ClassFile.ACC_PROTECTED)); default -> fb.with(fe); @@ -214,7 +214,7 @@ public byte[] changeFieldFlags(ClassModel cm) { } public byte[] addException(ClassModel cm, ClassDesc ex) { - return ClassFile.of().transform(cm, ClassTransform.transformingMethods( + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethods( MethodTransform.ofStateful(() -> new MethodTransform() { ExceptionsAttribute attr; @@ -258,11 +258,11 @@ public void accept(CodeBuilder codeB, CodeElement codeE) { } }); - return ClassFile.of().transform(cm, ClassTransform.transformingMethodBodies(transform)); + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethodBodies(transform)); } public byte[] addInstrumentationBeforeInvoke(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { switch (codeE) { case InvokeInstruction i -> { codeB.nop(); @@ -274,7 +274,7 @@ public byte[] addInstrumentationBeforeInvoke(ClassModel cm) { } public byte[] replaceIntegerConstant(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { + return ClassFile.of().transformClass(cm, ClassTransform.transformingMethodBodies((codeB, codeE) -> { switch (codeE) { case ConstantInstruction ci -> { if (ci.constantValue() instanceof Integer i) codeB.loadConstant(i + 1); diff --git a/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java b/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java index d66cc6737daf1..c0bfceff16f47 100644 --- a/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java +++ b/test/jdk/jdk/classfile/examples/ExperimentalTransformExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ public class ExperimentalTransformExamples { }; public byte[] deleteAnnotations(ClassModel cm) { - return ClassFile.of().transform(cm, (cb, ce) -> { + return ClassFile.of().transformClass(cm, (cb, ce) -> { switch (ce) { case MethodModel m -> cb.transformMethod(m, dropMethodAnnos); case FieldModel f -> cb.transformField(f, dropFieldAnnos); diff --git a/test/jdk/jdk/classfile/examples/TransformExamples.java b/test/jdk/jdk/classfile/examples/TransformExamples.java index 97dfcd8a58582..2473e024e70ab 100644 --- a/test/jdk/jdk/classfile/examples/TransformExamples.java +++ b/test/jdk/jdk/classfile/examples/TransformExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,18 +38,18 @@ */ public class TransformExamples { public byte[] noop(ClassModel cm) { - return ClassFile.of().transform(cm, ClassTransform.ACCEPT_ALL); + return ClassFile.of().transformClass(cm, ClassTransform.ACCEPT_ALL); } public byte[] deleteAllMethods(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> { + return ClassFile.of().transformClass(cm, (b, e) -> { if (!(e instanceof MethodModel)) b.with(e); }); } public byte[] deleteFieldsWithDollarInName(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> + return ClassFile.of().transformClass(cm, (b, e) -> { if (!(e instanceof FieldModel fm && fm.fieldName().stringValue().contains("$"))) b.with(e); @@ -57,14 +57,14 @@ public byte[] deleteFieldsWithDollarInName(ClassModel cm) { } public byte[] deleteAttributes(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> { + return ClassFile.of().transformClass(cm, (b, e) -> { if (!(e instanceof Attribute)) b.with(e); }); } public byte[] keepMethodsAndFields(ClassModel cm) { - return ClassFile.of().transform(cm, (b, e) -> { + return ClassFile.of().transformClass(cm, (b, e) -> { if (e instanceof MethodModel || e instanceof FieldModel) b.with(e); }); diff --git a/test/jdk/jdk/classfile/helpers/Transforms.java b/test/jdk/jdk/classfile/helpers/Transforms.java index 64b4836d50ad5..0b44c5a22aa48 100644 --- a/test/jdk/jdk/classfile/helpers/Transforms.java +++ b/test/jdk/jdk/classfile/helpers/Transforms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,7 +187,7 @@ public enum NoOpTransform { shared ? options : Stream.concat(Stream.of(options), Stream.of(ClassFile.ConstantPoolSharingOption.NEW_POOL)).toArray(ClassFile.Option[]::new)); - this.transform = bytes -> cc.transform(cc.parse(bytes), classTransform); + this.transform = bytes -> cc.transformClass(cc.parse(bytes), classTransform); } public Optional classRecord(byte[] bytes) throws IOException { @@ -212,7 +212,7 @@ public enum InjectNopTransform { NOP_SHARED(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (cb, ce) -> { + return cc.transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { @@ -253,7 +253,7 @@ public enum SimpleTransform { HIGH_SHARED_ADD_FIELD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, new ClassTransform() { + return cc.transformClass(cm, new ClassTransform() { @Override public void accept(ClassBuilder builder, ClassElement element) { builder.with(element); @@ -291,7 +291,7 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str HIGH_SHARED_DEL_METHOD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (builder, element) -> { + return cc.transformClass(cm, (builder, element) -> { if (!(element instanceof MethodModel mm)) builder.with(element); }); diff --git a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java index 5f3885f31bf49..daa3d0162d4ce 100644 --- a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java +++ b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java @@ -317,7 +317,7 @@ public byte[] transform( instrClassesDone.add(target); var cf = ClassFile.of(); - return cf.transform(cf.parse(bytes), (clb, ce) -> { + return cf.transformClass(cf.parse(bytes), (clb, ce) -> { MethodKey key; if (ce instanceof MethodModel mm && instrMethodKeys.contains(key = new MethodKey( target, mm.methodName().stringValue(), mm.methodTypeSymbol()))) { diff --git a/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java b/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java index 8a8415dc524c0..049a1172d0c72 100644 --- a/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java +++ b/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java @@ -116,7 +116,7 @@ public byte[] transform(ClassLoader classLoader, String className, } var cf = ClassFile.of(); - result = cf.transform(cf.parse(bytes), (clb, ce) -> { + result = cf.transformClass(cf.parse(bytes), (clb, ce) -> { if (ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) { clb.transformMethod(mm, MethodTransform.transformingCode(new CodeTransform() { @Override diff --git a/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java b/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java index 26c1790128140..7bf9b19390e08 100644 --- a/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java +++ b/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +50,7 @@ private byte[] convertToInterface(ClassModel classModel) { } }; - return ClassFile.of().transform(classModel, + return ClassFile.of().transformClass(classModel, ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) .andThen(ClassTransform.transformingMethodBodies(ct)) .andThen(ClassTransform.endHandler(b -> b.withFlags(ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC))) diff --git a/test/langtools/tools/javac/MethodParametersTest.java b/test/langtools/tools/javac/MethodParametersTest.java index 8ce73671d1fd6..a4d55525e60c5 100644 --- a/test/langtools/tools/javac/MethodParametersTest.java +++ b/test/langtools/tools/javac/MethodParametersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,7 @@ void modifyBaz(boolean flip) throws Exception { // Alter the MethodParameters attribute, changing the name of // the parameter from i to baz. - byte[] bazBytes = ClassFile.of().transform(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { + byte[] bazBytes = ClassFile.of().transformClass(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { if (methodElement instanceof MethodParametersAttribute a) { List newParameterInfos = new ArrayList<>(); for (MethodParameterInfo info : a.parameters()) { @@ -200,7 +200,7 @@ void modifyBaz(boolean flip) throws Exception { // Flip the code and method attributes(). This is for checking // that order doesn't matter. if (flip) { - bazBytes = ClassFile.of().transform(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { + bazBytes = ClassFile.of().transformClass(baz, ClassTransform.transformingMethods((methodBuilder, methodElement) -> { if (methodElement instanceof MethodParametersAttribute) { methodBuilder.with(cattr); } else if (methodElement instanceof CodeAttribute){ diff --git a/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java b/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java index b4230c461c1a4..a44adbf6d9e71 100644 --- a/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java +++ b/test/langtools/tools/javac/classreader/8171132/BadConstantValue.java @@ -1,5 +1,6 @@ /* * Copyright 2016 Google, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +185,7 @@ private static void swapConstantValues(File file) throws Exception { ClassModel cf = ClassFile.of().parse(file.toPath()); FieldModel a = cf.fields().getFirst(); FieldModel b = cf.fields().get(1); - byte[] Bytes = ClassFile.of().transform(cf, ClassTransform + byte[] Bytes = ClassFile.of().transformClass(cf, ClassTransform .dropping(ce -> ce instanceof ClassFileVersion || ce instanceof FieldModel) .andThen(ClassTransform.endHandler(classBuilder -> classBuilder .withField(b.fieldName(), b.fieldType(), fieldBuilder -> { diff --git a/test/langtools/tools/javac/classreader/BadMethodParameter.java b/test/langtools/tools/javac/classreader/BadMethodParameter.java index b37a196e2ed90..cddd3f2495630 100644 --- a/test/langtools/tools/javac/classreader/BadMethodParameter.java +++ b/test/langtools/tools/javac/classreader/BadMethodParameter.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Alphabet LLC. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +149,7 @@ private static void transform(Path path) throws IOException { }; ClassTransform classTransform = ClassTransform.transformingMethods(methodTransform); - bytes = cf.transform(classModel, classTransform); + bytes = cf.transformClass(classModel, classTransform); Files.write(path, bytes); } } diff --git a/test/langtools/tools/javac/defaultMethods/BadClassfile.java b/test/langtools/tools/javac/defaultMethods/BadClassfile.java index 366692f17e3c4..589b65bcf66e5 100644 --- a/test/langtools/tools/javac/defaultMethods/BadClassfile.java +++ b/test/langtools/tools/javac/defaultMethods/BadClassfile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ public static void main(String... args) throws Exception { private static void test(String classname, String expected) throws Exception { File classfile = new File(System.getProperty("test.classes", "."), classname + ".class"); ClassModel cf = ClassFile.of().parse(classfile.toPath()); - ClassFile.of().transform(cf, ClassTransform.dropping(ce -> ce instanceof ClassFileVersion) + ClassFile.of().transformClass(cf, ClassTransform.dropping(ce -> ce instanceof ClassFileVersion) .andThen(ClassTransform.endHandler(classBuilder -> classBuilder.withVersion(Target.JDK1_7.majorVersion, Target.JDK1_7.minorVersion)))); JavaCompiler c = ToolProvider.getSystemJavaCompiler(); JavacTaskImpl task = (JavacTaskImpl) c.getTask(null, null, null, Arrays.asList("-classpath", System.getProperty("test.classes", ".")), null, null); diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 5f558d421ff0f..5e70e84482d32 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -743,7 +743,7 @@ public void testNoDuplicateIncubatorWarning(Path base) throws Exception { private static void markModuleAsIncubator(Path moduleInfoFile) throws Exception { ClassModel cf = ClassFile.of().parse(moduleInfoFile); ModuleResolutionAttribute newAttr = ModuleResolutionAttribute.of(WARN_INCUBATING); - byte[] newBytes = ClassFile.of().transform(cf, + byte[] newBytes = ClassFile.of().transformClass(cf, ClassTransform.endHandler(classBuilder -> classBuilder.with(newAttr))); try (OutputStream out = Files.newOutputStream(moduleInfoFile)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/modules/IncubatingTest.java b/test/langtools/tools/javac/modules/IncubatingTest.java index 776023db5e521..ce9d372a2f669 100644 --- a/test/langtools/tools/javac/modules/IncubatingTest.java +++ b/test/langtools/tools/javac/modules/IncubatingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,7 +266,7 @@ private void copyJavaBase(Path targetDir) throws IOException { private void addModuleResolutionAttribute(Path classfile, int resolution_flags) throws Exception { ClassModel cm = ClassFile.of().parse(classfile); ModuleResolutionAttribute modRAttr = ModuleResolutionAttribute.of(resolution_flags); - byte[] newBytes = ClassFile.of().transform(cm, ClassTransform.dropping(ce -> ce instanceof ModuleResolutionAttribute). + byte[] newBytes = ClassFile.of().transformClass(cm, ClassTransform.dropping(ce -> ce instanceof ModuleResolutionAttribute). andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(modRAttr)))); try (OutputStream out = Files.newOutputStream(classfile)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/modules/JavaBaseTest.java b/test/langtools/tools/javac/modules/JavaBaseTest.java index 188bc4801e5cb..6d9f574705d0d 100644 --- a/test/langtools/tools/javac/modules/JavaBaseTest.java +++ b/test/langtools/tools/javac/modules/JavaBaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,7 @@ void createClass(Path base, List mods, String target) throws Exception { modAttr1.provides()); Path modInfo = base.resolve("test-modules").resolve("module-info.class"); Files.createDirectories(modInfo.getParent()); - byte[] newBytes = ClassFile.of().transform(cm1, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). + byte[] newBytes = ClassFile.of().transformClass(cm1, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(modAttr2)))); try (OutputStream out = Files.newOutputStream(modInfo)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/modules/OpenModulesTest.java b/test/langtools/tools/javac/modules/OpenModulesTest.java index e21601031e73c..f2bf1d00cc760 100644 --- a/test/langtools/tools/javac/modules/OpenModulesTest.java +++ b/test/langtools/tools/javac/modules/OpenModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -243,7 +243,7 @@ public void testNonZeroOpensInOpen(Path base) throws Exception { module.uses(), module.provides()); - byte[] newBytes = ClassFile.of().transform(cm, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). + byte[] newBytes = ClassFile.of().transformClass(cm, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute). andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(newModule)))); try (OutputStream out = Files.newOutputStream(miClass)) { out.write(newBytes); diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java index 3a4fd85e54ecb..c66cd08852a21 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java @@ -1070,7 +1070,7 @@ void testModuleMainClass() throws Exception { try { Path moduleInfo = classesDir.resolve("module-info.class"); byte[] newClassData = - cf.transform(cf.parse(moduleInfo), + cf.transformClass(cf.parse(moduleInfo), (builder, element) -> { builder.with(element); if (element instanceof ModuleAttribute) { @@ -1179,7 +1179,7 @@ void compileAndPack(Path output, Path outputFile, } ClassFile cf = ClassFile.of(); ClassModel cm = cf.parse(moduleInfo); - byte[] newData = cf.transform(cm, (builder, element) -> { + byte[] newData = cf.transformClass(cm, (builder, element) -> { builder.with(element); if (element instanceof ModuleAttribute) { builder.with(ModulePackagesAttribute.ofNames(packages.stream() diff --git a/test/langtools/tools/javac/processing/model/element/TestOrigin.java b/test/langtools/tools/javac/processing/model/element/TestOrigin.java index 1fae5374bea33..dee13cbbeb2e4 100644 --- a/test/langtools/tools/javac/processing/model/element/TestOrigin.java +++ b/test/langtools/tools/javac/processing/model/element/TestOrigin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -302,7 +302,7 @@ public void testModuleDirectives(Path base) throws Exception { newOpens, module.uses(), module.provides()); - byte[] newClassFileBytes = ClassFile.of().transform(cf, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute) + byte[] newClassFileBytes = ClassFile.of().transformClass(cf, ClassTransform.dropping(ce -> ce instanceof ModuleAttribute) .andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(newModule)))); try (OutputStream out = Files.newOutputStream(moduleInfo)) { out.write(newClassFileBytes); diff --git a/test/langtools/tools/javap/UndefinedAccessFlagTest.java b/test/langtools/tools/javap/UndefinedAccessFlagTest.java index bb531fa369c16..822c9e20f3533 100644 --- a/test/langtools/tools/javap/UndefinedAccessFlagTest.java +++ b/test/langtools/tools/javap/UndefinedAccessFlagTest.java @@ -70,7 +70,7 @@ void test(TestLocation location) throws Throwable { )) { cm = cf.parse(is.readAllBytes()); } - var bytes = cf.transform(cm, (cb, ce) -> { + var bytes = cf.transformClass(cm, (cb, ce) -> { switch (ce) { case AccessFlags flags when location == TestLocation.CLASS -> cb .withFlags(flags.flagsMask() | ACC_PRIVATE); diff --git a/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java b/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java index 99ef450851e9c..c74956755b04d 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/AdHocAdapt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +57,6 @@ public enum X { public void transform(Blackhole bh) { var cc = ClassFile.of(); for (byte[] bytes : classes) - bh.consume(cc.transform(cc.parse(bytes), transform.transform)); + bh.consume(cc.transformClass(cc.parse(bytes), transform.transform)); } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java b/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java index 05dd4b1758351..c07eff075c959 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ClassfileBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,18 +99,18 @@ private static void consume(CompoundElement parent) { @Benchmark @BenchmarkMode(Mode.Throughput) public void transformWithSharedCP(Blackhole bh) { - bh.consume(sharedCP.transform(benchModel, threeLevelNoop)); + bh.consume(sharedCP.transformClass(benchModel, threeLevelNoop)); } @Benchmark @BenchmarkMode(Mode.Throughput) public void transformWithNewCP(Blackhole bh) { - bh.consume(newCP.transform(benchModel, threeLevelNoop)); + bh.consume(newCP.transformClass(benchModel, threeLevelNoop)); } @Benchmark @BenchmarkMode(Mode.Throughput) public void transformWithAddedNOP(Blackhole bh) { - bh.consume(sharedCP.transform(benchModel, addNOP)); + bh.consume(sharedCP.transformClass(benchModel, addNOP)); } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java b/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java index ed5e0f150acdc..29c555c4a6081 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ParseOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public void transformNoDebug(Blackhole bh) { var cc = ClassFile.of(ClassFile.DebugElementsOption.DROP_DEBUG); for (byte[] aClass : classes) { ClassModel cm = cc.parse(aClass); - bh.consume(cc.transform(cm, threeLevelNoop)); + bh.consume(cc.transformClass(cm, threeLevelNoop)); } } @@ -52,7 +52,7 @@ public void transformNoStackmap(Blackhole bh) { var cc = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS); for (byte[] aClass : classes) { ClassModel cm = cc.parse(aClass); - bh.consume(cc.transform(cm, threeLevelNoop)); + bh.consume(cc.transformClass(cm, threeLevelNoop)); } } @@ -62,7 +62,7 @@ public void transformNoLineNumbers(Blackhole bh) { var cc = ClassFile.of(ClassFile.LineNumbersOption.DROP_LINE_NUMBERS); for (byte[] aClass : classes) { ClassModel cm = cc.parse(aClass); - bh.consume(cc.transform(cm, threeLevelNoop)); + bh.consume(cc.transformClass(cm, threeLevelNoop)); } } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java b/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java index d5e77c1a2a7e7..07deec0ae489a 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/RebuildMethodBodies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ public void unshared() { } private static void transform(ClassFile cc, ClassModel clm) { - cc.transform(clm, ClassTransform.transformingMethodBodies((cob, coe) -> { + cc.transformClass(clm, ClassTransform.transformingMethodBodies((cob, coe) -> { switch (coe) { case FieldInstruction i -> cob.fieldAccess(i.opcode(), i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); diff --git a/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java b/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java index def55b5f20c40..d49897dc9c2a0 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/Transforms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,7 @@ public enum NoOpTransform { shared ? options : Stream.concat(Stream.of(options), Stream.of(ClassFile.ConstantPoolSharingOption.NEW_POOL)).toArray(ClassFile.Option[]::new)); - this.transform = bytes -> cc.transform(cc.parse(bytes), classTransform); + this.transform = bytes -> cc.transformClass(cc.parse(bytes), classTransform); } } @@ -198,7 +198,7 @@ public enum InjectNopTransform { NOP_SHARED(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (cb, ce) -> { + return cc.transformClass(cm, (cb, ce) -> { if (ce instanceof MethodModel mm) { cb.transformMethod(mm, (mb, me) -> { if (me instanceof CodeModel xm) { @@ -239,7 +239,7 @@ public enum SimpleTransform { HIGH_SHARED_ADD_FIELD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, new ClassTransform() { + return cc.transformClass(cm, new ClassTransform() { @Override public void accept(ClassBuilder builder, ClassElement element) { builder.with(element); @@ -277,7 +277,7 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str HIGH_SHARED_DEL_METHOD(bytes -> { var cc = ClassFile.of(); ClassModel cm = cc.parse(bytes); - return cc.transform(cm, (builder, element) -> { + return cc.transformClass(cm, (builder, element) -> { if (!(element instanceof MethodModel mm)) builder.with(element); }); From 7bc8f9c150cbf457edf6144adba734ecd5ca5a0f Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 05:55:28 +0000 Subject: [PATCH 135/288] 8335589: Fix -Wzero-as-null-pointer-constant warnings in IdealLoopTree ctor Reviewed-by: thartmann --- src/hotspot/share/opto/loopnode.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 79faf9c931dd2..448c29b6976bb 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -607,7 +607,7 @@ class IdealLoopTree : public ResourceObj { bool _allow_optimizations; // Allow loop optimizations IdealLoopTree( PhaseIdealLoop* phase, Node *head, Node *tail ) - : _parent(0), _next(0), _child(0), + : _parent(nullptr), _next(nullptr), _child(nullptr), _head(head), _tail(tail), _phase(phase), _local_loop_unroll_limit(0), _local_loop_unroll_factor(0), From f3f90dc11a5cbc146a5ef8a73eadf4168373838d Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 05:57:49 +0000 Subject: [PATCH 136/288] 8335592: Fix -Wzero-as-null-pointer-constant warnings in RootNode ctor Reviewed-by: thartmann --- src/hotspot/share/opto/rootnode.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/rootnode.hpp b/src/hotspot/share/opto/rootnode.hpp index 40e812023c197..3838578b4dbbf 100644 --- a/src/hotspot/share/opto/rootnode.hpp +++ b/src/hotspot/share/opto/rootnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ // procedure start. class RootNode : public LoopNode { public: - RootNode( ) : LoopNode(0,0) { + RootNode( ) : LoopNode(nullptr, nullptr) { init_class_id(Class_Root); del_req(2); del_req(1); From 77a7078b82fd0cb3cfa13685072f04fdef33758b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 06:00:20 +0000 Subject: [PATCH 137/288] 8335593: Fix -Wzero-as-null-pointer-constant warning in Type_Array ctor Reviewed-by: thartmann --- src/hotspot/share/opto/phaseX.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 0025f4dca4695..7843bd39aeaab 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ class Type_Array : public AnyObj { const Type **_types; void grow( uint i ); // Grow array node to fit public: - Type_Array(Arena *a) : _a(a), _max(0), _types(0) {} + Type_Array(Arena *a) : _a(a), _max(0), _types(nullptr) {} const Type *operator[] ( uint i ) const // Lookup, or null for not mapped { return (i<_max) ? _types[i] : (Type*)nullptr; } const Type *fast_lookup(uint i) const{assert(i<_max,"oob");return _types[i];} From 4d2f73764bcd5ff62fbdb9d406d4180ae09613ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Wed, 3 Jul 2024 08:08:22 +0000 Subject: [PATCH 138/288] 8335357: Delete HotSpotJDKReflection.oopSizeOffset Reviewed-by: dnsimon --- .../classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java index 21c6fb3dc0e58..6ee925cd3a7b0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,9 +108,6 @@ boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) { return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed(); } - // This field is being kept around for compatibility with libgraal - @SuppressWarnings("unused") private long oopSizeOffset; - @Override ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) { java.lang.reflect.Parameter[] javaParameters = getMethod(javaMethod).getParameters(); From 6c84e9c8cb71aac103901c0d92fe6ae51aabff15 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Jul 2024 08:42:43 +0000 Subject: [PATCH 139/288] 8335544: Serial: Remove unused _should_allocate_from_space Reviewed-by: iwalulya --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 1 - src/hotspot/share/gc/serial/defNewGeneration.hpp | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 593977030cbf1..7729ea71f027b 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -229,7 +229,6 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, _promotion_failed(false), _preserved_marks_set(false /* in_c_heap */), _promo_failure_drain_in_progress(false), - _should_allocate_from_space(false), _string_dedup_requests() { MemRegion cmr((HeapWord*)_virtual_space.low(), diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 0cf2545421f72..d0af3114b303e 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -119,18 +119,6 @@ class DefNewGeneration: public Generation { size_t _max_eden_size; size_t _max_survivor_size; - // Allocation support - bool _should_allocate_from_space; - bool should_allocate_from_space() const { - return _should_allocate_from_space; - } - void clear_should_allocate_from_space() { - _should_allocate_from_space = false; - } - void set_should_allocate_from_space() { - _should_allocate_from_space = true; - } - // Tenuring void adjust_desired_tenuring_threshold(); From c06b75ff88babf57bdcd0919ea177ff363fd858b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 11:12:08 +0000 Subject: [PATCH 140/288] 8335591: Fix -Wzero-as-null-pointer-constant warnings in ConcurrentHashTable Reviewed-by: chagedorn --- .../share/utilities/concurrentHashTable.inline.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index a83b6dd8a58d0..78c7e148bbb3c 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -318,7 +318,7 @@ inline bool ConcurrentHashTable:: } else { return false; } - _invisible_epoch = 0; + _invisible_epoch = nullptr; _resize_lock_owner = locker; return true; } @@ -345,14 +345,14 @@ inline void ConcurrentHashTable:: } } while(true); _resize_lock_owner = locker; - _invisible_epoch = 0; + _invisible_epoch = nullptr; } template inline void ConcurrentHashTable:: unlock_resize_lock(Thread* locker) { - _invisible_epoch = 0; + _invisible_epoch = nullptr; assert(locker == _resize_lock_owner, "Not unlocked by locker."); _resize_lock_owner = nullptr; _resize_lock->unlock(); @@ -1016,7 +1016,7 @@ ConcurrentHashTable(size_t log2size, size_t log2size_limit, size_t grow_hint, bo : _context(context), _new_table(nullptr), _log2_size_limit(log2size_limit), _log2_start_size(log2size), _grow_hint(grow_hint), _size_limit_reached(false), _resize_lock_owner(nullptr), - _invisible_epoch(0) + _invisible_epoch(nullptr) { if (enable_statistics) { _stats_rate = new TableRateStatistics(); From 350f9c1947b0eab3ee233516ceefca1e25de9583 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 3 Jul 2024 11:36:14 +0000 Subject: [PATCH 141/288] 8322812: Manpage for jcmd is missing JFR.view command Reviewed-by: kevinw, mgronlun --- src/jdk.jcmd/share/man/jcmd.1 | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index 2befaf5a94993..1a8aefde06e8b 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -681,6 +681,55 @@ If no path is provided, the data from the recording is discarded. value) .RE .TP +\f[V]JFR.view\f[R] [\f[I]options\f[R]] +Display event data in predefined views. +.RS +.PP +Impact: Medium +.PP +\f[B]Note:\f[R] +.PP +The \f[I]options\f[R] must be specified using either \f[I]key\f[R] or +\f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +If no parameters are entered, then a list of available views are +displayed. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]cell-height\f[R]: (Optional) Maximum number of rows in a table +cell. +(INT, default value depends on the view) +.IP \[bu] 2 +\f[V]maxage\f[R]: (Optional) Length of time for the view to span. +(INT followed by \[aq]s\[aq] for seconds \[aq]m\[aq] for minutes or +\[aq]h\[aq] for hours, default value is 10m) +.IP \[bu] 2 +\f[V]maxsize\f[R]: (Optional) Maximum size for the view to span in bytes +if one of the following suffixes is not used: \[aq]m\[aq] or \[aq]M\[aq] +for megabytes OR \[aq]g\[aq] or \[aq]G\[aq] for gigabytes. +(STRING, default value is 32MB) +.IP \[bu] 2 +\f[V]truncate\f[R]: (Optional) Maximum number of rows in a table cell. +(INT, default value depends on the view) +.IP \[bu] 2 +\f[V]verbose\f[R]: (Optional) Displays the query that makes up the view. +(BOOLEAN, default value is false) +.IP \[bu] 2 +\f[V]width\f[R]: (Optional) The width of the view in characters. +(INT, default value depends on the view) +.PP +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[V]view\f[R]: Name of the view or event type to display. +Use \f[V]help JFR.view\f[R] to see a list of available views. +(STRING, no default value) +.PP +The view parameter can be an event type name. +Use \f[V]JFR.view types\f[R] to see a list. +To display all views, use \f[V]JFR.view all-views\f[R]. +To display all events, use \f[V]JFR.view all-events\f[R]. +.RE +.TP \f[V]JVMTI.agent_load\f[R] [\f[I]arguments\f[R]] Loads JVMTI native agent. .RS From 6db4c6a772df856fc3099c32a5b2c102a30d360c Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Wed, 3 Jul 2024 12:12:00 +0000 Subject: [PATCH 142/288] 8335536: Fix assertion failure in IdealGraphPrinter when append is true Reviewed-by: thartmann, chagedorn, tholenstein --- src/hotspot/share/opto/idealGraphPrinter.cpp | 30 +++++++++++++------- src/hotspot/share/opto/idealGraphPrinter.hpp | 3 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 8a9da980893b0..4b813252ff9cf 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -143,21 +143,24 @@ void IdealGraphPrinter::init(const char* file_name, bool use_multiple_files, boo _depth = 0; _current_method = nullptr; _network_stream = nullptr; + _append = append; if (file_name != nullptr) { - init_file_stream(file_name, use_multiple_files, append); + init_file_stream(file_name, use_multiple_files); } else { init_network_stream(); } _xml = new (mtCompiler) xmlStream(_output); - if (!append) { + if (!_append) { head(TOP_ELEMENT); } } // Destructor, close file or network stream IdealGraphPrinter::~IdealGraphPrinter() { - tail(TOP_ELEMENT); + if (!_append) { + tail(TOP_ELEMENT); + } // tty->print_cr("Walk time: %d", (int)_walk_time.milliseconds()); // tty->print_cr("Output time: %d", (int)_output_time.milliseconds()); @@ -860,10 +863,10 @@ void IdealGraphPrinter::print(const char *name, Node *node) { _xml->flush(); } -void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multiple_files, bool append) { +void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multiple_files) { ThreadCritical tc; if (use_multiple_files && _file_count != 0) { - assert(!append, "append should only be used for debugging with a single file"); + assert(!_append, "append should only be used for debugging with a single file"); ResourceMark rm; stringStream st; const char* dot = strrchr(file_name, '.'); @@ -875,10 +878,10 @@ void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multipl } _output = new (mtCompiler) fileStream(st.as_string(), "w"); } else { - _output = new (mtCompiler) fileStream(file_name, append ? "a" : "w"); + _output = new (mtCompiler) fileStream(file_name, _append ? "a" : "w"); } if (use_multiple_files) { - assert(!append, "append should only be used for debugging with a single file"); + assert(!_append, "append should only be used for debugging with a single file"); _file_count++; } } @@ -909,9 +912,16 @@ void IdealGraphPrinter::update_compiled_method(ciMethod* current_method) { assert(C != nullptr, "must already be set"); if (current_method != _current_method) { // If a different method, end the old and begin with the new one. - end_method(); - _current_method = nullptr; - begin_method(); + if (_append) { + // Do not call `end_method` if we are appending, just update `_current_method`, + // because `begin_method` is not called in the constructor in append mode. + _current_method = current_method; + } else { + // End the old method and begin a new one. + // Don't worry about `_current_method`, `end_method` will clear it. + end_method(); + begin_method(); + } } } diff --git a/src/hotspot/share/opto/idealGraphPrinter.hpp b/src/hotspot/share/opto/idealGraphPrinter.hpp index 11b0b6e5ea169..65d7f4b547384 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.hpp +++ b/src/hotspot/share/opto/idealGraphPrinter.hpp @@ -96,6 +96,7 @@ class IdealGraphPrinter : public CHeapObj { bool _traverse_outs; Compile *C; double _max_freq; + bool _append; void print_method(ciMethod* method, int bci, InlineTree* tree); void print_inline_tree(InlineTree* tree); @@ -118,7 +119,7 @@ class IdealGraphPrinter : public CHeapObj { void head(const char *name); void text(const char *s); void init(const char* file_name, bool use_multiple_files, bool append); - void init_file_stream(const char* file_name, bool use_multiple_files, bool append); + void init_file_stream(const char* file_name, bool use_multiple_files); void init_network_stream(); IdealGraphPrinter(); ~IdealGraphPrinter(); From 5866b16dbca3f63770c8792d204dabdf49b59839 Mon Sep 17 00:00:00 2001 From: Feilong Jiang Date: Wed, 3 Jul 2024 12:12:12 +0000 Subject: [PATCH 143/288] 8335411: RISC-V: Optimize encode_heap_oop when oop is not null Reviewed-by: fyang, rehn --- .../cpu/riscv/macroAssembler_riscv.cpp | 47 ++++++++++++++++++- .../cpu/riscv/macroAssembler_riscv.hpp | 4 +- src/hotspot/cpu/riscv/riscv.ad | 14 +++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b707b20f6692a..a04c02bbc45bd 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2664,6 +2664,51 @@ void MacroAssembler::encode_heap_oop(Register d, Register s) { } } +void MacroAssembler::encode_heap_oop_not_null(Register r) { +#ifdef ASSERT + if (CheckCompressedOops) { + Label ok; + bnez(r, ok); + stop("null oop passed to encode_heap_oop_not_null"); + bind(ok); + } +#endif + verify_oop_msg(r, "broken oop in encode_heap_oop_not_null"); + if (CompressedOops::base() != nullptr) { + sub(r, r, xheapbase); + } + if (CompressedOops::shift() != 0) { + assert(LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + srli(r, r, LogMinObjAlignmentInBytes); + } +} + +void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { +#ifdef ASSERT + if (CheckCompressedOops) { + Label ok; + bnez(src, ok); + stop("null oop passed to encode_heap_oop_not_null2"); + bind(ok); + } +#endif + verify_oop_msg(src, "broken oop in encode_heap_oop_not_null2"); + + Register data = src; + if (CompressedOops::base() != nullptr) { + sub(dst, src, xheapbase); + data = dst; + } + if (CompressedOops::shift() != 0) { + assert(LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + srli(dst, data, LogMinObjAlignmentInBytes); + data = dst; + } + if (data == src) { + mv(dst, src); + } +} + void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { assert_different_registers(dst, tmp); assert_different_registers(src, tmp); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index ddd3c48a93e10..ea2b9229eab47 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1,7 +1,7 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,8 @@ class MacroAssembler: public Assembler { void decode_heap_oop_not_null(Register dst, Register src); void decode_heap_oop(Register d, Register s); void decode_heap_oop(Register r) { decode_heap_oop(r, r); } + void encode_heap_oop_not_null(Register r); + void encode_heap_oop_not_null(Register dst, Register src); void encode_heap_oop(Register d, Register s); void encode_heap_oop(Register r) { encode_heap_oop(r, r); }; void load_heap_oop(Register dst, Address src, Register tmp1, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 4ed449032d6e9..e2a1fcf621fab 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1,7 +1,7 @@ // // Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. -// Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. +// Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -8404,6 +8404,7 @@ instruct round_float_reg(iRegINoSp dst, fRegF src, fRegF ftmp) %{ // Convert oop pointer into compressed form instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ + predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); match(Set dst (EncodeP src)); ins_cost(ALU_COST); format %{ "encode_heap_oop $dst, $src\t#@encodeHeapOop" %} @@ -8415,6 +8416,17 @@ instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ ins_pipe(pipe_class_default); %} +instruct encodeHeapOop_not_null(iRegNNoSp dst, iRegP src) %{ + predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); + match(Set dst (EncodeP src)); + ins_cost(ALU_COST); + format %{ "encode_heap_oop_not_null $dst, $src\t#@encodeHeapOop_not_null" %} + ins_encode %{ + __ encode_heap_oop_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(pipe_class_default); +%} + instruct decodeHeapOop(iRegPNoSp dst, iRegN src) %{ predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); From 6923a5114b2a9f02f0d6f0fefc21141ac3b9322a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Jul 2024 12:57:26 +0000 Subject: [PATCH 144/288] 8335607: Serial: Remove unused collection_attempt_is_safe Reviewed-by: tschatzl --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 11 ----------- src/hotspot/share/gc/serial/defNewGeneration.hpp | 7 ------- 2 files changed, 18 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 7729ea71f027b..acf7e23910367 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -834,17 +834,6 @@ void DefNewGeneration::reset_scratch() { } } -bool DefNewGeneration::collection_attempt_is_safe() { - if (!to()->is_empty()) { - log_trace(gc)(":: to is not empty ::"); - return false; - } - if (_old_gen == nullptr) { - _old_gen = SerialHeap::heap()->old_gen(); - } - return _old_gen->promotion_attempt_is_safe(used()); -} - void DefNewGeneration::gc_epilogue(bool full) { assert(!GCLocker::is_active(), "We should not be executing here"); // update the generation and space performance counters diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index d0af3114b303e..5c8dd08e40b82 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -228,13 +228,6 @@ class DefNewGeneration: public Generation { // GC support void compute_new_size(); - // Returns true if the collection is likely to be safely - // completed. Even if this method returns true, a collection - // may not be guaranteed to succeed, and the system should be - // able to safely unwind and recover from that failure, albeit - // at some additional cost. - bool collection_attempt_is_safe(); - bool collect(bool clear_all_soft_refs); HeapWord* expand_and_allocate(size_t size, bool is_tlab); From 5a8af2b8b93672de9b3a3e73e6984506980da932 Mon Sep 17 00:00:00 2001 From: Arseny Bochkarev Date: Wed, 3 Jul 2024 14:09:59 +0000 Subject: [PATCH 145/288] 8335615: Clean up left-overs from 8317721 Reviewed-by: fyang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a04c02bbc45bd..b3ae5fbcdd02b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1494,10 +1494,9 @@ void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp1, xorr(crc, crc, tmp2); lwu(tmp2, Address(tmp3)); - if (upper) { - tmp1 = v; + // It is more optimal to use 'srli' instead of 'srliw' for case when it is not necessary to clean upper bits + if (upper) srli(tmp1, v, 24); - } else srliw(tmp1, v, 24); From cf4f2b53d6174a808f8b45f0bb848efd5bd91c3c Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 3 Jul 2024 15:12:40 +0000 Subject: [PATCH 146/288] 8332517: G1: Refactor G1AllocRegion Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1AllocRegion.cpp | 46 +++++------ src/hotspot/share/gc/g1/g1AllocRegion.hpp | 56 +++++-------- .../share/gc/g1/g1AllocRegion.inline.hpp | 38 +++------ src/hotspot/share/gc/g1/g1Allocator.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 22 +++-- .../share/gc/g1/g1HeapRegion.inline.hpp | 82 ++++++++----------- 6 files changed, 99 insertions(+), 147 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index a205cf71ee673..c4ab81cda8fc4 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -100,16 +100,13 @@ size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up) // it will never be empty. size_t waste = 0; assert_alloc_region(!alloc_region->is_empty(), - "the alloc region should never be empty"); + "the alloc region should never be empty"); if (fill_up) { waste = fill_up_remaining_space(alloc_region); } - assert_alloc_region(alloc_region->used() >= _used_bytes_before, "invariant"); - size_t allocated_bytes = alloc_region->used() - _used_bytes_before; - retire_region(alloc_region, allocated_bytes); - _used_bytes_before = 0; + retire_region(alloc_region); return waste; } @@ -132,15 +129,14 @@ size_t G1AllocRegion::retire(bool fill_up) { HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { assert_alloc_region(_alloc_region == _dummy_region, "pre-condition"); - assert_alloc_region(_used_bytes_before == 0, "pre-condition"); trace("attempting region allocation"); G1HeapRegion* new_alloc_region = allocate_new_region(word_size); if (new_alloc_region != nullptr) { new_alloc_region->reset_pre_dummy_top(); - // Need to do this before the allocation - _used_bytes_before = new_alloc_region->used(); - HeapWord* result = allocate(new_alloc_region, word_size); + + assert(new_alloc_region->is_empty(), "new regions should be empty"); + HeapWord* result = new_alloc_region->allocate(word_size); assert_alloc_region(result != nullptr, "the allocation should succeeded"); OrderAccess::storestore(); @@ -159,7 +155,7 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { void G1AllocRegion::init() { trace("initializing"); - assert_alloc_region(_alloc_region == nullptr && _used_bytes_before == 0, "pre-condition"); + assert_alloc_region(_alloc_region == nullptr, "pre-condition"); assert_alloc_region(_dummy_region != nullptr, "should have been set"); _alloc_region = _dummy_region; _count = 0; @@ -168,16 +164,9 @@ void G1AllocRegion::init() { void G1AllocRegion::set(G1HeapRegion* alloc_region) { trace("setting"); - // We explicitly check that the region is not empty to make sure we - // maintain the "the alloc region cannot be empty" invariant. - assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "pre-condition"); - assert_alloc_region(_alloc_region == _dummy_region && - _used_bytes_before == 0 && _count == 0, - "pre-condition"); + assert_alloc_region(_alloc_region == _dummy_region && _count == 0, "pre-condition"); - _used_bytes_before = alloc_region->used(); - _alloc_region = alloc_region; - _count += 1; + update_alloc_region(alloc_region); trace("set"); } @@ -237,7 +226,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_ if (detailed_info) { if (result != nullptr) { out->print(" min " SIZE_FORMAT " desired " SIZE_FORMAT " actual " SIZE_FORMAT " " PTR_FORMAT, - min_word_size, desired_word_size, actual_word_size, p2i(result)); + min_word_size, desired_word_size, actual_word_size, p2i(result)); } else if (min_word_size != 0) { out->print(" min " SIZE_FORMAT " desired " SIZE_FORMAT, min_word_size, desired_word_size); } @@ -252,7 +241,6 @@ G1AllocRegion::G1AllocRegion(const char* name, uint node_index) : _alloc_region(nullptr), _count(0), - _used_bytes_before(0), _name(name), _node_index(node_index) { } @@ -261,9 +249,8 @@ G1HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size) { return _g1h->new_mutator_alloc_region(word_size, _node_index); } -void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region, - size_t allocated_bytes) { - _g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes); +void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region) { + _g1h->retire_mutator_alloc_region(alloc_region, alloc_region->used()); } void MutatorAllocRegion::init() { @@ -346,9 +333,11 @@ G1HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size) { return _g1h->new_gc_alloc_region(word_size, _purpose, _node_index); } -void G1GCAllocRegion::retire_region(G1HeapRegion* alloc_region, - size_t allocated_bytes) { +void G1GCAllocRegion::retire_region(G1HeapRegion* alloc_region) { + assert(alloc_region->used() >= _used_bytes_before, "invariant"); + size_t allocated_bytes = alloc_region->used() - _used_bytes_before; _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, _purpose); + _used_bytes_before = 0; } size_t G1GCAllocRegion::retire(bool fill_up) { @@ -360,3 +349,8 @@ size_t G1GCAllocRegion::retire(bool fill_up) { } return end_waste; } + +void G1GCAllocRegion::reuse(G1HeapRegion* alloc_region) { + _used_bytes_before = alloc_region->used(); + set(alloc_region); +} diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index a8903fd54f148..391ded283885f 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -63,11 +63,6 @@ class G1AllocRegion : public CHeapObj { // distinct regions this object can used during an active interval. uint _count; - // When we set up a new active region we save its used bytes in this - // field so that, when we retire it, we can calculate how much space - // we allocated in it. - size_t _used_bytes_before; - // Useful for debugging and tracing. const char* _name; @@ -94,24 +89,14 @@ class G1AllocRegion : public CHeapObj { // The memory node index this allocation region belongs to. uint _node_index; + void set(G1HeapRegion* alloc_region); + // Reset the alloc region to point the dummy region. void reset_alloc_region(); - // Perform a non-MT-safe allocation out of the given region. - inline HeapWord* allocate(G1HeapRegion* alloc_region, - size_t word_size); - // Perform a MT-safe allocation out of the given region. inline HeapWord* par_allocate(G1HeapRegion* alloc_region, size_t word_size); - // Perform a MT-safe allocation out of the given region, with the given - // minimum and desired size. Returns the actual size allocated (between - // minimum and desired size) in actual_word_size if the allocation has been - // successful. - inline HeapWord* par_allocate(G1HeapRegion* alloc_region, - size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size); // Ensure that the region passed as a parameter has been filled up // so that no one else can allocate out of it any more. @@ -131,8 +116,7 @@ class G1AllocRegion : public CHeapObj { static G1CollectedHeap* _g1h; virtual G1HeapRegion* allocate_new_region(size_t word_size) = 0; - virtual void retire_region(G1HeapRegion* alloc_region, - size_t allocated_bytes) = 0; + virtual void retire_region(G1HeapRegion* alloc_region) = 0; G1AllocRegion(const char* name, bool bot_updates, uint node_index); @@ -173,12 +157,6 @@ class G1AllocRegion : public CHeapObj { // Should be called before we start using this object. virtual void init(); - // This can be used to set the active region to a specific - // region. (Use Example: we try to retain the last old GC alloc - // region that we've used during a GC and we can use set() to - // re-instate it at the beginning of the next GC.) - void set(G1HeapRegion* alloc_region); - // Should be called when we want to release the active region which // is returned after it's been retired. virtual G1HeapRegion* release(); @@ -205,10 +183,9 @@ class MutatorAllocRegion : public G1AllocRegion { // in it and the free size in the currently retained region, if any. bool should_retain(G1HeapRegion* region); protected: - virtual G1HeapRegion* allocate_new_region(size_t word_size); - virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes); - virtual size_t retire(bool fill_up); - + G1HeapRegion* allocate_new_region(size_t word_size) override; + void retire_region(G1HeapRegion* alloc_region) override; + size_t retire(bool fill_up) override; public: MutatorAllocRegion(uint node_index) : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */, node_index), @@ -231,27 +208,36 @@ class MutatorAllocRegion : public G1AllocRegion { // This specialization of release() makes sure that the retained alloc // region is retired and set to null. - virtual G1HeapRegion* release(); + G1HeapRegion* release() override; - virtual void init(); + void init() override; }; // Common base class for allocation regions used during GC. class G1GCAllocRegion : public G1AllocRegion { + // When we set up a new active region we save its used bytes in this + // field so that, when we retire it, we can calculate how much space + // we allocated in it. + size_t _used_bytes_before; protected: G1EvacStats* _stats; G1HeapRegionAttr::region_type_t _purpose; - virtual G1HeapRegion* allocate_new_region(size_t word_size); - virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes); + G1HeapRegion* allocate_new_region(size_t word_size) override; + void retire_region(G1HeapRegion* alloc_region) override; - virtual size_t retire(bool fill_up); + size_t retire(bool fill_up) override; G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, G1HeapRegionAttr::region_type_t purpose, uint node_index = G1NUMA::AnyNodeIndex) - : G1AllocRegion(name, bot_updates, node_index), _stats(stats), _purpose(purpose) { + : G1AllocRegion(name, bot_updates, node_index), _used_bytes_before(0), _stats(stats), _purpose(purpose) { assert(stats != nullptr, "Must pass non-null PLAB statistics"); } +public: + // This can be used to reuse a specific region. (Use Example: we try to retain the + // last old GC alloc region that we've used during a GC and we can use reuse() to + // re-instate it at the beginning of the next GC.) + void reuse(G1HeapRegion* alloc_region); }; class SurvivorGCAllocRegion : public G1GCAllocRegion { diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp index ba4f1a12628d0..457a83f42857c 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp @@ -31,9 +31,9 @@ #define assert_alloc_region(p, message) \ do { \ - assert((p), "[%s] %s c: %u r: " PTR_FORMAT " u: " SIZE_FORMAT, \ - _name, (message), _count, p2i(_alloc_region), \ - _used_bytes_before); \ + assert((p), "[%s] %s c: %u r: " PTR_FORMAT, \ + _name, (message), _count, p2i(_alloc_region) \ + ); \ } while (0) @@ -41,41 +41,27 @@ inline void G1AllocRegion::reset_alloc_region() { _alloc_region = _dummy_region; } -inline HeapWord* G1AllocRegion::allocate(G1HeapRegion* alloc_region, - size_t word_size) { - assert(alloc_region != nullptr, "pre-condition"); - - return alloc_region->allocate(word_size); -} - inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) { - size_t temp; - return par_allocate(alloc_region, word_size, word_size, &temp); -} - -inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, - size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size) { assert(alloc_region != nullptr, "pre-condition"); assert(!alloc_region->is_empty(), "pre-condition"); - - return alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); + size_t temp; + return alloc_region->par_allocate(word_size, word_size, &temp); } inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { G1HeapRegion* alloc_region = _alloc_region; - assert_alloc_region(alloc_region != nullptr, "not initialized properly"); + assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "not initialized properly"); + + HeapWord* result = alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); - HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size); if (result != nullptr) { trace("alloc", min_word_size, desired_word_size, *actual_word_size, result); - return result; + } else { + trace("alloc failed", min_word_size, desired_word_size); } - trace("alloc failed", min_word_size, desired_word_size); - return nullptr; + return result; } inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size) { @@ -112,7 +98,7 @@ inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word size_t desired_word_size, size_t* actual_word_size) { if (_retained_alloc_region != nullptr) { - HeapWord* result = par_allocate(_retained_alloc_region, min_word_size, desired_word_size, actual_word_size); + HeapWord* result = _retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); if (result != nullptr) { trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result); return result; diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 05c64287ec0eb..29ce8e26bbbc6 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -118,7 +118,7 @@ void G1Allocator::reuse_retained_old_region(G1EvacInfo* evacuation_info, // we allocate to in the region sets. We'll re-add it later, when // it's retired again. _g1h->old_set_remove(retained_region); - old->set(retained_region); + old->reuse(retained_region); G1HeapRegionPrinter::reuse(retained_region); evacuation_info->set_alloc_regions_used_before(retained_region->used()); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index dc2c71bcbb450..67d6556203cad 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -127,18 +127,6 @@ class G1HeapRegion : public CHeapObj { void mangle_unused_area() PRODUCT_RETURN; - // Try to allocate at least min_word_size and up to desired_size from this region. - // Returns null if not possible, otherwise sets actual_word_size to the amount of - // space allocated. - // This version assumes that all allocation requests to this G1HeapRegion are properly - // synchronized. - inline HeapWord* allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size); - // Try to allocate at least min_word_size and up to desired_size from this G1HeapRegion. - // Returns null if not possible, otherwise sets actual_word_size to the amount of - // space allocated. - // This version synchronizes with other calls to par_allocate_impl(). - inline HeapWord* par_allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size); - inline HeapWord* advance_to_block_containing_addr(const void* addr, HeapWord* const pb, HeapWord* first_block) const; @@ -163,8 +151,18 @@ class G1HeapRegion : public CHeapObj { // All allocations are done without updating the BOT. The BOT // needs to be kept in sync for old generation regions and // this is done by explicit updates when crossing thresholds. + + // Try to allocate at least min_word_size and up to desired_size from this HeapRegion. + // Returns null if not possible, otherwise sets actual_word_size to the amount of + // space allocated. + // This version synchronizes with other calls to par_allocate(). inline HeapWord* par_allocate(size_t min_word_size, size_t desired_word_size, size_t* word_size); inline HeapWord* allocate(size_t word_size); + // Try to allocate at least min_word_size and up to desired_size from this region. + // Returns null if not possible, otherwise sets actual_word_size to the amount of + // space allocated. + // This version assumes that all allocation requests to this HeapRegion are properly + // synchronized. inline HeapWord* allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_size); // Full GC support methods. diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index 8e5e594b5cac2..f31c5fb553e29 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -42,47 +42,6 @@ #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" -inline HeapWord* G1HeapRegion::allocate_impl(size_t min_word_size, - size_t desired_word_size, - size_t* actual_size) { - HeapWord* obj = top(); - size_t available = pointer_delta(end(), obj); - size_t want_to_allocate = MIN2(available, desired_word_size); - if (want_to_allocate >= min_word_size) { - HeapWord* new_top = obj + want_to_allocate; - set_top(new_top); - assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); - *actual_size = want_to_allocate; - return obj; - } else { - return nullptr; - } -} - -inline HeapWord* G1HeapRegion::par_allocate_impl(size_t min_word_size, - size_t desired_word_size, - size_t* actual_size) { - do { - HeapWord* obj = top(); - size_t available = pointer_delta(end(), obj); - size_t want_to_allocate = MIN2(available, desired_word_size); - if (want_to_allocate >= min_word_size) { - HeapWord* new_top = obj + want_to_allocate; - HeapWord* result = Atomic::cmpxchg(&_top, obj, new_top); - // result can be one of two: - // the old top value: the exchange succeeded - // otherwise: the new value of the top is returned. - if (result == obj) { - assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); - *actual_size = want_to_allocate; - return obj; - } - } else { - return nullptr; - } - } while (true); -} - inline HeapWord* G1HeapRegion::block_start(const void* addr) const { return block_start(addr, parsable_bottom_acquire()); } @@ -225,9 +184,27 @@ inline void G1HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMar } inline HeapWord* G1HeapRegion::par_allocate(size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size) { - return par_allocate_impl(min_word_size, desired_word_size, actual_word_size); + size_t desired_word_size, + size_t* actual_word_size) { + do { + HeapWord* obj = top(); + size_t available = pointer_delta(end(), obj); + size_t want_to_allocate = MIN2(available, desired_word_size); + if (want_to_allocate >= min_word_size) { + HeapWord* new_top = obj + want_to_allocate; + HeapWord* result = Atomic::cmpxchg(&_top, obj, new_top); + // result can be one of two: + // the old top value: the exchange succeeded + // otherwise: the new value of the top is returned. + if (result == obj) { + assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); + *actual_word_size = want_to_allocate; + return obj; + } + } else { + return nullptr; + } + } while (true); } inline HeapWord* G1HeapRegion::allocate(size_t word_size) { @@ -236,9 +213,20 @@ inline HeapWord* G1HeapRegion::allocate(size_t word_size) { } inline HeapWord* G1HeapRegion::allocate(size_t min_word_size, - size_t desired_word_size, - size_t* actual_word_size) { - return allocate_impl(min_word_size, desired_word_size, actual_word_size); + size_t desired_word_size, + size_t* actual_word_size) { + HeapWord* obj = top(); + size_t available = pointer_delta(end(), obj); + size_t want_to_allocate = MIN2(available, desired_word_size); + if (want_to_allocate >= min_word_size) { + HeapWord* new_top = obj + want_to_allocate; + set_top(new_top); + assert(is_object_aligned(obj) && is_object_aligned(new_top), "checking alignment"); + *actual_word_size = want_to_allocate; + return obj; + } else { + return nullptr; + } } inline void G1HeapRegion::update_bot() { From 19a8a2baa9e749c7527ff526b2794826f0cdebb3 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Jul 2024 15:42:47 +0000 Subject: [PATCH 147/288] 8335618: Serial: Remove unused definitions in SerialHeap Reviewed-by: iwalulya --- src/hotspot/share/gc/serial/defNewGeneration.hpp | 1 - src/hotspot/share/gc/serial/serialHeap.hpp | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 5c8dd08e40b82..a7ee555902a25 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -43,7 +43,6 @@ class CSpaceCounters; class OldGenScanClosure; class YoungGenScanClosure; class DefNewTracer; -class ScanWeakRefClosure; class SerialHeap; class STWGCTimer; diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 14e0d737c1a4e..750bb322b2ac4 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -72,14 +72,8 @@ class SerialHeap : public CollectedHeap { friend class HeapInspection; friend class GCCauseSetter; friend class VMStructs; -public: friend class VM_PopulateDumpSharedSpace; - enum GenerationType { - YoungGen, - OldGen - }; - private: DefNewGeneration* _young_gen; TenuredGeneration* _old_gen; @@ -124,7 +118,6 @@ class SerialHeap : public CollectedHeap { // Does operations required after initialization has been done. void post_initialize() override; - bool is_young_gen(const Generation* gen) const { return gen == _young_gen; } bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); } // Performance Counter support From 8aaec37ace102b55ee1387cfd1967ec3ab662083 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 3 Jul 2024 16:08:34 +0000 Subject: [PATCH 148/288] 8322475: Extend printing for System.map Reviewed-by: sgehwolf, jsjolen --- src/hotspot/os/linux/memMapPrinter_linux.cpp | 183 ++++++++++++++---- src/hotspot/os/linux/procMapsParser.cpp | 125 ++++++++++++ src/hotspot/os/linux/procMapsParser.hpp | 91 +++++++++ src/hotspot/share/nmt/memMapPrinter.cpp | 115 ++++------- src/hotspot/share/nmt/memMapPrinter.hpp | 33 +--- src/hotspot/share/runtime/java.cpp | 2 +- src/hotspot/share/services/attachListener.cpp | 8 +- .../share/services/diagnosticCommand.cpp | 14 +- .../share/services/diagnosticCommand.hpp | 13 +- src/hotspot/share/utilities/ostream.cpp | 7 +- src/hotspot/share/utilities/ostream.hpp | 2 +- .../dcmd/vm/SystemDumpMapTest.java | 23 ++- .../serviceability/dcmd/vm/SystemMapTest.java | 29 +-- .../dcmd/vm/SystemMapTestBase.java | 67 +++++++ 14 files changed, 513 insertions(+), 199 deletions(-) create mode 100644 src/hotspot/os/linux/procMapsParser.cpp create mode 100644 src/hotspot/os/linux/procMapsParser.hpp create mode 100644 test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java diff --git a/src/hotspot/os/linux/memMapPrinter_linux.cpp b/src/hotspot/os/linux/memMapPrinter_linux.cpp index 05d520f69539a..0b696b9914efe 100644 --- a/src/hotspot/os/linux/memMapPrinter_linux.cpp +++ b/src/hotspot/os/linux/memMapPrinter_linux.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,60 +25,165 @@ #include "precompiled.hpp" -#include "runtime/os.hpp" #include "nmt/memMapPrinter.hpp" +#include "procMapsParser.hpp" +#include "runtime/os.hpp" +#include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" + #include -struct ProcMapsInfo { - void* from = 0; - void* to = 0; - char prot[20 + 1]; - char offset[20 + 1]; - char dev[20 + 1]; - char inode[20 + 1]; - char filename[1024 + 1]; - - bool scan_proc_maps_line(const char* line) { - prot[0] = offset[0] = dev[0] = inode[0] = filename[0] = '\0'; - const int items_read = ::sscanf(line, "%p-%p %20s %20s %20s %20s %1024s", - &from, &to, prot, offset, dev, inode, filename); - return items_read >= 2; // need at least from and to +class ProcSmapsSummary { + unsigned _num_mappings; + size_t _vsize; // combined virtual size + size_t _rss; // combined resident set size + size_t _committed; // combined committed size + size_t _shared; // combined shared size + size_t _swapped_out; // combined amount of swapped-out memory + size_t _hugetlb; // combined amount of memory backed by explicit huge pages + size_t _thp; // combined amount of memory backed by THPs +public: + ProcSmapsSummary() : _num_mappings(0), _vsize(0), _rss(0), _committed(0), _shared(0), + _swapped_out(0), _hugetlb(0), _thp(0) {} + void add_mapping(const ProcSmapsInfo& info) { + _num_mappings++; + _vsize += info.vsize(); + _rss += info.rss; + _committed += info.nr ? 0 : info.vsize(); + _shared += info.sh ? info.vsize() : 0; + _swapped_out += info.swap; + _hugetlb += info.private_hugetlb + info.shared_hugetlb; + _thp += info.anonhugepages; + } + + void print_on(const MappingPrintSession& session) const { + outputStream* st = session.out(); + st->print_cr("Number of mappings: %u", _num_mappings); + st->print_cr(" vsize: %zu (" PROPERFMT ")", _vsize, PROPERFMTARGS(_vsize)); + st->print_cr(" rss: %zu (" PROPERFMT ")", _rss, PROPERFMTARGS(_rss)); + st->print_cr(" committed: %zu (" PROPERFMT ")", _committed, PROPERFMTARGS(_committed)); + st->print_cr(" shared: %zu (" PROPERFMT ")", _shared, PROPERFMTARGS(_shared)); + st->print_cr(" swapped out: %zu (" PROPERFMT ")", _swapped_out, PROPERFMTARGS(_swapped_out)); + st->print_cr(" using thp: %zu (" PROPERFMT ")", _thp, PROPERFMTARGS(_thp)); + st->print_cr(" hugetlb: %zu (" PROPERFMT ")", _hugetlb, PROPERFMTARGS(_hugetlb)); } }; -class LinuxMappingPrintInformation : public MappingPrintInformation { - const ProcMapsInfo _info; +class ProcSmapsPrinter { + const MappingPrintSession& _session; public: + ProcSmapsPrinter(const MappingPrintSession& session) : + _session(session) + {} - LinuxMappingPrintInformation(const void* from, const void* to, const ProcMapsInfo* info) : - MappingPrintInformation(from, to), _info(*info) {} + void print_single_mapping(const ProcSmapsInfo& info) const { + outputStream* st = _session.out(); +#define INDENT_BY(n) \ + if (st->fill_to(n) == 0) { \ + st->print(" "); \ + } + st->print(PTR_FORMAT "-" PTR_FORMAT, p2i(info.from), p2i(info.to)); + INDENT_BY(38); + st->print("%12zu", info.vsize()); + INDENT_BY(51); + st->print("%s", info.prot); + INDENT_BY(56); + st->print("%12zu", info.rss); + INDENT_BY(69); + st->print("%12zu", info.private_hugetlb); + INDENT_BY(82); + st->print(EXACTFMT, EXACTFMTARGS(info.kernelpagesize)); + { + INDENT_BY(87); + int num_printed = 0; +#define PRINTIF(cond, s) \ + if (cond) { \ + st->print("%s%s", (num_printed > 0 ? "," : ""), s); \ + num_printed++; \ + } + PRINTIF(info.sh, "shrd"); + PRINTIF(!info.nr, "com"); + PRINTIF(info.swap > 0, "swap"); + PRINTIF(info.ht, "huge"); + PRINTIF(info.anonhugepages > 0, "thp"); + PRINTIF(info.hg, "thpad"); + PRINTIF(info.nh, "nothp"); + if (num_printed == 0) { + st->print("-"); + } +#undef PRINTIF + } + INDENT_BY(104); + if (!_session.print_nmt_info_for_region(info.from, info.to)) { + st->print("-"); + } + INDENT_BY(142); + st->print_raw(info.filename[0] == '\0' ? "-" : info.filename); + #undef INDENT_BY + st->cr(); + } - void print_OS_specific_details(outputStream* st) const override { - st->print("%s %s ", _info.prot, _info.offset); + void print_legend() const { + outputStream* st = _session.out(); + st->print_cr("from, to, vsize: address range and size"); + st->print_cr("prot: protection"); + st->print_cr("rss: resident set size"); + st->print_cr("hugetlb: size of private hugetlb pages"); + st->print_cr("pgsz: page size"); + st->print_cr("notes: mapping information (detail mode only)"); + st->print_cr(" shrd: mapping is shared"); + st->print_cr(" com: mapping committed (swap space reserved)"); + st->print_cr(" swap: mapping partly or completely swapped out"); + st->print_cr(" thp: mapping uses THP"); + st->print_cr(" thpad: mapping is THP-madvised"); + st->print_cr(" nothp: mapping is forbidden to use THP"); + st->print_cr(" huge: mapping uses hugetlb pages"); + st->print_cr("vm info: VM information (requires NMT)"); + { + streamIndentor si(st, 16); + _session.print_nmt_flag_legend(); + } + st->print_cr("file: file mapped, if mapping is not anonymous"); } - const char* filename() const override { return _info.filename; } + void print_header() const { + outputStream* st = _session.out(); + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 + // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 + // 0x0000000414000000-0x0000000453000000 123456789012 rw-p 123456789012 123456789012 16g thp,thpadv STACK-340754-Monitor-Deflation-Thread /shared/tmp.txt + st->print_cr("from to vsize prot rss hugetlb pgsz notes info file"); + st->print_cr("========================================================================================================================================================================"); + } }; -void MemMapPrinter::pd_print_header(outputStream* st) { - st->print_cr("size prot offset What"); -} - -void MemMapPrinter::pd_iterate_all_mappings(MappingPrintClosure& closure) { - FILE* f = os::fopen("/proc/self/maps", "r"); +void MemMapPrinter::pd_print_all_mappings(const MappingPrintSession& session) { + constexpr char filename[] = "/proc/self/smaps"; + FILE* f = os::fopen(filename, "r"); if (f == nullptr) { + session.out()->print_cr("Cannot open %s", filename); return; } - constexpr size_t linesize = sizeof(ProcMapsInfo); - char line[linesize]; - while (fgets(line, sizeof(line), f) == line) { - line[sizeof(line) - 1] = '\0'; - ProcMapsInfo info; - if (info.scan_proc_maps_line(line)) { - LinuxMappingPrintInformation mapinfo(info.from, info.to, &info); - closure.do_it(&mapinfo); - } + + ProcSmapsPrinter printer(session); + ProcSmapsSummary summary; + + outputStream* const st = session.out(); + + printer.print_legend(); + st->cr(); + printer.print_header(); + + ProcSmapsInfo info; + ProcSmapsParser parser(f); + while (parser.parse_next(info)) { + printer.print_single_mapping(info); + summary.add_mapping(info); } + st->cr(); + + summary.print_on(session); + st->cr(); + ::fclose(f); } diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp new file mode 100644 index 0000000000000..6dfd49a0596e3 --- /dev/null +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "procMapsParser.hpp" +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" + +static bool is_lowercase_hex(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); +} + +static size_t max_mapping_line_len() { + return 100 + // everything but the file name + os::vm_page_size() // the file name (kernel limits /proc/pid/cmdline to one page + ; +} + +ProcSmapsParser::ProcSmapsParser(FILE* f) : + _f(f), _linelen(max_mapping_line_len()), _line(nullptr) { + assert(_f != nullptr, "Invalid file handle given"); + _line = NEW_C_HEAP_ARRAY(char, max_mapping_line_len(), mtInternal); + _line[0] = '\0'; +} + +ProcSmapsParser::~ProcSmapsParser() { + FREE_C_HEAP_ARRAY(char, _line); +} + +bool ProcSmapsParser::read_line() { + _line[0] = '\0'; + return ::fgets(_line, _linelen, _f) != nullptr; +} + +bool ProcSmapsParser::is_header_line() { + // e.g. ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] + return is_lowercase_hex(_line[0]); // All non-header lines in /proc/pid/smaps start with upper-case letters. +} + +void ProcSmapsParser::scan_header_line(ProcSmapsInfo& out) { + const int items_read = ::sscanf(_line, "%p-%p %20s %*s %*s %*s %1024s", + &out.from, &out.to, out.prot, out.filename); + assert(items_read >= 2, "Expected header_line"); +} + +void ProcSmapsParser::scan_additional_line(ProcSmapsInfo& out) { +#define SCAN(key, var) \ + if (::sscanf(_line, key ": %zu kB", &var) == 1) { \ + var *= K; \ + return; \ + } + SCAN("KernelPageSize", out.kernelpagesize); + SCAN("Rss", out.rss); + SCAN("AnonHugePages", out.anonhugepages); + SCAN("Private_Hugetlb", out.private_hugetlb); + SCAN("Shared_Hugetlb", out.shared_hugetlb); + SCAN("Swap", out.swap); + int i = 0; +#undef SCAN + // scan some flags too + if (strncmp(_line, "VmFlags:", 8) == 0) { +#define SCAN(flag) { out.flag = (::strstr(_line + 8, " " #flag) != nullptr); } + SCAN(rd); + SCAN(wr); + SCAN(ex); + SCAN(nr); + SCAN(sh); + SCAN(hg); + SCAN(ht); + SCAN(nh); +#undef SCAN + } +} + +// Starts or continues parsing. Returns true on success, +// false on EOF or on error. +bool ProcSmapsParser::parse_next(ProcSmapsInfo& out) { + + // Information about a single mapping reaches across several lines. + out.reset(); + + // Read header line, unless we already read it + if (_line[0] == '\0') { + if (!read_line()) { + return false; + } + } + assert(is_header_line(), "Not a header line: \"%s\".", _line); + scan_header_line(out); + + // Now read until we encounter the next header line or EOF or an error. + bool ok = false, stop = false; + do { + ok = read_line(); + stop = !ok || is_header_line(); + if (!stop) { + scan_additional_line(out); + } + } while (!stop); + + return ok; +} diff --git a/src/hotspot/os/linux/procMapsParser.hpp b/src/hotspot/os/linux/procMapsParser.hpp new file mode 100644 index 0000000000000..0971c4fb084f9 --- /dev/null +++ b/src/hotspot/os/linux/procMapsParser.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_PROCMAPSPARSER_HPP +#define OS_LINUX_PROCMAPSPARSER_HPP + +#include "utilities/globalDefinitions.hpp" + +// This header exposes two simple parsers for /proc/pid/maps and +// /proc/pid/smaps. +// +// Usage: +// +// FILE* f = fopen(...) +// ProcSMapsParser parser(f); +// ProcSMapsInfo info; +// while (parser.parse_next(info)) { ... } + +struct ProcSmapsInfo { + void* from; + void* to; + char prot[20 + 1]; + char filename[1024 + 1]; + size_t kernelpagesize; + size_t rss; + size_t private_hugetlb; + size_t shared_hugetlb; + size_t anonhugepages; + size_t swap; + bool rd, wr, ex; + bool sh; // shared + bool nr; // no reserve + bool hg; // thp-advised + bool ht; // uses hugetlb pages + bool nh; // thp forbidden + + size_t vsize() const { + return from < to ? pointer_delta(to, from, 1) : 0; + } + + void reset() { + from = to = nullptr; + prot[0] = filename[0] = '\0'; + kernelpagesize = rss = private_hugetlb = shared_hugetlb = anonhugepages = swap = 0; + rd = wr = ex = sh = nr = hg = ht = nh = false; + } +}; + +class ProcSmapsParser { + FILE* _f; + const size_t _linelen; + char* _line; + + bool read_line(); // sets had_error in case of error + bool is_header_line(); + void scan_header_line(ProcSmapsInfo& out); + void scan_additional_line(ProcSmapsInfo& out); + +public: + + ProcSmapsParser(FILE* f); + ~ProcSmapsParser(); + + // Starts or continues parsing. Returns true on success, + // false on EOF or on error. + bool parse_next(ProcSmapsInfo& out); +}; + +#endif // OS_LINUX_PROCMAPSPARSER_HPP diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp index 5480904d57c40..5f920b102a977 100644 --- a/src/hotspot/share/nmt/memMapPrinter.cpp +++ b/src/hotspot/share/nmt/memMapPrinter.cpp @@ -27,8 +27,9 @@ #ifdef LINUX -#include "logging/logAsyncWriter.hpp" #include "gc/shared/collectedHeap.hpp" +#include "logging/logAsyncWriter.hpp" +#include "memory/allocation.hpp" #include "memory/universe.hpp" #include "memory/resourceArea.hpp" #include "nmt/memflags.hpp" @@ -42,7 +43,6 @@ #include "runtime/threadSMR.hpp" #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" // Note: throughout this code we will use the term "VMA" for OS system level memory mapping @@ -160,13 +160,6 @@ class CachedNMTInformation : public VirtualMemoryWalker { bool fill_from_nmt() { return VirtualMemoryTracker::walk_virtual_memory(this); } - - void print_on(outputStream* st) const { - for (size_t i = 0; i < _count; i ++) { - st->print_cr(PTR_FORMAT "-" PTR_FORMAT " %s", p2i(_ranges[i].from), p2i(_ranges[i].to), - NMTUtil::flag_to_enum_name(_flags[i])); - } - } }; /////// Thread information ////////////////////////// @@ -198,7 +191,16 @@ struct GCThreadClosure : public ThreadClosure { }; static void print_thread_details(uintx thread_id, const char* name, outputStream* st) { - st->print("(" UINTX_FORMAT " \"%s\")", (uintx)thread_id, name); + // avoid commas and spaces in output to ease post-processing via awk + char tmp[64]; + stringStream ss(tmp, sizeof(tmp)); + ss.print(":" UINTX_FORMAT "-%s", (uintx)thread_id, name); + for (int i = 0; tmp[i] != '\0'; i++) { + if (!isalnum(tmp[i])) { + tmp[i] = '-'; + } + } + st->print_raw(tmp); } // Given a region [from, to), if it intersects a known thread stack, print detail infos about that thread. @@ -230,41 +232,18 @@ static void print_thread_details_for_supposed_stack_address(const void* from, co /////////////// -static void print_legend(outputStream* st) { -#define DO(flag, shortname, text) st->print_cr("%10s %s", shortname, text); +MappingPrintSession::MappingPrintSession(outputStream* st, const CachedNMTInformation& nmt_info) : + _out(st), _nmt_info(nmt_info) +{} + +void MappingPrintSession::print_nmt_flag_legend() const { +#define DO(flag, shortname, text) _out->indent(); _out->print_cr("%10s: %s", shortname, text); NMT_FLAGS_DO(DO) #undef DO } -MappingPrintClosure::MappingPrintClosure(outputStream* st, bool human_readable, const CachedNMTInformation& nmt_info) : - _out(st), _human_readable(human_readable), - _total_count(0), _total_vsize(0), _nmt_info(nmt_info) -{} - -void MappingPrintClosure::do_it(const MappingPrintInformation* info) { - - _total_count++; - - const void* const vma_from = info->from(); - const void* const vma_to = info->to(); - - // print from, to - _out->print(PTR_FORMAT " - " PTR_FORMAT " ", p2i(vma_from), p2i(vma_to)); - const size_t size = pointer_delta(vma_to, vma_from, 1); - _total_vsize += size; - - // print mapping size - if (_human_readable) { - _out->print(PROPERFMT " ", PROPERFMTARGS(size)); - } else { - _out->print("%11zu", size); - } - - assert(info->from() <= info->to(), "Invalid VMA"); - _out->fill_to(53); - info->print_OS_specific_details(_out); - _out->fill_to(70); - +bool MappingPrintSession::print_nmt_info_for_region(const void* vma_from, const void* vma_to) const { + int num_printed = 0; // print NMT information, if available if (MemTracker::enabled()) { // Correlate vma region (from, to) with NMT region(s) we collected previously. @@ -273,59 +252,33 @@ void MappingPrintClosure::do_it(const MappingPrintInformation* info) { for (int i = 0; i < mt_number_of_types; i++) { const MEMFLAGS flag = (MEMFLAGS)i; if (flags.has_flag(flag)) { + if (num_printed > 0) { + _out->put(','); + } _out->print("%s", get_shortname_for_nmt_flag(flag)); if (flag == mtThreadStack) { print_thread_details_for_supposed_stack_address(vma_from, vma_to, _out); } - _out->print(" "); + num_printed++; } } } } - - // print file name, if available - const char* f = info->filename(); - if (f != nullptr) { - _out->print_raw(f); - } - _out->cr(); -} - -void MemMapPrinter::print_header(outputStream* st) { - st->print( -#ifdef _LP64 - // 0x0000000000000000 - 0x0000000000000000 - "from to " -#else - // 0x00000000 - 0x00000000 - "from to " -#endif - ); - // Print platform-specific columns - pd_print_header(st); + return num_printed > 0; } -void MemMapPrinter::print_all_mappings(outputStream* st, bool human_readable) { - // First collect all NMT information +void MemMapPrinter::print_all_mappings(outputStream* st) { CachedNMTInformation nmt_info; - nmt_info.fill_from_nmt(); - DEBUG_ONLY(nmt_info.print_on(st);) st->print_cr("Memory mappings:"); - if (!MemTracker::enabled()) { - st->cr(); - st->print_cr(" (NMT is disabled, will not annotate mappings)."); + // Prepare NMT info cache. But only do so if we print individual mappings, + // otherwise, we won't need it and can save that work. + if (MemTracker::enabled()) { + nmt_info.fill_from_nmt(); + } else { + st->print_cr("NMT is disabled. VM info not available."); } - st->cr(); - - print_legend(st); - st->print_cr("(*) - Mapping contains data from multiple regions"); - st->cr(); - - pd_print_header(st); - MappingPrintClosure closure(st, human_readable, nmt_info); - pd_iterate_all_mappings(closure); - st->print_cr("Total: " UINTX_FORMAT " mappings with a total vsize of %zu (" PROPERFMT ")", - closure.total_count(), closure.total_vsize(), PROPERFMTARGS(closure.total_vsize())); + MappingPrintSession session(st, nmt_info); + pd_print_all_mappings(session); } #endif // LINUX diff --git a/src/hotspot/share/nmt/memMapPrinter.hpp b/src/hotspot/share/nmt/memMapPrinter.hpp index 67706c4d4d74e..aa35a830001e3 100644 --- a/src/hotspot/share/nmt/memMapPrinter.hpp +++ b/src/hotspot/share/nmt/memMapPrinter.hpp @@ -35,39 +35,20 @@ class outputStream; class CachedNMTInformation; -class MappingPrintInformation { - const void* const _from; - const void* const _to; -public: - MappingPrintInformation(const void* from, const void* to) : _from(from), _to(to) {} - const void* from() const { return _from; } - const void* to() const { return _to; } - // Will be called for each mapping before VM annotations are printed. - virtual void print_OS_specific_details(outputStream* st) const {} - // If mapping is backed by a file, the name of that file - virtual const char* filename() const { return nullptr; } -}; - -class MappingPrintClosure { +class MappingPrintSession { outputStream* const _out; - const bool _human_readable; - uintx _total_count; - size_t _total_vsize; const CachedNMTInformation& _nmt_info; public: - MappingPrintClosure(outputStream* st, bool human_readable, const CachedNMTInformation& nmt_info); - void do_it(const MappingPrintInformation* info); // returns false if timeout reached. - uintx total_count() const { return _total_count; } - size_t total_vsize() const { return _total_vsize; } + MappingPrintSession(outputStream* st, const CachedNMTInformation& nmt_info); + bool print_nmt_info_for_region(const void* from, const void* to) const; + void print_nmt_flag_legend() const; + outputStream* out() const { return _out; } }; class MemMapPrinter : public AllStatic { - static void pd_print_header(outputStream* st); - static void print_header(outputStream* st); - static void pd_iterate_all_mappings(MappingPrintClosure& closure); + static void pd_print_all_mappings(const MappingPrintSession& session); public: - static void mark_page_malloced(const void* p, MEMFLAGS f); - static void print_all_mappings(outputStream* st, bool human_readable); + static void print_all_mappings(outputStream* st); }; #endif // LINUX diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 674716a859852..7ffe56d9715a3 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -487,7 +487,7 @@ void before_exit(JavaThread* thread, bool halt) { CodeCache::write_perf_map(); } if (PrintMemoryMapAtExit) { - MemMapPrinter::print_all_mappings(tty, false); + MemMapPrinter::print_all_mappings(tty); } #endif diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index d1531e1ec012e..36931531a4e02 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -395,7 +395,13 @@ void AttachListenerThread::thread_entry(JavaThread* thread, TRAPS) { } ResourceMark rm; - bufferedStream st; + // jcmd output can get lengthy. As long as we miss jcmd continuous streaming output + // and instead just send the output in bulk, make sure large command output does not + // cause asserts. We still retain a max cap, but dimensioned in a way that makes it + // highly unlikely we should ever hit it under normal conditions. + constexpr size_t initial_size = 1 * M; + constexpr size_t max_size = 3 * G; + bufferedStream st(initial_size, max_size); jint res = JNI_OK; // handle special detachall operation diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 4b8eae8a4138e..7d2325c16b651 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -1180,23 +1180,17 @@ void CompilationMemoryStatisticDCmd::execute(DCmdSource source, TRAPS) { #ifdef LINUX -SystemMapDCmd::SystemMapDCmd(outputStream* output, bool heap) : - DCmdWithParser(output, heap), - _human_readable("-H", "Human readable format", "BOOLEAN", false, "false") { - _dcmdparser.add_dcmd_option(&_human_readable); -} +SystemMapDCmd::SystemMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} void SystemMapDCmd::execute(DCmdSource source, TRAPS) { - MemMapPrinter::print_all_mappings(output(), _human_readable.value()); + MemMapPrinter::print_all_mappings(output()); } static constexpr char default_filename[] = "vm_memory_map_.txt"; SystemDumpMapDCmd::SystemDumpMapDCmd(outputStream* output, bool heap) : - DCmdWithParser(output, heap), - _human_readable("-H", "Human readable format", "BOOLEAN", false, "false"), + DCmdWithParser(output, heap), _filename("-F", "file path", "STRING", false, default_filename) { - _dcmdparser.add_dcmd_option(&_human_readable); _dcmdparser.add_dcmd_option(&_filename); } @@ -1214,7 +1208,7 @@ void SystemDumpMapDCmd::execute(DCmdSource source, TRAPS) { if (!MemTracker::enabled()) { output()->print_cr("(NMT is disabled, will not annotate mappings)."); } - MemMapPrinter::print_all_mappings(&fs, _human_readable.value()); + MemMapPrinter::print_all_mappings(&fs); // For the readers convenience, resolve path name. char tmp[JVM_MAXPATHLEN]; const char* absname = os::Posix::realpath(name, tmp, sizeof(tmp)); diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index 88a4897081091..ec3469c8d1523 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -983,16 +983,14 @@ class CompilationMemoryStatisticDCmd: public DCmdWithParser { #ifdef LINUX -class SystemMapDCmd : public DCmdWithParser { - DCmdArgument _human_readable; +class SystemMapDCmd : public DCmd { public: - static int num_arguments() { return 1; } SystemMapDCmd(outputStream* output, bool heap); static const char* name() { return "System.map"; } static const char* description() { return "Prints an annotated process memory map of the VM process (linux only)."; } - static const char* impact() { return "Low"; } + static const char* impact() { return "Medium; can be high for very large java heaps."; } static const JavaPermission permission() { JavaPermission p = {"java.lang.management.ManagementPermission", "control", nullptr}; @@ -1002,16 +1000,15 @@ class SystemMapDCmd : public DCmdWithParser { }; class SystemDumpMapDCmd : public DCmdWithParser { - DCmdArgument _human_readable; DCmdArgument _filename; public: - static int num_arguments() { return 2; } + static int num_arguments() { return 1; } SystemDumpMapDCmd(outputStream* output, bool heap); static const char* name() { return "System.dump_map"; } static const char* description() { return "Dumps an annotated process memory map to an output file (linux only)."; } - static const char* impact() { return "Low"; } + static const char* impact() { return "Medium; can be high for very large java heaps."; } static const JavaPermission permission() { JavaPermission p = {"java.lang.management.ManagementPermission", "control", nullptr}; diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 5d6731785a3ac..b8f27fbd4130b 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -191,9 +191,10 @@ void outputStream::print_raw(const char* str, size_t len) { write(str, len); } -void outputStream::fill_to(int col) { - int need_fill = col - position(); +int outputStream::fill_to(int col) { + const int need_fill = MAX2(col - position(), 0); sp(need_fill); + return need_fill; } void outputStream::move_to(int col, int slop, int min_space) { @@ -1037,7 +1038,7 @@ void bufferedStream::write(const char* s, size_t len) { const size_t reasonable_cap = MAX2(100 * M, buffer_max * 2); if (end > reasonable_cap) { // In debug VM, assert right away. - assert(false, "Exceeded max buffer size for this string."); + assert(false, "Exceeded max buffer size for this string (\"%.200s...\").", buffer); // Release VM: silently truncate. We do this since these kind of errors // are both difficult to predict with testing (depending on logging content) // and usually not serious enough to kill a production VM for it. diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index bff682a3e5aa9..beb02309d3f23 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -101,7 +101,7 @@ class outputStream : public CHeapObjBase { void dec(int n) { _indentation -= n; }; int indentation() const { return _indentation; } void set_indentation(int i) { _indentation = i; } - void fill_to(int col); + int fill_to(int col); void move_to(int col, int slop = 6, int min_space = 2); // Automatic indentation: diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java index 347e888409631..eb0b6bd8566ae 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemDumpMapTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import jdk.test.lib.process.OutputAnalyzer; import java.io.*; -import java.util.ArrayList; import java.util.HashSet; import java.util.regex.Pattern; @@ -41,9 +40,9 @@ * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run testng SystemDumpMapTest + * @run testng/othervm -XX:+UsePerfData SystemDumpMapTest */ -public class SystemDumpMapTest { +public class SystemDumpMapTest extends SystemMapTestBase { private void run_test(CommandExecutor executor, boolean useDefaultFileName) { @@ -64,18 +63,22 @@ private void run_test(CommandExecutor executor, boolean useDefaultFileName) { boolean NMTOff = output.contains("NMT is disabled"); String regexBase = ".*0x\\p{XDigit}+ - 0x\\p{XDigit}+ +\\d+"; HashSet patterns = new HashSet<>(); - patterns.add(Pattern.compile(regexBase + ".*jvm.*")); + for (String s: shouldMatchUnconditionally) { + patterns.add(Pattern.compile(s)); + } if (!NMTOff) { // expect VM annotations if NMT is on - patterns.add(Pattern.compile(regexBase + ".*JAVAHEAP.*")); - patterns.add(Pattern.compile(regexBase + ".*META.*")); - patterns.add(Pattern.compile(regexBase + ".*CODE.*")); - patterns.add(Pattern.compile(regexBase + ".*STACK.*main.*")); + for (String s: shouldMatchIfNMTIsEnabled) { + patterns.add(Pattern.compile(s)); + } } + do { String line = reader.readLine(); if (line != null) { + System.out.println(" " + line); for (Pattern pat : patterns) { if (pat.matcher(line).matches()) { + System.out.println(">>> matches " + pat); patterns.remove(pat); break; } diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java index 9fb8efe5a716b..43857a1f039bf 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. * 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,13 +27,6 @@ import jdk.test.lib.dcmd.JMXExecutor; import jdk.test.lib.process.OutputAnalyzer; -import java.io.*; -import java.util.ArrayDeque; -import java.util.Collections; -import java.util.Deque; -import java.util.HashSet; -import java.util.regex.Pattern; - /* * @test * @summary Test of diagnostic command System.map @@ -43,21 +36,19 @@ * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run testng SystemMapTest + * @run testng/othervm -XX:+UsePerfData SystemMapTest */ -public class SystemMapTest { +public class SystemMapTest extends SystemMapTestBase { public void run(CommandExecutor executor) { OutputAnalyzer output = executor.execute("System.map"); - output.reportDiagnosticSummary(); boolean NMTOff = output.contains("NMT is disabled"); - - String regexBase = ".*0x\\p{XDigit}+ - 0x\\p{XDigit}+ +\\d+"; - output.shouldMatch(regexBase + ".*jvm.*"); + for (String s: shouldMatchUnconditionally) { + output.shouldMatch(s); + } if (!NMTOff) { // expect VM annotations if NMT is on - output.shouldMatch(regexBase + ".*JAVAHEAP.*"); - output.shouldMatch(regexBase + ".*META.*"); - output.shouldMatch(regexBase + ".*CODE.*"); - output.shouldMatch(regexBase + ".*STACK.*main.*"); + for (String s: shouldMatchIfNMTIsEnabled) { + output.shouldMatch(s); + } } } diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java new file mode 100644 index 0000000000000..20dc8d70d7a47 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat, Inc. and/or its affiliates. + * 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. + */ + +public class SystemMapTestBase { + + // e.g. + // 0x00000007ff800000-0x00000007ff91a000 1155072 rw-p 1155072 0 4K com JAVAHEAP /shared/projects/openjdk/jdk-jdk/output-fastdebug/images/jdk/lib/server/classes.jsa + private static final String range = "0x\\p{XDigit}+-0x\\p{XDigit}+"; + private static final String space = " +"; + private static final String someSize = "\\d+"; + private static final String pagesize = "(4K|8K|16K|64K|2M|16M|64M)"; + private static final String prot = "[rwsxp-]+"; + + private static final String regexBase = range + space + + someSize + space + + prot + space + + someSize + space + + someSize + space + + pagesize + space; + + private static final String regexBase_committed = regexBase + "com.*"; + private static final String regexBase_shared_and_committed = regexBase + "shrd,com.*"; + + protected static final String shouldMatchUnconditionally[] = { + // java launcher + regexBase_committed + "/bin/java", + // libjvm + regexBase_committed + "/lib/.*/libjvm.so", + // vdso library, should be part of all user space apps on all architectures OpenJDK supports. + regexBase_committed + "\\[vdso\\]", + // we should see the hs-perf data file, and it should appear as shared as well as committed + regexBase_shared_and_committed + "hsperfdata_.*" + }; + + protected static final String shouldMatchIfNMTIsEnabled[] = { + regexBase_committed + "JAVAHEAP.*", + // metaspace + regexBase_committed + "META.*", + // parts of metaspace should be uncommitted + regexBase + "-" + space + "META.*", + // code cache + regexBase_committed + "CODE.*", + // Main thread stack + regexBase_committed + "STACK.*main.*" + }; +} From 13b782c3de9a470a7cf1db9d5111ce19faf28729 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 3 Jul 2024 16:10:22 +0000 Subject: [PATCH 149/288] 8334554: RISC-V: verify & fix perf of string comparison Reviewed-by: rehn, luhenry, fyang --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 21 +++++++++---- .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 2 +- src/hotspot/cpu/riscv/riscv_v.ad | 30 +++++++++++++++++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 9ce197a44bf8a..887baa4a506d1 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2326,12 +2326,13 @@ void C2_MacroAssembler::expand_bits_l_v(Register dst, Register src, Register mas } void C2_MacroAssembler::element_compare(Register a1, Register a2, Register result, Register cnt, Register tmp1, Register tmp2, - VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE) { + VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE, + Assembler::LMUL lmul) { Label loop; Assembler::SEW sew = islatin ? Assembler::e8 : Assembler::e16; bind(loop); - vsetvli(tmp1, cnt, sew, Assembler::m2); + vsetvli(tmp1, cnt, sew, lmul); vlex_v(vr1, a1, sew); vlex_v(vr2, a2, sew); vmsne_vv(vrs, vr1, vr2); @@ -2357,7 +2358,7 @@ void C2_MacroAssembler::string_equals_v(Register a1, Register a2, Register resul mv(result, false); - element_compare(a1, a2, result, cnt, tmp1, tmp2, v2, v4, v2, true, DONE); + element_compare(a1, a2, result, cnt, tmp1, tmp2, v2, v4, v2, true, DONE, Assembler::m2); bind(DONE); BLOCK_COMMENT("} string_equals_v"); @@ -2410,7 +2411,7 @@ void C2_MacroAssembler::arrays_equals_v(Register a1, Register a2, Register resul la(a1, Address(a1, base_offset)); la(a2, Address(a2, base_offset)); - element_compare(a1, a2, result, cnt1, tmp1, tmp2, v2, v4, v2, elem_size == 1, DONE); + element_compare(a1, a2, result, cnt1, tmp1, tmp2, v2, v4, v2, elem_size == 1, DONE, Assembler::m2); bind(DONE); @@ -2445,8 +2446,18 @@ void C2_MacroAssembler::string_compare_v(Register str1, Register str2, Register mv(cnt2, cnt1); bind(L); + // We focus on the optimization of small sized string. + // Please check below document for string size distribution statistics. + // https://cr.openjdk.org/~shade/density/string-density-report.pdf if (str1_isL == str2_isL) { // LL or UU - element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v2, v4, v2, encLL, DIFFERENCE); + // Below construction of v regs and lmul is based on test on 2 different boards, + // vlen == 128 and vlen == 256 respectively. + if (!encLL && MaxVectorSize == 16) { // UU + element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v4, v8, v4, encLL, DIFFERENCE, Assembler::m4); + } else { // UU + MaxVectorSize or LL + element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v2, v4, v2, encLL, DIFFERENCE, Assembler::m2); + } + j(DONE); } else { // LU or UL Register strL = encLU ? str1 : str2; diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 9988b98fa2c4d..07041fe085006 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -37,7 +37,7 @@ Register tmp1, Register tmp2, VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, - bool is_latin, Label& DONE); + bool is_latin, Label& DONE, Assembler::LMUL lmul); void compress_bits_v(Register dst, Register src, Register mask, bool is_long); void expand_bits_v(Register dst, Register src, Register mask, bool is_long); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 841e8cb260cb8..1a51d7583c9dd 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -3605,14 +3605,37 @@ instruct varray_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, ins_pipe(pipe_class_memory); %} +instruct vstring_compareU_128b(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, vReg_V4 v4, vReg_V5 v5, vReg_V6 v6, vReg_V7 v7, + vReg_V8 v8, vReg_V9 v9, vReg_V10 v10, vReg_V11 v11, + iRegP_R28 tmp1, iRegL_R29 tmp2) +%{ + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU && + MaxVectorSize == 16); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, + TEMP v4, TEMP v5, TEMP v6, TEMP v7, TEMP v8, TEMP v9, TEMP v10, TEMP v11); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareU" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_compare_v($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, + StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_memory); +%} + instruct vstring_compareU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, iRegI_R10 result, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, iRegP_R28 tmp1, iRegL_R29 tmp2) %{ - predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU); + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU && + MaxVectorSize > 16); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, - TEMP v2, TEMP v3, TEMP v4, TEMP v5); + TEMP v2, TEMP v3, TEMP v4, TEMP v5); format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareU" %} ins_encode %{ @@ -3624,6 +3647,7 @@ instruct vstring_compareU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_ %} ins_pipe(pipe_class_memory); %} + instruct vstring_compareL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, iRegI_R10 result, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, iRegP_R28 tmp1, iRegL_R29 tmp2) @@ -3631,7 +3655,7 @@ instruct vstring_compareL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_ predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, - TEMP v2, TEMP v3, TEMP v4, TEMP v5); + TEMP v2, TEMP v3, TEMP v4, TEMP v5); format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareL" %} ins_encode %{ From 9a91865ff38f6fbb48b9aba5028e0b529d9bce76 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Jul 2024 16:29:52 +0000 Subject: [PATCH 150/288] 8335395: G1: Verification does not detect references into Free regions Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp | 1 + src/hotspot/share/gc/g1/g1HeapRegion.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 49f1c82a98ab0..63eceb4a5baa5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -253,6 +253,7 @@ inline bool G1CollectedHeap::is_obj_filler(const oop obj) { } inline bool G1CollectedHeap::is_obj_dead(const oop obj, const G1HeapRegion* hr) const { + assert(!hr->is_free(), "looking up obj " PTR_FORMAT " in Free region %u", p2i(obj), hr->hrm_index()); if (hr->is_in_parsable_area(obj)) { // This object is in the parsable part of the heap, live unless scrubbed. return is_obj_filler(obj); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 94382a3b256d1..d611cf7f947ff 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -547,7 +547,10 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { } bool failed() const { - return !_is_in_heap || this->_g1h->is_obj_dead_cond(this->_obj, _vo); + return !_is_in_heap || + // is_obj_dead* assume that obj is not in a Free region. + this->_g1h->heap_region_containing(this->_obj)->is_free() || + this->_g1h->is_obj_dead_cond(this->_obj, _vo); } void report_error() { From 68ffec9800b798927a050900a2d47000aa18ef30 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 3 Jul 2024 20:43:08 +0000 Subject: [PATCH 151/288] 8335479: JFR: Missing documentation for -XX:StartFlightRecording Reviewed-by: mgronlun --- src/java.base/share/man/java.1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 839d46e122833..133710abc25db 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -1710,10 +1710,12 @@ This prevents the JVM from exiting and keeps the process active so that you can attach a debugger to it to investigate the cause of the error. By default, this option is disabled. .TP -\f[V]-XX:StartFlightRecording=\f[R]\f[I]parameter\f[R]\f[V]=\f[R]\f[I]value\f[R] +\f[V]-XX:StartFlightRecording:\f[R]\f[I]parameter\f[R]\f[V]=\f[R]\f[I]value\f[R] Starts a JFR recording for the Java application. This option is equivalent to the \f[V]JFR.start\f[R] diagnostic command that starts a recording during runtime. +\f[V]-XX:StartFlightRecording:help\f[R] prints available options and +example command lines. You can set the following \f[I]parameter\f[R]\f[V]=\f[R]\f[I]value\f[R] entries when starting a JFR recording: .RS @@ -1760,6 +1762,8 @@ written when the recording is stopped, for example: .PP If %p and/or %t is specified in the filename, it expands to the JVM\[aq]s PID and the current timestamp, respectively. +The filename may also be a directory in which case, the filename is +generated from the PID and the current date in the specified directory. .RE .TP \f[V]name=\f[R]\f[I]identifier\f[R] @@ -1840,6 +1844,9 @@ The whitespace delimiter can be omitted for timespan values, i.e. 20ms. For more information about the settings syntax, see Javadoc of the jdk.jfr package. +.PP +To only see warnings and errors from JFR during startup set +-Xlog:jfr+startup=warning. .RE .TP \f[V]-XX:ThreadStackSize=\f[R]\f[I]size\f[R] From 587535c5b9bb258836b47c3a8c41ffb91bbfc131 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 3 Jul 2024 21:42:08 +0000 Subject: [PATCH 152/288] 8334545: runtime/ClassInitErrors/TestStackOverflowDuringInit.java fails after JDK-8294960 Reviewed-by: iklam, stuefe --- test/hotspot/jtreg/ProblemList.txt | 1 - .../TestStackOverflowDuringInit.java | 49 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index c55790de5ca58..d7088408ab887 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -108,7 +108,6 @@ runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/cds/appcds/customLoader/HelloCustom_JFR.java 8241075 linux-all,windows-x64 -runtime/ClassInitErrors/TestStackOverflowDuringInit.java 8334545 generic-all applications/jcstress/copy.java 8229852 linux-all diff --git a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java index 43a9985d8357f..3917abe85ad57 100644 --- a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java +++ b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * 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,16 +23,15 @@ /** * @test - * @bug 8309034 + * @bug 8309034 8334545 * @summary Test that when saving a class initialization failure caused by * a StackOverflowError, that we record the SOE as the underlying * cause, even if we can't create the ExceptionInInitializerError - * @requires os.simpleArch == "x64" - * @comment The reproducer only fails in the desired way on x64. - * @requires vm.flagless * @comment This test could easily be perturbed so don't allow flag settings. - * - * @run main/othervm -Xss160K -Xint TestStackOverflowDuringInit + * @requires vm.flagless + * @comment Run with the smallest stack possible to limit the execution time. + * This is the smallest stack that is supported by all platforms. + * @run main/othervm -Xss240K -Xint TestStackOverflowDuringInit */ import java.io.ByteArrayOutputStream; @@ -51,11 +50,33 @@ public class TestStackOverflowDuringInit { // of another class, which is where we will fail to create the EIIE. // Even then this is non-trivial, only the use of Long.valueOf from // the original reproducer seems to trigger SOE in just the right places. + // Later changes to the JDK meant that LongCache was initialized before + // the test even started under jtreg so we define local versions. + + static class LongCache { + // Must have a static initializer + static { + System.out.println("LongCache is initializing"); + } + static java.lang.Long valueOf(long l) { + return Long.valueOf(l); + } + } + + static class MyLong { + static java.lang.Long valueOf(long l) { + if (l > -128 && l < 127) { + return LongCache.valueOf(l); + } else { + return Long.valueOf(l); + } + } + } static void recurse() { try { - // This will initialize Long but not touch LongCache. - Long.valueOf(1024L); + // This will initialize MyLong but not touch LongCache. + MyLong.valueOf(1024L); recurse(); } finally { // This will require initializing LongCache, which will @@ -63,14 +84,20 @@ static void recurse() { // will be marked erroneous. As we unwind and again execute this // we will throw NoClassDefFoundError due to the erroneous // state of LongCache. - Long.valueOf(0); + MyLong.valueOf(0); } } public static void main(String[] args) throws Exception { - String expected = "java.lang.NoClassDefFoundError: Could not initialize class java.lang.Long$LongCache"; + String expected = "java.lang.NoClassDefFoundError: Could not initialize class TestStackOverflowDuringInit$LongCache"; String cause = "Caused by: java.lang.StackOverflowError"; + // Pre-load, but not initialize, LongCache, else we will + // hit SOE during class loading. + System.out.println("Pre-loading ..."); + Class c = Class.forName("TestStackOverflowDuringInit$LongCache", + false, + TestStackOverflowDuringInit.class.getClassLoader()); try { recurse(); } catch (Throwable ex) { From 3efa93ba1307cedf05609c0c04b2ba986a515f6e Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 3 Jul 2024 22:03:23 +0000 Subject: [PATCH 153/288] 8335588: Fix -Wzero-as-null-pointer-constant warnings in calls to Node ctor Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/addnode.hpp | 4 ++-- src/hotspot/share/opto/convertnode.hpp | 4 ++-- src/hotspot/share/opto/countbitsnode.hpp | 4 ++-- src/hotspot/share/opto/intrinsicnode.hpp | 18 +++++++++--------- src/hotspot/share/opto/loopnode.hpp | 2 +- src/hotspot/share/opto/memnode.hpp | 2 +- src/hotspot/share/opto/movenode.hpp | 2 +- src/hotspot/share/opto/mulnode.hpp | 20 ++++++++++---------- src/hotspot/share/opto/opaquenode.hpp | 2 +- src/hotspot/share/opto/subnode.hpp | 10 +++++----- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index fd044d6eead63..8879606954a52 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -43,7 +43,7 @@ typedef const Pair ConstAddOperands; class AddNode : public Node { virtual uint hash() const; public: - AddNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + AddNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { init_class_id(Class_Add); } @@ -165,7 +165,7 @@ class AddPNode : public Node { Base, // Base oop, for GC purposes Address, // Actually address, derived from base Offset } ; // Offset added to address - AddPNode( Node *base, Node *ptr, Node *off ) : Node(0,base,ptr,off) { + AddPNode( Node *base, Node *ptr, Node *off ) : Node(nullptr,base,ptr,off) { init_class_id(Class_AddP); } virtual int Opcode() const; diff --git a/src/hotspot/share/opto/convertnode.hpp b/src/hotspot/share/opto/convertnode.hpp index cf76f5ab6fde2..9438176a9f996 100644 --- a/src/hotspot/share/opto/convertnode.hpp +++ b/src/hotspot/share/opto/convertnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,7 +260,7 @@ class RoundDoubleModeNode: public Node { rmode_floor = 1, rmode_ceil = 2 }; - RoundDoubleModeNode(Node *in1, Node * rmode): Node(0, in1, rmode) {} + RoundDoubleModeNode(Node *in1, Node * rmode): Node(nullptr, in1, rmode) {} static RoundDoubleModeNode* make(PhaseGVN& gvn, Node* arg, RoundDoubleModeNode::RoundingMode rmode); virtual int Opcode() const; virtual const Type *bottom_type() const { return Type::DOUBLE; } diff --git a/src/hotspot/share/opto/countbitsnode.hpp b/src/hotspot/share/opto/countbitsnode.hpp index b0703d33326c9..410d51298829b 100644 --- a/src/hotspot/share/opto/countbitsnode.hpp +++ b/src/hotspot/share/opto/countbitsnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ class PhaseTransform; //---------- CountBitsNode ----------------------------------------------------- class CountBitsNode : public Node { public: - CountBitsNode(Node* in1) : Node(0, in1) {} + CountBitsNode(Node* in1) : Node(nullptr, in1) {} const Type* bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } }; diff --git a/src/hotspot/share/opto/intrinsicnode.hpp b/src/hotspot/share/opto/intrinsicnode.hpp index e8ebad788eb21..bfb200b5e9695 100644 --- a/src/hotspot/share/opto/intrinsicnode.hpp +++ b/src/hotspot/share/opto/intrinsicnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,7 +239,7 @@ class WhitespaceNode : public Node { //------------------------------CopySign----------------------------------------- class CopySignDNode : public Node { protected: - CopySignDNode(Node* in1, Node* in2, Node* in3) : Node(0, in1, in2, in3) {} + CopySignDNode(Node* in1, Node* in2, Node* in3) : Node(nullptr, in1, in2, in3) {} public: static CopySignDNode* make(PhaseGVN& gvn, Node* in1, Node* in2); virtual int Opcode() const; @@ -249,7 +249,7 @@ class CopySignDNode : public Node { class CopySignFNode : public Node { public: - CopySignFNode(Node* in1, Node* in2) : Node(0, in1, in2) {} + CopySignFNode(Node* in1, Node* in2) : Node(nullptr, in1, in2) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeLong::FLOAT; } virtual uint ideal_reg() const { return Op_RegF; } @@ -258,7 +258,7 @@ class CopySignFNode : public Node { //------------------------------Signum------------------------------------------- class SignumDNode : public Node { protected: - SignumDNode(Node* in1, Node* in2, Node* in3) : Node(0, in1, in2, in3) {} + SignumDNode(Node* in1, Node* in2, Node* in3) : Node(nullptr, in1, in2, in3) {} public: static SignumDNode* make(PhaseGVN& gvn, Node* in); virtual int Opcode() const; @@ -268,7 +268,7 @@ class SignumDNode : public Node { class SignumFNode : public Node { protected: - SignumFNode(Node* in1, Node* in2, Node* in3) : Node(0, in1, in2, in3) {} + SignumFNode(Node* in1, Node* in2, Node* in3) : Node(nullptr, in1, in2, in3) {} public: static SignumFNode* make(PhaseGVN& gvn, Node* in); virtual int Opcode() const; @@ -306,7 +306,7 @@ class ExpandBitsNode : public TypeNode { //---------- IsInfiniteFNode ----------------------------------------------------- class IsInfiniteFNode : public Node { public: - IsInfiniteFNode(Node* in1) : Node(0, in1) {} + IsInfiniteFNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } @@ -315,7 +315,7 @@ class IsInfiniteFNode : public Node { //---------- IsInfiniteDNode ----------------------------------------------------- class IsInfiniteDNode : public Node { public: - IsInfiniteDNode(Node* in1) : Node(0, in1) {} + IsInfiniteDNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } @@ -324,7 +324,7 @@ class IsInfiniteDNode : public Node { //---------- IsFiniteFNode ----------------------------------------------------- class IsFiniteFNode : public Node { public: - IsFiniteFNode(Node* in1) : Node(0, in1) {} + IsFiniteFNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } @@ -333,7 +333,7 @@ class IsFiniteFNode : public Node { //---------- IsFiniteDNode ----------------------------------------------------- class IsFiniteDNode : public Node { public: - IsFiniteDNode(Node* in1) : Node(0, in1) {} + IsFiniteDNode(Node* in1) : Node(nullptr, in1) {} virtual int Opcode() const; const Type* bottom_type() const { return TypeInt::BOOL; } virtual uint ideal_reg() const { return Op_RegI; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 448c29b6976bb..7d78bf5021c22 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -514,7 +514,7 @@ inline jlong BaseCountedLoopNode::stride_con() const { class LoopLimitNode : public Node { enum { Init=1, Limit=2, Stride=3 }; public: - LoopLimitNode( Compile* C, Node *init, Node *limit, Node *stride ) : Node(0,init,limit,stride) { + LoopLimitNode( Compile* C, Node *init, Node *limit, Node *stride ) : Node(nullptr,init,limit,stride) { // Put it on the Macro nodes list to optimize during macro nodes expansion. init_flags(Flag_is_macro); C->add_macro_node(this); diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index e0f5a4374133a..1b65585f1a006 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -1681,7 +1681,7 @@ class CacheWBPostSyncNode : public Node { // Allocation prefetch which may fault, TLAB size have to be adjusted. class PrefetchAllocationNode : public Node { public: - PrefetchAllocationNode(Node *mem, Node *adr) : Node(0,mem,adr) {} + PrefetchAllocationNode(Node *mem, Node *adr) : Node(nullptr,mem,adr) {} virtual int Opcode() const; virtual uint ideal_reg() const { return NotAMachineReg; } virtual uint match_edge(uint idx) const { return idx==2; } diff --git a/src/hotspot/share/opto/movenode.hpp b/src/hotspot/share/opto/movenode.hpp index ae1e8563da368..02db0c73079f8 100644 --- a/src/hotspot/share/opto/movenode.hpp +++ b/src/hotspot/share/opto/movenode.hpp @@ -158,7 +158,7 @@ class MoveD2LNode : public MoveNode { // (CMove (Binary bol cmp) (Binary src1 src2)) class BinaryNode : public Node { public: - BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { } + BinaryNode( Node *n1, Node *n2 ) : Node(nullptr,n1,n2) { } virtual int Opcode() const; virtual uint ideal_reg() const { return 0; } }; diff --git a/src/hotspot/share/opto/mulnode.hpp b/src/hotspot/share/opto/mulnode.hpp index 10ef442299d87..4c5e3e33248da 100644 --- a/src/hotspot/share/opto/mulnode.hpp +++ b/src/hotspot/share/opto/mulnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,7 +167,7 @@ const Type* MulHiValue(const Type *t1, const Type *t2, const Type *bot); // Upper 64 bits of a 64 bit by 64 bit multiply class MulHiLNode : public Node { public: - MulHiLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + MulHiLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual const Type* Value(PhaseGVN* phase) const; const Type *bottom_type() const { return TypeLong::LONG; } @@ -178,7 +178,7 @@ class MulHiLNode : public Node { // Upper 64 bits of a 64 bit by 64 bit unsigned multiply class UMulHiLNode : public Node { public: - UMulHiLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + UMulHiLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual const Type* Value(PhaseGVN* phase) const; const Type *bottom_type() const { return TypeLong::LONG; } @@ -291,7 +291,7 @@ class RotateRightNode : public TypeNode { // Signed shift right class RShiftINode : public Node { public: - RShiftINode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + RShiftINode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -304,7 +304,7 @@ class RShiftINode : public Node { // Signed shift right class RShiftLNode : public Node { public: - RShiftLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + RShiftLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual const Type* Value(PhaseGVN* phase) const; @@ -316,7 +316,7 @@ class RShiftLNode : public Node { // Logical shift right class URShiftBNode : public Node { public: - URShiftBNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + URShiftBNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { ShouldNotReachHere(); // only vector variant is used } virtual int Opcode() const; @@ -326,7 +326,7 @@ class URShiftBNode : public Node { // Logical shift right class URShiftSNode : public Node { public: - URShiftSNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + URShiftSNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { ShouldNotReachHere(); // only vector variant is used } virtual int Opcode() const; @@ -336,7 +336,7 @@ class URShiftSNode : public Node { // Logical shift right class URShiftINode : public Node { public: - URShiftINode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + URShiftINode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -349,7 +349,7 @@ class URShiftINode : public Node { // Logical shift right class URShiftLNode : public Node { public: - URShiftLNode( Node *in1, Node *in2 ) : Node(0,in1,in2) {} + URShiftLNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {} virtual int Opcode() const; virtual Node* Identity(PhaseGVN* phase); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -396,7 +396,7 @@ class FmaFNode : public FmaNode { class MulAddS2INode : public Node { virtual uint hash() const; public: - MulAddS2INode(Node* in1, Node *in2, Node *in3, Node* in4) : Node(0, in1, in2, in3, in4) {} + MulAddS2INode(Node* in1, Node *in2, Node *in3, Node* in4) : Node(nullptr, in1, in2, in3, in4) {} virtual int Opcode() const; const Type *bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index 4617979c2e494..9c775408cc0cd 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -140,7 +140,7 @@ class ProfileBooleanNode : public Node { virtual uint hash() const ; // { return NO_HASH; } virtual bool cmp( const Node &n ) const; public: - ProfileBooleanNode(Node *n, uint false_cnt, uint true_cnt) : Node(0, n), + ProfileBooleanNode(Node *n, uint false_cnt, uint true_cnt) : Node(nullptr, n), _false_cnt(false_cnt), _true_cnt(true_cnt), _consumed(false), _delay_removal(true) {} uint false_count() const { return _false_cnt; } diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index f424e258db2cf..a0c052645c69c 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ // are compressed into -1, and all positive answers compressed to 1. class SubNode : public Node { public: - SubNode( Node *in1, Node *in2 ) : Node(0,in1,in2) { + SubNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) { init_class_id(Class_Sub); } @@ -363,7 +363,7 @@ class BoolNode : public Node { // for finding this pattern in the graph. class AbsNode : public Node { public: - AbsNode( Node *value ) : Node(0,value) {} + AbsNode( Node *value ) : Node(nullptr,value) {} virtual Node* Identity(PhaseGVN* phase); virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); virtual const Type* Value(PhaseGVN* phase) const; @@ -420,7 +420,7 @@ class AbsDNode : public AbsNode { // If p < q, return -1 else return 0. Nice for flow-free idioms. class CmpLTMaskNode : public Node { public: - CmpLTMaskNode( Node *p, Node *q ) : Node(0, p, q) {} + CmpLTMaskNode( Node *p, Node *q ) : Node(nullptr, p, q) {} virtual int Opcode() const; const Type *bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } @@ -430,7 +430,7 @@ class CmpLTMaskNode : public Node { //------------------------------NegNode---------------------------------------- class NegNode : public Node { public: - NegNode(Node* in1) : Node(0, in1) { + NegNode(Node* in1) : Node(nullptr, in1) { init_class_id(Class_Neg); } }; From e01626cf09850f7b0af33cdb905ca8992266fe5b Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 4 Jul 2024 04:18:31 +0000 Subject: [PATCH 154/288] 8335655: ProblemList serviceability/dcmd/vm tests failing after JDK-8322475 Reviewed-by: mikael --- test/hotspot/jtreg/ProblemList-generational-zgc.txt | 3 +++ test/hotspot/jtreg/ProblemList-zgc.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index db8182641ac54..bdeed9947c571 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -114,4 +114,7 @@ serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic- serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all +serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all +serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all + vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 1afe56c99f8af..892c980b0696d 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -45,4 +45,7 @@ serviceability/sa/TestSysProps.java 8302055 generic- serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all +serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all +serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all + vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 From 7b894bc4afa96bc04f0d58042f69becadb573e20 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 4 Jul 2024 05:44:44 +0000 Subject: [PATCH 155/288] 8332786: When dumping static CDS archives, explicitly assert that we don't use a CDS archive Reviewed-by: iklam, dholmes --- src/hotspot/share/cds/metaspaceShared.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index a5061fef567e3..4d978a7ad880f 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -510,6 +510,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { } void VM_PopulateDumpSharedSpace::doit() { + guarantee(!CDSConfig::is_using_archive(), "We should not be using an archive when we dump"); + DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); FileMapInfo::check_nonempty_dir_in_shared_path_table(); From 38a578d547f39c3637d97f5e0242f4a69f3bbb31 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 4 Jul 2024 06:20:03 +0000 Subject: [PATCH 156/288] 8334738: os::print_hex_dump should optionally print ASCII Reviewed-by: dholmes, sgehwolf --- .../windows_aarch64/os_windows_aarch64.cpp | 4 +- src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 89 ++++++++---- src/hotspot/share/runtime/os.hpp | 8 +- .../share/utilities/globalDefinitions.hpp | 1 + src/hotspot/share/utilities/ostream.hpp | 1 + test/hotspot/gtest/runtime/test_os.cpp | 131 ++++++++++-------- 7 files changed, 144 insertions(+), 92 deletions(-) diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp index 78e98609b6bdc..722c3c8dd608d 100644 --- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, Microsoft Corporation. All rights reserved. - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,7 +219,7 @@ void os::print_tos_pc(outputStream *st, const void *context) { // this at the end, and hope for the best. address pc = (address)uc->Pc; st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char), /* print_ascii=*/false); st->cr(); } diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index a87a3ff042dec..fdbb6605c13e9 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1273,7 +1273,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { // longs and doubles will be split into two words. unitsize = sizeof(narrowOop); } - os::print_hex_dump(&lsh, base, top, unitsize, 32, requested_base); + os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base); } } diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 97bf33fbaaa7c..d141ee244262b 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -938,56 +938,73 @@ bool os::print_function_and_library_name(outputStream* st, return have_function_name || have_library_name; } -ATTRIBUTE_NO_ASAN static bool read_safely_from(intptr_t* p, intptr_t* result) { - const intptr_t errval = 0x1717; - intptr_t i = SafeFetchN(p, errval); +ATTRIBUTE_NO_ASAN static bool read_safely_from(const uintptr_t* p, uintptr_t* result) { + DEBUG_ONLY(*result = 0xAAAA;) + const uintptr_t errval = 0x1717; + uintptr_t i = (uintptr_t)SafeFetchN((intptr_t*)p, errval); if (i == errval) { - i = SafeFetchN(p, ~errval); + i = (uintptr_t)SafeFetchN((intptr_t*)p, ~errval); if (i == ~errval) { return false; } } - (*result) = i; + (*result) = (uintptr_t)i; return true; } -static void print_hex_location(outputStream* st, address p, int unitsize) { +// Helper for os::print_hex_dump +static void print_ascii_form(stringStream& ascii_form, uint64_t value, int unitsize) { + union { + uint64_t v; + uint8_t c[sizeof(v)]; + } u = { value }; + for (int i = 0; i < unitsize; i++) { + const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - 1 - i); + const uint8_t c = u.c[idx]; + ascii_form.put(isprint(c) && isascii(c) ? c : '.'); + } +} + +// Helper for os::print_hex_dump +static void print_hex_location(outputStream* st, const_address p, int unitsize, stringStream& ascii_form) { assert(is_aligned(p, unitsize), "Unaligned"); - address pa = align_down(p, sizeof(intptr_t)); + const uintptr_t* pa = (const uintptr_t*) align_down(p, sizeof(intptr_t)); #ifndef _LP64 // Special handling for printing qwords on 32-bit platforms if (unitsize == 8) { - intptr_t i1, i2; - if (read_safely_from((intptr_t*)pa, &i1) && - read_safely_from((intptr_t*)pa + 1, &i2)) { + uintptr_t i1 = 0, i2 = 0; + if (read_safely_from(pa, &i1) && + read_safely_from(pa + 1, &i2)) { const uint64_t value = LITTLE_ENDIAN_ONLY((((uint64_t)i2) << 32) | i1) BIG_ENDIAN_ONLY((((uint64_t)i1) << 32) | i2); st->print("%016" FORMAT64_MODIFIER "x", value); + print_ascii_form(ascii_form, value, unitsize); } else { st->print_raw("????????????????"); } return; } #endif // 32-bit, qwords - intptr_t i = 0; - if (read_safely_from((intptr_t*)pa, &i)) { + uintptr_t i = 0; + if (read_safely_from(pa, &i)) { // bytes: CA FE BA BE DE AD C0 DE // bytoff: 0 1 2 3 4 5 6 7 // LE bits: 0 8 16 24 32 40 48 56 // BE bits: 56 48 40 32 24 16 8 0 - const int offset = (int)(p - (address)pa); + const int offset = (int)(p - (const_address)pa); const int bitoffset = LITTLE_ENDIAN_ONLY(offset * BitsPerByte) BIG_ENDIAN_ONLY((int)((sizeof(intptr_t) - unitsize - offset) * BitsPerByte)); const int bitfieldsize = unitsize * BitsPerByte; - intptr_t value = bitfield(i, bitoffset, bitfieldsize); + uintptr_t value = bitfield(i, bitoffset, bitfieldsize); switch (unitsize) { case 1: st->print("%02x", (u1)value); break; case 2: st->print("%04x", (u2)value); break; case 4: st->print("%08x", (u4)value); break; case 8: st->print("%016" FORMAT64_MODIFIER "x", (u8)value); break; } + print_ascii_form(ascii_form, value, unitsize); } else { switch (unitsize) { case 1: st->print_raw("??"); break; @@ -998,36 +1015,56 @@ static void print_hex_location(outputStream* st, address p, int unitsize) { } } -void os::print_hex_dump(outputStream* st, address start, address end, int unitsize, - int bytes_per_line, address logical_start) { +void os::print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, + bool print_ascii, int bytes_per_line, const_address logical_start) { + constexpr int max_bytes_per_line = 64; assert(unitsize == 1 || unitsize == 2 || unitsize == 4 || unitsize == 8, "just checking"); + assert(bytes_per_line > 0 && bytes_per_line <= max_bytes_per_line && + is_power_of_2(bytes_per_line), "invalid bytes_per_line"); start = align_down(start, unitsize); logical_start = align_down(logical_start, unitsize); bytes_per_line = align_up(bytes_per_line, 8); int cols = 0; - int cols_per_line = bytes_per_line / unitsize; + const int cols_per_line = bytes_per_line / unitsize; - address p = start; - address logical_p = logical_start; + const_address p = start; + const_address logical_p = logical_start; + + stringStream ascii_form; // Print out the addresses as if we were starting from logical_start. - st->print(PTR_FORMAT ": ", p2i(logical_p)); while (p < end) { - print_hex_location(st, p, unitsize); + if (cols == 0) { + st->print(PTR_FORMAT ": ", p2i(logical_p)); + } + print_hex_location(st, p, unitsize, ascii_form); p += unitsize; logical_p += unitsize; cols++; - if (cols >= cols_per_line && p < end) { - cols = 0; + if (cols >= cols_per_line) { + if (print_ascii && !ascii_form.is_empty()) { + st->print(" %s", ascii_form.base()); + } + ascii_form.reset(); st->cr(); - st->print(PTR_FORMAT ": ", p2i(logical_p)); + cols = 0; } else { st->print(" "); } } - st->cr(); + + if (cols > 0) { // did not print a full line + if (print_ascii) { + // indent last ascii part to match that of full lines + const int size_of_printed_unit = unitsize * 2; + const int space_left = (cols_per_line - cols) * (size_of_printed_unit + 1); + st->sp(space_left); + st->print(" %s", ascii_form.base()); + } + st->cr(); + } } void os::print_dhm(outputStream* st, const char* startStr, long sec) { @@ -1045,7 +1082,7 @@ void os::print_tos(outputStream* st, address sp) { void os::print_instructions(outputStream* st, address pc, int unitsize) { st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc)); - print_hex_dump(st, pc - 256, pc + 256, unitsize); + print_hex_dump(st, pc - 256, pc + 256, unitsize, /* print_ascii=*/false); } void os::print_environment_variables(outputStream* st, const char** env_list) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index f3f44ddb2e659..af8eb8c8b9a13 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -856,10 +856,10 @@ class os: AllStatic { // return current frame. pc() and sp() are set to null on failure. static frame current_frame(); - static void print_hex_dump(outputStream* st, address start, address end, int unitsize, - int bytes_per_line, address logical_start); - static void print_hex_dump(outputStream* st, address start, address end, int unitsize) { - print_hex_dump(st, start, end, unitsize, /*bytes_per_line=*/16, /*logical_start=*/start); + static void print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, bool print_ascii, + int bytes_per_line, const_address logical_start); + static void print_hex_dump(outputStream* st, const_address start, const_address end, int unitsize, bool print_ascii = true) { + print_hex_dump(st, start, end, unitsize, print_ascii, /*bytes_per_line=*/16, /*logical_start=*/start); } // returns a string to describe the exception/signal; diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index a15a4de3e93dc..74817a35e7706 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -455,6 +455,7 @@ typedef unsigned int uint; NEEDS_CLEANUP typedef signed char s_char; typedef unsigned char u_char; typedef u_char* address; +typedef const u_char* const_address; // Pointer subtraction. // The idea here is to avoid ptrdiff_t, which is signed and so doesn't have diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index beb02309d3f23..9faaf32fb6bc1 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -267,6 +267,7 @@ class stringStream : public outputStream { return _buffer; }; void reset(); + bool is_empty() const { return _buffer[0] == '\0'; } // Copy to a resource, or C-heap, array as requested char* as_string(bool c_heap = false) const; }; diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 55d30349ee5a9..654c2c60673ba 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -167,82 +167,95 @@ TEST_VM_ASSERT_MSG(os, page_size_for_region_with_zero_min_pages, } #endif -static void do_test_print_hex_dump(address addr, size_t len, int unitsize, const char* expected) { - char buf[256]; +#ifndef AIX +// Test relies on the ability to protect memory allocated with os::reserve_memory. AIX may not be able +// to do that (mprotect won't work on System V shm). +static void do_test_print_hex_dump(const_address from, const_address to, int unitsize, int bytes_per_line, + const_address logical_start, const char* expected) { + char buf[2048]; buf[0] = '\0'; stringStream ss(buf, sizeof(buf)); - os::print_hex_dump(&ss, addr, addr + len, unitsize); - // tty->print_cr("expected: %s", expected); - // tty->print_cr("result: %s", buf); - EXPECT_THAT(buf, HasSubstr(expected)); + os::print_hex_dump(&ss, from, to, unitsize, /* print_ascii=*/true, bytes_per_line, logical_start); + EXPECT_STREQ(buf, expected); } TEST_VM(os, test_print_hex_dump) { - const char* pattern [4] = { -#ifdef VM_LITTLE_ENDIAN - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", - "0100 0302 0504 0706 0908 0b0a 0d0c 0f0e", - "03020100 07060504 0b0a0908 0f0e0d0c", - "0706050403020100 0f0e0d0c0b0a0908" + +#ifdef _LP64 +#define ADDRESS1 "0x0000aaaaaaaaaa00" +#define ADDRESS2 "0x0000aaaaaaaaaa20" +#define ADDRESS3 "0x0000aaaaaaaaaa40" #else - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", - "0001 0203 0405 0607 0809 0a0b 0c0d 0e0f", - "00010203 04050607 08090a0b 0c0d0e0f", - "0001020304050607 08090a0b0c0d0e0f" +#define ADDRESS1 "0xaaaaaa00" +#define ADDRESS2 "0xaaaaaa20" +#define ADDRESS3 "0xaaaaaa40" #endif - }; - const char* pattern_not_readable [4] = { - "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??", - "???? ???? ???? ???? ???? ???? ???? ????", - "???????? ???????? ???????? ????????", - "???????????????? ????????????????" - }; +#define ASCII_1 "....#.jdk/internal/loader/Native" +#define ASCII_2 "Libraries......." - // On AIX, zero page is readable. - address unreadable = -#ifdef AIX - (address) 0xFFFFFFFFFFFF0000ULL; +#define PAT_1 ADDRESS1 ": ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??\n" \ + ADDRESS2 ": ff ff e0 dc 23 00 6a 64 6b 2f 69 6e 74 65 72 6e 61 6c 2f 6c 6f 61 64 65 72 2f 4e 61 74 69 76 65 " ASCII_1 "\n" \ + ADDRESS3 ": 4c 69 62 72 61 72 69 65 73 00 00 00 00 00 00 00 " ASCII_2 "\n" + +#ifdef VM_LITTLE_ENDIAN +#define PAT_2 ADDRESS1 ": ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ????\n" \ + ADDRESS2 ": ffff dce0 0023 646a 2f6b 6e69 6574 6e72 6c61 6c2f 616f 6564 2f72 614e 6974 6576 " ASCII_1 "\n" \ + ADDRESS3 ": 694c 7262 7261 6569 0073 0000 0000 0000 " ASCII_2 "\n" + +#define PAT_4 ADDRESS1 ": ???????? ???????? ???????? ???????? ???????? ???????? ???????? ????????\n" \ + ADDRESS2 ": dce0ffff 646a0023 6e692f6b 6e726574 6c2f6c61 6564616f 614e2f72 65766974 " ASCII_1 "\n" \ + ADDRESS3 ": 7262694c 65697261 00000073 00000000 " ASCII_2 "\n" + +#define PAT_8 ADDRESS1 ": ???????????????? ???????????????? ???????????????? ????????????????\n" \ + ADDRESS2 ": 646a0023dce0ffff 6e7265746e692f6b 6564616f6c2f6c61 65766974614e2f72 " ASCII_1 "\n" \ + ADDRESS3 ": 656972617262694c 0000000000000073 " ASCII_2 "\n" #else - (address) 0 -#endif - ; +#define PAT_2 ADDRESS1 ": ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ????\n" \ + ADDRESS2 ": ffff e0dc 2300 6a64 6b2f 696e 7465 726e 616c 2f6c 6f61 6465 722f 4e61 7469 7665 " ASCII_1 "\n" \ + ADDRESS3 ": 4c69 6272 6172 6965 7300 0000 0000 0000 " ASCII_2 "\n" - ResourceMark rm; - char buf[64]; - stringStream ss(buf, sizeof(buf)); - outputStream* out = &ss; -// outputStream* out = tty; // enable for printout - - // Test dumping unreadable memory - // Exclude test for Windows for now, since it needs SEH handling to work which cannot be - // guaranteed when we call directly into VM code. (see JDK-8220220) -#ifndef _WIN32 - do_test_print_hex_dump(unreadable, 100, 1, pattern_not_readable[0]); - do_test_print_hex_dump(unreadable, 100, 2, pattern_not_readable[1]); - do_test_print_hex_dump(unreadable, 100, 4, pattern_not_readable[2]); - do_test_print_hex_dump(unreadable, 100, 8, pattern_not_readable[3]); +#define PAT_4 ADDRESS1 ": ???????? ???????? ???????? ???????? ???????? ???????? ???????? ????????\n" \ + ADDRESS2 ": ffffe0dc 23006a64 6b2f696e 7465726e 616c2f6c 6f616465 722f4e61 74697665 " ASCII_1 "\n" \ + ADDRESS3 ": 4c696272 61726965 73000000 00000000 " ASCII_2 "\n" + +#define PAT_8 ADDRESS1 ": ???????????????? ???????????????? ???????????????? ????????????????\n" \ + ADDRESS2 ": ffffe0dc23006a64 6b2f696e7465726e 616c2f6c6f616465 722f4e6174697665 " ASCII_1 "\n" \ + ADDRESS3 ": 4c69627261726965 7300000000000000 " ASCII_2 "\n" #endif - // Test dumping readable memory - address arr = (address)os::malloc(100, mtInternal); - for (u1 c = 0; c < 100; c++) { - arr[c] = c; - } + constexpr uint8_t bytes[] = { + 0xff, 0xff, 0xe0, 0xdc, 0x23, 0x00, 0x6a, 0x64, 0x6b, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x2f, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // two pages, first one protected. + const size_t ps = os::vm_page_size(); + char* two_pages = os::reserve_memory(ps * 2, false, mtTest); + os::commit_memory(two_pages, ps * 2, false); + os::protect_memory(two_pages, ps, os::MEM_PROT_NONE, true); + + memcpy(two_pages + ps, bytes, sizeof(bytes)); + + // print + const const_address from = (const_address) two_pages + ps - 32; + const const_address to = (const_address) from + 32 + sizeof(bytes); + const const_address logical_start = (const_address) LP64_ONLY(0xAAAAAAAAAA00ULL) NOT_LP64(0xAAAAAA00ULL); - // properly aligned - do_test_print_hex_dump(arr, 100, 1, pattern[0]); - do_test_print_hex_dump(arr, 100, 2, pattern[1]); - do_test_print_hex_dump(arr, 100, 4, pattern[2]); - do_test_print_hex_dump(arr, 100, 8, pattern[3]); + do_test_print_hex_dump(from, to, 1, 32, logical_start, PAT_1); + do_test_print_hex_dump(from, to, 2, 32, logical_start, PAT_2); + do_test_print_hex_dump(from, to, 4, 32, logical_start, PAT_4); + do_test_print_hex_dump(from, to, 8, 32, logical_start, PAT_8); - // Not properly aligned. Should automatically down-align by unitsize - do_test_print_hex_dump(arr + 1, 100, 2, pattern[1]); - do_test_print_hex_dump(arr + 1, 100, 4, pattern[2]); - do_test_print_hex_dump(arr + 1, 100, 8, pattern[3]); + // unaligned printing, should align to next lower unitsize + do_test_print_hex_dump(from + 1, to, 2, 32, logical_start, PAT_2); + do_test_print_hex_dump(from + 1, to, 4, 32, logical_start, PAT_4); + do_test_print_hex_dump(from + 1, to, 8, 32, logical_start, PAT_8); - os::free(arr); + os::release_memory(two_pages, ps * 2); } +#endif // not AIX ////////////////////////////////////////////////////////////////////////////// // Test os::vsnprintf and friends. From b20e8c8e85e0a0e96ae648f42ff803f1c83f6291 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 4 Jul 2024 08:21:18 +0000 Subject: [PATCH 157/288] 8335397: Improve reliability of TestRecursiveMonitorChurn.java Reviewed-by: coleenp, rkennke, dholmes --- src/hotspot/share/prims/whitebox.cpp | 9 ++ src/hotspot/share/prims/whitebox.hpp | 1 + src/hotspot/share/runtime/synchronizer.hpp | 1 + .../locking/TestRecursiveMonitorChurn.java | 82 ++++++++----------- test/lib/jdk/test/whitebox/WhiteBox.java | 2 + 5 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5ed593b0d2f8e..c480f8a09ac1c 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1115,6 +1115,10 @@ bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThrea return false; } +size_t WhiteBox::get_in_use_monitor_count() { + return ObjectSynchronizer::_in_use_list.count(); +} + WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level, jint bci)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); @@ -1850,6 +1854,10 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj)) return (jboolean) obj_oop->mark().has_monitor(); WB_END +WB_ENTRY(jlong, WB_getInUseMonitorCount(JNIEnv* env, jobject wb)) + return (jlong) WhiteBox::get_in_use_monitor_count(); +WB_END + WB_ENTRY(jint, WB_getLockStackCapacity(JNIEnv* env)) return (jint) LockStack::CAPACITY; WB_END @@ -2844,6 +2852,7 @@ static JNINativeMethod methods[] = { (void*)&WB_AddModuleExportsToAll }, {CC"deflateIdleMonitors", CC"()Z", (void*)&WB_DeflateIdleMonitors }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, + {CC"getInUseMonitorCount", CC"()J", (void*)&WB_getInUseMonitorCount }, {CC"getLockStackCapacity", CC"()I", (void*)&WB_getLockStackCapacity }, {CC"supportsRecursiveLightweightLocking", CC"()Z", (void*)&WB_supportsRecursiveLightweightLocking }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, diff --git a/src/hotspot/share/prims/whitebox.hpp b/src/hotspot/share/prims/whitebox.hpp index a88f8d218439f..c5072b97d4f22 100644 --- a/src/hotspot/share/prims/whitebox.hpp +++ b/src/hotspot/share/prims/whitebox.hpp @@ -68,6 +68,7 @@ class WhiteBox : public AllStatic { JNINativeMethod* method_array, int method_count); static void register_extended(JNIEnv* env, jclass wbclass, JavaThread* thread); static bool compile_method(Method* method, int comp_level, int bci, JavaThread* THREAD); + static size_t get_in_use_monitor_count(); #ifdef LINUX static bool validate_cgroup(const char* proc_cgroups, const char* proc_self_cgroup, const char* proc_self_mountinfo, u1* cg_flags); #endif diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 7406af678e0e7..493303df66124 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -69,6 +69,7 @@ class MonitorList::Iterator { class ObjectSynchronizer : AllStatic { friend class VMStructs; friend class ObjectMonitorDeflationLogging; + friend class WhiteBox; public: typedef enum { diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java index 47cb561317196..19dd90015bf1c 100644 --- a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -21,19 +21,21 @@ * questions. */ -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /* * @test * @summary Tests that recursive locking doesn't cause excessive native memory usage * @library /test/lib - * @run driver TestRecursiveMonitorChurn + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xmx100M -XX:AsyncDeflationInterval=0 -XX:GuaranteedAsyncDeflationInterval=0 + * -Xlog:monitorinflation=trace + * TestRecursiveMonitorChurn */ + +import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; + public class TestRecursiveMonitorChurn { static class Monitor { public static volatile int i, j; @@ -46,50 +48,32 @@ synchronized void doSomethingElse() { } } - public static volatile Monitor monitor; - public static void main(String[] args) throws IOException { - if (args.length == 1 && args[0].equals("test")) { - // The actual test, in a forked JVM. - for (int i = 0; i < 100000; i++) { - monitor = new Monitor(); - monitor.doSomething(); - } - System.out.println("i + j = " + (Monitor.i + Monitor.j)); - } else { - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-Xmx100M", "-XX:AsyncDeflationInterval=0", "-XX:GuaranteedAsyncDeflationInterval=0", - "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics", - "TestRecursiveMonitorChurn", - "test"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.reportDiagnosticSummary(); - - output.shouldHaveExitValue(0); + static final WhiteBox WB = WhiteBox.getWhiteBox(); + static final int LM_MONITOR = 0; + static final int COUNT = 100000; - // We want to see, in the final NMT printout, a committed object monitor size that is reasonably low. - // Like this: - // - Object Monitors (reserved=208, committed=208) - // (malloc=208 #1) (at peak) - // - // Without recursive locking support, this would look more like this: - // - Object Monitors (reserved=20800624, committed=20800624) - // (malloc=20800624 #100003) (at peak) + public static volatile Monitor monitor; + public static void main(String[] args) { + if (WB.getIntVMFlag("LockingMode") == LM_MONITOR) { + throw new SkippedException("LM_MONITOR always inflates. Invalid test."); + } + final long pre_monitor_count = WB.getInUseMonitorCount(); + System.out.println(" Precount = " + pre_monitor_count); + for (int i = 0; i < COUNT; i++) { + monitor = new Monitor(); + monitor.doSomething(); + } + System.out.println("i + j = " + (Monitor.i + Monitor.j)); + final long post_monitor_count = WB.getInUseMonitorCount(); + System.out.println("Postcount = " + post_monitor_count); - Pattern pat = Pattern.compile("- *Object Monitors.*reserved=(\\d+), committed=(\\d+).*"); - for (String line : output.asLines()) { - Matcher m = pat.matcher(line); - if (m.matches()) { - long reserved = Long.parseLong(m.group(1)); - long committed = Long.parseLong(m.group(2)); - System.out.println(">>>>> " + line + ": " + reserved + " - " + committed); - if (committed > 1000) { - throw new RuntimeException("Allocated too many monitors"); - } - return; - } + if (pre_monitor_count != post_monitor_count) { + final long monitor_count_change = post_monitor_count - pre_monitor_count; + System.out.println("Unexpected change in monitor count: " + monitor_count_change); + if (monitor_count_change < 0) { + throw new RuntimeException("Unexpected Deflation"); } - throw new RuntimeException("Did not find expected NMT output"); + throw new RuntimeException("Unexpected Inflation"); } } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 3b930aec16f29..1bc309e2aecf8 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -119,6 +119,8 @@ public boolean isMonitorInflated(Object obj) { return isMonitorInflated0(obj); } + public native long getInUseMonitorCount(); + public native int getLockStackCapacity(); public native boolean supportsRecursiveLightweightLocking(); From 3e3f83f62c67caf960ca031439b022f915e1102a Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 4 Jul 2024 08:36:56 +0000 Subject: [PATCH 158/288] 8335385: javac crash on unattributed piece of AST Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Resolve.java | 18 +- .../importscope/BadClassFileDuringImport.java | 100 +++++++- ...utesFilledForReferencesOnMissingTypes.java | 227 ++++++++++++++++++ 3 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 test/langtools/tools/javac/tree/ASTAttributesFilledForReferencesOnMissingTypes.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 079a0bc5c6a46..643bb22c85358 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -2423,7 +2423,14 @@ Symbol findType(Env env, Name name) { * (a subset of VAL, TYP, PCK). */ Symbol findIdent(DiagnosticPosition pos, Env env, Name name, KindSelector kind) { - return checkNonExistentType(checkRestrictedType(pos, findIdentInternal(pos, env, name, kind), name)); + try { + return checkNonExistentType(checkRestrictedType(pos, findIdentInternal(pos, env, name, kind), name)); + } catch (ClassFinder.BadClassFile err) { + return new BadClassFileError(err); + } catch (CompletionFailure cf) { + chk.completionError(pos, cf); + return typeNotFound; + } } Symbol findIdentInternal(DiagnosticPosition pos, Env env, Name name, KindSelector kind) { @@ -2495,7 +2502,14 @@ Symbol findIdentInPackageInternal(Env env, TypeSymbol pck, Symbol findIdentInType(DiagnosticPosition pos, Env env, Type site, Name name, KindSelector kind) { - return checkNonExistentType(checkRestrictedType(pos, findIdentInTypeInternal(env, site, name, kind), name)); + try { + return checkNonExistentType(checkRestrictedType(pos, findIdentInTypeInternal(env, site, name, kind), name)); + } catch (ClassFinder.BadClassFile err) { + return new BadClassFileError(err); + } catch (CompletionFailure cf) { + chk.completionError(pos, cf); + return typeNotFound; + } } private Symbol checkNonExistentType(Symbol symbol) { diff --git a/test/langtools/tools/javac/importscope/BadClassFileDuringImport.java b/test/langtools/tools/javac/importscope/BadClassFileDuringImport.java index a4b751fea41ba..8d1d2a965130b 100644 --- a/test/langtools/tools/javac/importscope/BadClassFileDuringImport.java +++ b/test/langtools/tools/javac/importscope/BadClassFileDuringImport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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 8198378 + * @bug 8198378 8335385 * @summary Verify that BadClassFile related to imports are handled properly. * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -53,7 +53,9 @@ void run() throws Exception { new JavacTask(tb) .outdir(".") .sources("package p; public class A { }", - "package p; public class B { public static class I { } }") + "package p; public class B { public static class I { } }", + "package m; public class A { }", + "package m; public class B { public static class I { } }") .run() .writeAll(); @@ -65,80 +67,165 @@ void run() throws Exception { out.write("broken".getBytes("UTF-8")); } + Files.delete(Paths.get(".", "m", "A.class")); + Files.delete(Paths.get(".", "m", "B$I.class")); + doTest("import p.A;", "", "Test.java:2:9: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import m.A;", + "", + "Test.java:2:9: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.package, m, null)", + "1 error"); doTest("import p.A;", "A a;", "Test.java:2:9: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", "Test.java:2:33: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", "2 errors"); + doTest("import m.A;", + "A a;", + "Test.java:2:9: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.package, m, null)", + "Test.java:2:33: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); doTest("import p.A;", "void test() { A a; }", "Test.java:2:9: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", "Test.java:2:47: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", "2 errors"); + doTest("import m.A;", + "void test() { A a; }", + "Test.java:2:9: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.package, m, null)", + "Test.java:2:47: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); doTest("import p.*;", "", (String[]) null); + doTest("import m.*;", + "", + (String[]) null); doTest("import p.*;", "A a;", "Test.java:2:33: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import m.*;", + "A a;", + "Test.java:2:33: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", + "1 error"); doTest("import p.*;", "void test() { A a; }", "Test.java:2:47: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import m.*;", + "void test() { A a; }", + "Test.java:2:47: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", + "1 error"); doTest("import p.B.I;", "", "Test.java:2:11: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import m.B.I;", + "", + "Test.java:2:11: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "1 error"); doTest("import p.B.I;", "I i;", "Test.java:2:11: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", - "1 error"); + "Test.java:2:35: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); + doTest("import m.B.I;", + "I i;", + "Test.java:2:11: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "Test.java:2:35: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); doTest("import p.B.I;", "void test() { I i; }", "Test.java:2:11: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", - "1 error"); + "Test.java:2:49: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); + doTest("import m.B.I;", + "void test() { I i; }", + "Test.java:2:11: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "Test.java:2:49: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); doTest("import p.B.*;", "", (String[]) null); + doTest("import m.B.*;", + "", + (String[]) null); doTest("import p.B.*;", "I i;", "Test.java:2:35: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import m.B.*;", + "I i;", + "Test.java:2:35: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "1 error"); + doTest("import m.B.*;", + "I i;", + "Test.java:2:35: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "1 error"); doTest("import p.B.*;", "void test() { I i; }", "Test.java:2:49: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import m.B.*;", + "void test() { I i; }", + "Test.java:2:49: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "1 error"); doTest("import static p.B.I;", "", "Test.java:2:1: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import static m.B.I;", + "", + "Test.java:2:1: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "1 error"); doTest("import static p.B.I;", "I i;", "Test.java:2:42: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import static m.B.I;", + "I i;", + "Test.java:2:42: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "1 error"); doTest("import static p.B.I;", "void test() { I i; }", "Test.java:2:1: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import static m.B.I;", + "void test() { I i; }", + "Test.java:2:1: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "Test.java:2:56: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); doTest("import static p.B.*;", "", "Test.java:2:1: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import static m.B.*;", + "", + "Test.java:2:1: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "1 error"); doTest("import static p.B.*;", "I i;", "Test.java:2:42: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import static m.B.*;", + "I i;", + "Test.java:2:42: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "1 error"); doTest("import static p.B.*;", "void test() { I i; }", "Test.java:2:1: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", "1 error"); + doTest("import static m.B.*;", + "void test() { M m; }", + "Test.java:2:1: compiler.err.cant.access: m.B.I, (compiler.misc.class.file.not.found: m.B$I)", + "Test.java:2:56: compiler.err.cant.resolve.location: kindname.class, M, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); } void doTest(String importText, String useText, String... expectedOutput) { @@ -146,7 +233,8 @@ void doTest(String importText, String useText, String... expectedOutput) { .classpath(".") .sources("\n" + importText + " public class Test { " + useText + " }") .options("-XDrawDiagnostics") - .run(expectedOutput != null ? Task.Expect.FAIL : Task.Expect.SUCCESS) + .run(expectedOutput != null ? Task.Expect.FAIL : Task.Expect.SUCCESS, + expectedOutput != null ? 1 : 0) .writeAll() .getOutputLines(Task.OutputKind.DIRECT); diff --git a/test/langtools/tools/javac/tree/ASTAttributesFilledForReferencesOnMissingTypes.java b/test/langtools/tools/javac/tree/ASTAttributesFilledForReferencesOnMissingTypes.java new file mode 100644 index 0000000000000..908a3c24f7bd8 --- /dev/null +++ b/test/langtools/tools/javac/tree/ASTAttributesFilledForReferencesOnMissingTypes.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8335385 + * @summary Verify that BadClassFile related to imports are handled properly. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main ASTAttributesFilledForReferencesOnMissingTypes + */ + +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import javax.lang.model.element.Element; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class ASTAttributesFilledForReferencesOnMissingTypes { + public static void main(String... args) throws Exception { + new ASTAttributesFilledForReferencesOnMissingTypes().run(); + } + + ToolBox tb = new ToolBox(); + + void run() throws Exception { + new JavacTask(tb) + .outdir(".") + .sources("package p; public class A { }", + "package p; public class B { public static class I { } public static class M { } }", + "package p; public class C { }") + .run() + .writeAll(); + + try (OutputStream out = Files.newOutputStream(Paths.get(".", "p", "A.class"))) { + out.write("broken".getBytes("UTF-8")); + } + + try (OutputStream out = Files.newOutputStream(Paths.get(".", "p", "B$I.class"))) { + out.write("broken".getBytes("UTF-8")); + } + + Files.delete(Paths.get(".", "p", "C.class")); + Files.delete(Paths.get(".", "p", "B$M.class")); + + //tests for findIdent (must be in some global scope): + doTest(""" + package p; + public class Test { + A a; + } + """, + "Test.java:3:5: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", + "1 error"); + doTest(""" + import p.*; + public class Test { + A a; + } + """, + "Test.java:3:5: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", + "1 error"); + doTest(""" + package p; + public class Test { + C c; + } + """, + "Test.java:3:5: compiler.err.cant.resolve.location: kindname.class, C, , , (compiler.misc.location: kindname.class, p.Test, null)", + "1 error"); + doTest(""" + import p.*; + public class Test { + C c; + } + """, + "Test.java:3:5: compiler.err.cant.resolve.location: kindname.class, C, , , (compiler.misc.location: kindname.class, Test, null)", + "1 error"); + + //tests for findIdentInPackage: + doTest(""" + import p.A; + public class Test { + A a; + } + """, + "Test.java:1:9: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", + "Test.java:3:5: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); + doTest(""" + public class Test { + p.A a; + } + """, + "Test.java:2:6: compiler.err.cant.access: p.A, (compiler.misc.bad.class.file.header: A.class, (compiler.misc.illegal.start.of.class.file))", + "1 error"); + doTest(""" + import p.C; + public class Test { + C c; + } + """, + "Test.java:1:9: compiler.err.cant.resolve.location: kindname.class, C, , , (compiler.misc.location: kindname.package, p, null)", + "Test.java:3:5: compiler.err.cant.resolve.location: kindname.class, C, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); + doTest(""" + public class Test { + p.C c; + } + """, + "Test.java:2:6: compiler.err.cant.resolve.location: kindname.class, C, , , (compiler.misc.location: kindname.package, p, null)", + "1 error"); + + //tests for findIdentInType: + doTest(""" + import p.B.I; + public class Test { + I i; + } + """, + "Test.java:1:11: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", + "Test.java:3:5: compiler.err.cant.resolve.location: kindname.class, I, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); + doTest(""" + import p.B.M; + public class Test { + M m; + } + """, + "Test.java:1:11: compiler.err.cant.access: p.B.M, (compiler.misc.class.file.not.found: p.B$M)", + "Test.java:3:5: compiler.err.cant.resolve.location: kindname.class, M, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors"); + doTest(""" + public class Test { + p.B.I i; + } + """, + "Test.java:2:8: compiler.err.cant.access: p.B.I, (compiler.misc.bad.class.file.header: B$I.class, (compiler.misc.illegal.start.of.class.file))", + "1 error"); + doTest(""" + public class Test { + p.B.M m; + } + """, + "Test.java:2:8: compiler.err.cant.access: p.B.M, (compiler.misc.class.file.not.found: p.B$M)", + "1 error"); + } + + void doTest(String code, String... expectedOutput) { + List log = new JavacTask(tb) + .classpath(".") + .sources(code) + .options("-XDrawDiagnostics") + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitIdentifier(IdentifierTree node, Void p) { + validateAttributes(); + return super.visitIdentifier(node, p); + } + @Override + public Void visitMemberSelect(MemberSelectTree node, Void p) { + if (!node.getIdentifier().contentEquals("*")) { + validateAttributes(); + } + return super.visitMemberSelect(node, p); + } + void validateAttributes() { + Element el = trees.getElement(getCurrentPath()); + if (el == null) { + throw new AssertionError("A null sym attribute for: " + getCurrentPath().getLeaf() + "!"); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(expectedOutput != null ? Task.Expect.FAIL : Task.Expect.SUCCESS, + expectedOutput != null ? 1 : 0) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (expectedOutput != null && !log.equals(Arrays.asList(expectedOutput))) { + throw new AssertionError("Unexpected output: " + log); + } + } +} From 0bb9c76288b5f63fe965c3276bb566cef5f51c50 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 4 Jul 2024 10:03:39 +0000 Subject: [PATCH 159/288] 8324089: Fix typo in the manual page for "jcmd" (man jcmd) Reviewed-by: mgronlun, kevinw --- src/jdk.jcmd/share/man/jcmd.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index 1a8aefde06e8b..ec87ee3ae47a9 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -528,7 +528,7 @@ is not used: \[aq]m\[aq] or \[aq]M\[aq] for megabytes OR \[aq]g\[aq] or If no name is given, data from all recordings is dumped. (STRING, no default value) .IP \[bu] 2 -\f[V]path-to-gc-root\f[R]: (Optional) Flag for saving the path to +\f[V]path-to-gc-roots\f[R]: (Optional) Flag for saving the path to garbage collection (GC) roots at the time the recording data is dumped. The path information is useful for finding memory leaks but collecting it can cause the application to pause for a short period of time. @@ -606,7 +606,7 @@ Make note of the generated name that is shown in the response to the command so that you can use it with other commands. (STRING, system-generated default name) .IP \[bu] 2 -\f[V]path-to-gc-root\f[R]: (Optional) Flag for saving the path to +\f[V]path-to-gc-roots\f[R]: (Optional) Flag for saving the path to garbage collection (GC) roots at the end of a recording. The path information is useful for finding memory leaks but collecting it is time consuming. From cf1be87279ddfb2a9fd272e0b245fccd7ec10972 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 4 Jul 2024 10:04:52 +0000 Subject: [PATCH 160/288] 8335663: Fix simple -Wzero-as-null-pointer-constant warnings in C2 code Reviewed-by: jwaters, chagedorn --- src/hotspot/share/opto/block.hpp | 4 ++-- src/hotspot/share/opto/cfgnode.hpp | 4 ++-- src/hotspot/share/opto/constantTable.hpp | 4 ++-- src/hotspot/share/opto/machnode.hpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/block.hpp b/src/hotspot/share/opto/block.hpp index 2a08328b95c1c..e48b50b06ae8a 100644 --- a/src/hotspot/share/opto/block.hpp +++ b/src/hotspot/share/opto/block.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,7 +281,7 @@ class Block : public CFGElement { _succs(a), _num_succs(0), _pre_order(0), - _idom(0), + _idom(nullptr), _loop(nullptr), _reg_pressure(0), _ihrp_index(1), diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 32ac8c0162f22..18d7577d9e621 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,7 +238,7 @@ class PhiNode : public TypeNode { int is_diamond_phi() const; bool try_clean_memory_phi(PhaseIterGVN* igvn); virtual int Opcode() const; - virtual bool pinned() const { return in(0) != 0; } + virtual bool pinned() const { return in(0) != nullptr; } virtual const TypePtr *adr_type() const { verify_adr_type(true); return _adr_type; } void set_inst_mem_id(int inst_mem_id) { _inst_mem_id = inst_mem_id; } diff --git a/src/hotspot/share/opto/constantTable.hpp b/src/hotspot/share/opto/constantTable.hpp index f7197783773e3..74d310ec8d554 100644 --- a/src/hotspot/share/opto/constantTable.hpp +++ b/src/hotspot/share/opto/constantTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +50,7 @@ class ConstantTable { bool _can_be_reused; // true (default) if the value can be shared with other users. public: - Constant() : _type(T_ILLEGAL), _is_array(false), _alignment(-1), _offset(-1), _freq(0.0f), _can_be_reused(true) { _v._value.l = 0; } + Constant() : _type(T_ILLEGAL), _is_array(false), _alignment(-1), _offset(-1), _freq(0.0f), _can_be_reused(true) { _v._value.l = nullptr; } Constant(BasicType type, jvalue value, float freq = 0.0f, bool can_be_reused = true) : _type(type), _is_array(false), diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 6dbaa8a13969a..4d7b9c62aaa5b 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -1084,7 +1084,7 @@ class labelOper : public MachOper { uint _block_num; - labelOper() : _label(0), _block_num(0) {} + labelOper() : _label(nullptr), _block_num(0) {} labelOper(Label* label, uint block_num) : _label(label), _block_num(block_num) {} From c0604fb823d9f3b2e347a9857b11606b223ad8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Thu, 4 Jul 2024 10:06:09 +0000 Subject: [PATCH 161/288] 8334890: Missing unconditional cross modifying fence in nmethod entry barriers Reviewed-by: aboldtch, kbarrett --- .../share/gc/shared/barrierSetNMethod.cpp | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 79e3f47ed57bd..f041a2ccce184 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -178,16 +178,9 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { nmethod* nm = cb->as_nmethod(); BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); - // Check for disarmed method here to avoid going into DeoptimizeNMethodBarriersALot code - // too often. nmethod_entry_barrier checks for disarmed status itself, - // but we have no visibility into whether the barrier acted or not. - if (!bs_nm->is_armed(nm)) { - return 0; - } - - assert(!nm->is_osr_method(), "Should not reach here"); // Called upon first entry after being armed bool may_enter = bs_nm->nmethod_entry_barrier(nm); + assert(!nm->is_osr_method() || may_enter, "OSR nmethods should always be entrant after migration"); // In case a concurrent thread disarmed the nmethod, we need to ensure the new instructions // are made visible, by using a cross modify fence. Note that this is synchronous cross modifying @@ -197,11 +190,11 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { // it can be made conditional on the nmethod_patching_type. OrderAccess::cross_modify_fence(); - // Diagnostic option to force deoptimization 1 in 3 times. It is otherwise + // Diagnostic option to force deoptimization 1 in 10 times. It is otherwise // a very rare event. - if (DeoptimizeNMethodBarriersALot) { + if (DeoptimizeNMethodBarriersALot && !nm->is_osr_method()) { static volatile uint32_t counter=0; - if (Atomic::add(&counter, 1u) % 3 == 0) { + if (Atomic::add(&counter, 1u) % 10 == 0) { may_enter = false; } } @@ -214,15 +207,6 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { } bool BarrierSetNMethod::nmethod_osr_entry_barrier(nmethod* nm) { - // This check depends on the invariant that all nmethods that are deoptimized / made not entrant - // are NOT disarmed. - // This invariant is important because a method can be deoptimized after the method have been - // resolved / looked up by OSR by another thread. By not deoptimizing them we guarantee that - // a deoptimized method will always hit the barrier and come to the same conclusion - deoptimize - if (!is_armed(nm)) { - return true; - } - assert(nm->is_osr_method(), "Should not reach here"); log_trace(nmethod, barrier)("Running osr nmethod entry barrier: " PTR_FORMAT, p2i(nm)); bool result = nmethod_entry_barrier(nm); From 916db07e533cdc0fca2010751f7ebe54e6ada7b9 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Thu, 4 Jul 2024 10:34:56 +0000 Subject: [PATCH 162/288] 8335532: [JVMCI] Export VM_Version::L1_line_size in JVMCI Reviewed-by: dnsimon --- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 4 ++++ src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp | 8 ++++++++ src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 ++ 3 files changed, 14 insertions(+) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 2208813f170d6..665656d0be441 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -108,6 +108,10 @@ class CompilerToVM { static int sizeof_ZStoreBarrierEntry; #endif +#ifdef X86 + static int L1_line_size; +#endif + static address dsin; static address dcos; static address dtan; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 8595ac193fb8b..02cf6baff7827 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -114,6 +114,10 @@ int CompilerToVM::Data::_fields_annotations_base_offset; CardTable::CardValue* CompilerToVM::Data::cardtable_start_address; int CompilerToVM::Data::cardtable_shift; +#ifdef X86 +int CompilerToVM::Data::L1_line_size; +#endif + size_t CompilerToVM::Data::vm_page_size; int CompilerToVM::Data::sizeof_vtableEntry = sizeof(vtableEntry); @@ -240,6 +244,10 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { cardtable_shift = 0; } +#ifdef X86 + L1_line_size = VM_Version::L1_line_size(); +#endif + vm_page_size = os::vm_page_size(); #define SET_TRIGFUNC(name) \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index fea308503cf71..8f83d483bcf4b 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -112,6 +112,8 @@ static_field(CompilerToVM::Data, cardtable_start_address, CardTable::CardValue*) \ static_field(CompilerToVM::Data, cardtable_shift, int) \ \ + X86_ONLY(static_field(CompilerToVM::Data, L1_line_size, int)) \ + \ static_field(CompilerToVM::Data, vm_page_size, size_t) \ \ static_field(CompilerToVM::Data, sizeof_vtableEntry, int) \ From ced99066354fc6a32c587b9e3c35b07e26d3452e Mon Sep 17 00:00:00 2001 From: Joachim Kern Date: Thu, 4 Jul 2024 11:20:57 +0000 Subject: [PATCH 163/288] 8334371: [AIX] Beginning with AIX 7.3 TL1 mmap() supports 64K memory pages Reviewed-by: stuefe, mbaesken, mdoerr --- src/hotspot/os/aix/os_aix.cpp | 130 ++++++++++++++------- src/hotspot/os/aix/os_aix.hpp | 1 + src/hotspot/share/memory/virtualspace.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 3 +- test/hotspot/gtest/runtime/test_os.cpp | 12 -- test/hotspot/gtest/runtime/test_os_aix.cpp | 46 ++++++++ 6 files changed, 135 insertions(+), 59 deletions(-) create mode 100644 test/hotspot/gtest/runtime/test_os_aix.cpp diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 39f3e420662f0..dce12db3935b3 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -69,6 +69,7 @@ #include "signals_posix.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" @@ -96,6 +97,12 @@ #include #include #include +// sys/mman.h defines MAP_ANON_64K beginning with AIX7.3 TL1 +#ifndef MAP_ANON_64K + #define MAP_ANON_64K 0x400 +#else + STATIC_ASSERT(MAP_ANON_64K == 0x400); +#endif #include #include #include @@ -217,21 +224,22 @@ static address g_brk_at_startup = nullptr; // http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm // static struct { - size_t pagesize; // sysconf _SC_PAGESIZE (4K) - size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE) - size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE) - size_t pthr_stack_pagesize; // stack page size of pthread threads - size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE) - bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm. - bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm. - int error; // Error describing if something went wrong at multipage init. + size_t pagesize; // sysconf _SC_PAGESIZE (4K) + size_t datapsize; // default data page size (LDR_CNTRL DATAPSIZE) + size_t shmpsize; // default shared memory page size (LDR_CNTRL SHMPSIZE) + size_t pthr_stack_pagesize; // stack page size of pthread threads + size_t textpsize; // default text page size (LDR_CNTRL STACKPSIZE) + bool can_use_64K_pages; // True if we can alloc 64K pages dynamically with Sys V shm. + bool can_use_16M_pages; // True if we can alloc 16M pages dynamically with Sys V shm. + bool can_use_64K_mmap_pages; // True if we can alloc 64K pages dynamically with mmap. + int error; // Error describing if something went wrong at multipage init. } g_multipage_support = { (size_t) -1, (size_t) -1, (size_t) -1, (size_t) -1, (size_t) -1, - false, false, + false, false, false, 0 }; @@ -366,12 +374,16 @@ static void query_multipage_support() { // our own page size after allocated. { const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR); - guarantee(shmid != -1, "shmget failed"); - void* p = ::shmat(shmid, nullptr, 0); - ::shmctl(shmid, IPC_RMID, nullptr); - guarantee(p != (void*) -1, "shmat failed"); - g_multipage_support.shmpsize = os::Aix::query_pagesize(p); - ::shmdt(p); + assert(shmid != -1, "shmget failed"); + if (shmid != -1) { + void* p = ::shmat(shmid, nullptr, 0); + ::shmctl(shmid, IPC_RMID, nullptr); + assert(p != (void*) -1, "shmat failed"); + if (p != (void*) -1) { + g_multipage_support.shmpsize = os::Aix::query_pagesize(p); + ::shmdt(p); + } + } } // Before querying the stack page size, make sure we are not running as primordial @@ -421,26 +433,30 @@ static void query_multipage_support() { trcVerbose("Probing support for %s pages...", describe_pagesize(pagesize)); const int shmid = ::shmget(IPC_PRIVATE, pagesize, IPC_CREAT | S_IRUSR | S_IWUSR); - guarantee0(shmid != -1); // Should always work. - // Try to set pagesize. - struct shmid_ds shm_buf = { }; - shm_buf.shm_pagesize = pagesize; - if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { - const int en = errno; - ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! - log_warning(pagesize)("shmctl(SHM_PAGESIZE) failed with errno=%d", errno); - } else { - // Attach and double check pageisze. - void* p = ::shmat(shmid, nullptr, 0); - ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! - guarantee0(p != (void*) -1); // Should always work. - const size_t real_pagesize = os::Aix::query_pagesize(p); - if (real_pagesize != pagesize) { - log_warning(pagesize)("real page size (" SIZE_FORMAT_X ") differs.", real_pagesize); + assert(shmid != -1, "shmget failed"); + if (shmid != -1) { + // Try to set pagesize. + struct shmid_ds shm_buf = { }; + shm_buf.shm_pagesize = pagesize; + if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { + const int en = errno; + ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! + log_warning(pagesize)("shmctl(SHM_PAGESIZE) failed with errno=%d", errno); } else { - can_use = true; + // Attach and double check pageisze. + void* p = ::shmat(shmid, nullptr, 0); + ::shmctl(shmid, IPC_RMID, nullptr); // As early as possible! + assert(p != (void*) -1, "shmat failed"); + if (p != (void*) -1) { + const size_t real_pagesize = os::Aix::query_pagesize(p); + if (real_pagesize != pagesize) { + log_warning(pagesize)("real page size (" SIZE_FORMAT_X ") differs.", real_pagesize); + } else { + can_use = true; + } + ::shmdt(p); + } } - ::shmdt(p); } trcVerbose("Can use: %s", (can_use ? "yes" : "no")); if (pagesize == 64*K) { @@ -450,6 +466,16 @@ static void query_multipage_support() { } } + // Can we use mmap with 64K pages? (Should be available with AIX7.3 TL1) + { + void* p = mmap(NULL, 64*K, PROT_READ | PROT_WRITE, MAP_ANON_64K | MAP_ANONYMOUS | MAP_SHARED, -1, 0); + assert(p != (void*) -1, "mmap failed"); + if (p != (void*) -1) { + g_multipage_support.can_use_64K_mmap_pages = (64*K == os::Aix::query_pagesize(p)); + munmap(p, 64*K); + } + } + } // end: check which pages can be used for shared memory query_multipage_support_end: @@ -462,6 +488,8 @@ static void query_multipage_support() { describe_pagesize(g_multipage_support.textpsize)); trcVerbose("Thread stack page size (pthread): %s", describe_pagesize(g_multipage_support.pthr_stack_pagesize)); + trcVerbose("Can use 64K pages with mmap memory: %s", + (g_multipage_support.can_use_64K_mmap_pages ? "yes" :"no")); trcVerbose("Default shared memory page size: %s", describe_pagesize(g_multipage_support.shmpsize)); trcVerbose("Can use 64K pages dynamically with shared memory: %s", @@ -1133,6 +1161,8 @@ void os::print_memory_info(outputStream* st) { describe_pagesize(g_multipage_support.textpsize)); st->print_cr(" Thread stack page size (pthread): %s", describe_pagesize(g_multipage_support.pthr_stack_pagesize)); + st->print_cr(" Can use 64K pages with mmap memory: %s", + (g_multipage_support.can_use_64K_mmap_pages ? "yes" :"no")); st->print_cr(" Default shared memory page size: %s", describe_pagesize(g_multipage_support.shmpsize)); st->print_cr(" Can use 64K pages dynamically with shared memory: %s", @@ -1612,6 +1642,10 @@ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) { // later use msync(MS_INVALIDATE) (see os::uncommit_memory). int flags = MAP_ANONYMOUS | MAP_SHARED; + if (os::vm_page_size() == 64*K && g_multipage_support.can_use_64K_mmap_pages) { + flags |= MAP_ANON_64K; + } + // MAP_FIXED is needed to enforce requested_addr - manpage is vague about what // it means if wishaddress is given but MAP_FIXED is not set. // @@ -1661,7 +1695,11 @@ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) { p2i(addr), p2i(addr + bytes), bytes); // bookkeeping - vmembk_add(addr, size, 4*K, VMEM_MAPPED); + if (os::vm_page_size() == 64*K && g_multipage_support.can_use_64K_mmap_pages) { + vmembk_add(addr, size, 64*K, VMEM_MAPPED); + } else { + vmembk_add(addr, size, 4*K, VMEM_MAPPED); + } // Test alignment, see above. assert0(is_aligned_to(addr, os::vm_page_size())); @@ -1854,8 +1892,8 @@ char* os::pd_reserve_memory(size_t bytes, bool exec) { bytes = align_up(bytes, os::vm_page_size()); // In 4K mode always use mmap. - // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. - if (os::vm_page_size() == 4*K) { + // In 64K mode allocate with mmap if it supports 64K pages, otherwise use 64K shmatted. + if (os::vm_page_size() == 4*K || g_multipage_support.can_use_64K_mmap_pages) { return reserve_mmaped_memory(bytes, nullptr /* requested_addr */); } else { return reserve_shmated_memory(bytes, nullptr /* requested_addr */); @@ -2042,8 +2080,8 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool bytes = align_up(bytes, os::vm_page_size()); // In 4K mode always use mmap. - // In 64K mode allocate small sizes with mmap, large ones with 64K shmatted. - if (os::vm_page_size() == 4*K) { + // In 64K mode allocate with mmap if it supports 64K pages, otherwise use 64K shmatted. + if (os::vm_page_size() == 4*K || g_multipage_support.can_use_64K_mmap_pages) { return reserve_mmaped_memory(bytes, requested_addr); } else { return reserve_shmated_memory(bytes, requested_addr); @@ -2183,18 +2221,18 @@ void os::init(void) { // and should be allocated with 64k pages. // // So, we do the following: - // LDR_CNTRL can_use_64K_pages_dynamically what we do remarks - // 4K no 4K old systems (aix 5.2) or new systems with AME activated - // 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings + // LDR_CNTRL can_use_64K_pages_dynamically(mmap or shm) what we do remarks + // 4K no 4K old systems (aix 5.2) or new systems with AME activated + // 4k yes 64k (treat 4k stacks as 64k) different loader than java and standard settings // 64k no --- AIX 5.2 ? --- - // 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking) + // 64k yes 64k new systems and standard java loader (we set datapsize=64k when linking) // We explicitly leave no option to change page size, because only upgrading would work, // not downgrading (if stack page size is 64k you cannot pretend its 4k). if (g_multipage_support.datapsize == 4*K) { // datapsize = 4K. Data segment, thread stacks are 4K paged. - if (g_multipage_support.can_use_64K_pages) { + if (g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages) { // .. but we are able to use 64K pages dynamically. // This would be typical for java launchers which are not linked // with datapsize=64K (like, any other launcher but our own). @@ -2224,7 +2262,7 @@ void os::init(void) { // This normally means that we can allocate 64k pages dynamically. // (There is one special case where this may be false: EXTSHM=on. // but we decided to not support that mode). - assert0(g_multipage_support.can_use_64K_pages); + assert0(g_multipage_support.can_use_64K_pages || g_multipage_support.can_use_64K_mmap_pages); set_page_size(64*K); trcVerbose("64K page mode"); FLAG_SET_ERGO(Use64KPages, true); @@ -2709,6 +2747,10 @@ void os::Aix::initialize_libperfstat() { } } +bool os::Aix::supports_64K_mmap_pages() { + return g_multipage_support.can_use_64K_mmap_pages; +} + ///////////////////////////////////////////////////////////////////////////// // thread stack diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index 759bc552bb7c0..d17c022e41136 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -76,6 +76,7 @@ class os::Aix { public: static void init_thread_fpu_state(); static pthread_t main_thread(void) { return _main_thread; } + static bool supports_64K_mmap_pages(); // Given an address, returns the size of the page backing that address static size_t query_pagesize(void* p); diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index a75d9f076ad22..7df35bbeec88e 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -380,7 +380,7 @@ void ReservedHeapSpace::establish_noaccess_prefix() { if (base() && base() + _size > (char *)OopEncodingHeapMax) { if (true WIN64_ONLY(&& !UseLargePages) - AIX_ONLY(&& os::vm_page_size() != 64*K)) { + AIX_ONLY(&& (os::Aix::supports_64K_mmap_pages() || os::vm_page_size() == 4*K))) { // Protect memory at the base of the allocated region. // If special, the page was committed (only matters on windows) if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) { diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index d141ee244262b..7b766707b0d0e 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1958,8 +1958,7 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz // This is not reflected by os_allocation_granularity(). // The logic here is dual to the one in pd_reserve_memory in os_aix.cpp const size_t system_allocation_granularity = - AIX_ONLY(os::vm_page_size() == 4*K ? 4*K : 256*M) - NOT_AIX(os::vm_allocation_granularity()); + AIX_ONLY((!os::Aix::supports_64K_mmap_pages() && os::vm_page_size() == 64*K) ? 256*M : ) os::vm_allocation_granularity(); const size_t alignment_adjusted = MAX2(alignment, system_allocation_granularity); diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 654c2c60673ba..70f739ce9228f 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -967,18 +967,6 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { } } -#ifdef AIX -// On Aix, we should fail attach attempts not aligned to segment boundaries (256m) -TEST_VM(os, aix_reserve_at_non_shmlba_aligned_address) { - if (Use64KPages) { - char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); - ASSERT_EQ(p, nullptr); // should have failed - p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); - ASSERT_EQ(p, nullptr); // should have failed - } -} -#endif // AIX - TEST_VM(os, vm_min_address) { size_t s = os::vm_min_address(); ASSERT_GE(s, M); diff --git a/test/hotspot/gtest/runtime/test_os_aix.cpp b/test/hotspot/gtest/runtime/test_os_aix.cpp new file mode 100644 index 0000000000000..e8b06b3b4bc8b --- /dev/null +++ b/test/hotspot/gtest/runtime/test_os_aix.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" + +#ifdef AIX + +#include "runtime/os.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "unittest.hpp" + +// On Aix, when using shmget() in os::attempt_reserve_memory_at() we should fail with attach +// attempts not aligned to shmget() segment boundaries (256m) +// But shmget() is only used in cases we want to have 64K pages and mmap() does not provide it. +TEST_VM(os_aix, aix_reserve_at_non_shmlba_aligned_address) { + if (os::vm_page_size() != 4*K && !os::Aix::supports_64K_mmap_pages()) { + // With this condition true shmget() is used inside + char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); + ASSERT_EQ(p, nullptr); // should have failed + p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); + ASSERT_EQ(p, nullptr); // should have failed + } +} + +#endif // AIX From 7e378fccd8a4601c8b8e86aa2862c61e469c3a04 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 4 Jul 2024 12:16:54 +0000 Subject: [PATCH 164/288] 8335667: Fix simple -Wzero-as-null-pointer-constant warnings in compiler code Reviewed-by: chagedorn --- src/hotspot/share/ci/ciStreams.hpp | 4 ++-- src/hotspot/share/code/exceptionHandlerTable.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/ci/ciStreams.hpp b/src/hotspot/share/ci/ciStreams.hpp index 224dfbe556f0f..6c5dc31f4df9f 100644 --- a/src/hotspot/share/ci/ciStreams.hpp +++ b/src/hotspot/share/ci/ciStreams.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ class ciBytecodeStream : StackObj { Bytecodes::Code _raw_bc; // Current bytecode, raw form void reset( address base, unsigned int size ) { - _bc_start =_was_wide = 0; + _bc_start = _was_wide = nullptr; _start = _pc = base; _end = base + size; } diff --git a/src/hotspot/share/code/exceptionHandlerTable.hpp b/src/hotspot/share/code/exceptionHandlerTable.hpp index 083dc43011117..9d7981f392ca8 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.hpp +++ b/src/hotspot/share/code/exceptionHandlerTable.hpp @@ -148,7 +148,7 @@ class ImplicitExceptionTable { ReallocMark _nesting; // assertion check for reallocations public: - ImplicitExceptionTable( ) : _size(0), _len(0), _data(0) { } + ImplicitExceptionTable( ) : _size(0), _len(0), _data(nullptr) { } // (run-time) construction from nmethod ImplicitExceptionTable(const nmethod *nm); From 6a472797a410a6fa27f50371b255054af0cd3c99 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 4 Jul 2024 12:29:32 +0000 Subject: [PATCH 165/288] 8332072: Convert package.html files in `java.naming` to package-info.java 8335213: Code snippet in javax.naming.ldap package summary does not compile Reviewed-by: aefimov --- .../javax/naming/directory/package-info.java | 86 ++++++ .../javax/naming/directory/package.html | 90 ------ .../javax/naming/event/package-info.java | 118 ++++++++ .../classes/javax/naming/event/package.html | 125 -------- .../javax/naming/ldap/package-info.java | 259 +++++++++++++++++ .../classes/javax/naming/ldap/package.html | 266 ------------------ .../javax/naming/ldap/spi/package-info.java | 33 +++ .../classes/javax/naming/package-info.java | 136 +++++++++ .../share/classes/javax/naming/package.html | 143 ---------- .../javax/naming/spi/package-info.java | 85 ++++++ .../classes/javax/naming/spi/package.html | 90 ------ 11 files changed, 717 insertions(+), 714 deletions(-) create mode 100644 src/java.naming/share/classes/javax/naming/directory/package-info.java delete mode 100644 src/java.naming/share/classes/javax/naming/directory/package.html create mode 100644 src/java.naming/share/classes/javax/naming/event/package-info.java delete mode 100644 src/java.naming/share/classes/javax/naming/event/package.html create mode 100644 src/java.naming/share/classes/javax/naming/ldap/package-info.java delete mode 100644 src/java.naming/share/classes/javax/naming/ldap/package.html create mode 100644 src/java.naming/share/classes/javax/naming/ldap/spi/package-info.java create mode 100644 src/java.naming/share/classes/javax/naming/package-info.java delete mode 100644 src/java.naming/share/classes/javax/naming/package.html create mode 100644 src/java.naming/share/classes/javax/naming/spi/package-info.java delete mode 100644 src/java.naming/share/classes/javax/naming/spi/package.html diff --git a/src/java.naming/share/classes/javax/naming/directory/package-info.java b/src/java.naming/share/classes/javax/naming/directory/package-info.java new file mode 100644 index 0000000000000..3f32a95c31efe --- /dev/null +++ b/src/java.naming/share/classes/javax/naming/directory/package-info.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * + * Extends the {@code javax.naming} package to provide functionality + * for accessing directory services. + * + *

    + * This package defines the directory operations of the Java Naming and + * Directory Interface (JNDI).   + * JNDI provides naming and directory functionality to applications + * written in the Java programming language. It is designed to be + * independent of any specific naming or directory service + * implementation. Thus a variety of services--new, emerging, and + * already deployed ones--can be accessed in a common way. + * + *

    + * This package allows applications to retrieve and update attributes + * associated with objects stored in a directory, and to search for + * objects using specified attributes. + * + *

    The Directory Context

    + * + * The {@code DirContext} + * interface represents a directory context. + * It defines methods for examining and updating attributes associated with a + * directory object, or directory entry as it is sometimes + * called. + *

    + * You use {@code getAttributes()} to retrieve the attributes + * associated with a directory object (for which you supply the name). + * Attributes are modified using {@code modifyAttributes()}. + * You can add, replace, or remove attributes and/or attribute values + * using this operation. + *

    + * {@code DirContext} also behaves as a naming context + * by extending the {@code Context} interface in the {@code javax.naming} package. + * This means that any directory object can also provide + * a naming context. + * For example, the directory object for a person might contain + * the attributes of that person, and at the same time provide + * a context for naming objects relative to that person + * such as his printers and home directory. + * + *

    Searches

    + * {@code DirContext} contains methods for + * performing content-based searching of the directory. + * In the simplest and most common form of usage, the application + * specifies a set of attributes--possibly with specific + * values--to match, and submits this attribute set, to the + * {@code search()} method. + * There are other overloaded forms of {@code search()} + * that support more sophisticated search filters. + * + * + *

    Package Specification

    + * + * The JNDI API Specification and related documents can be found in the + * {@extLink jndi_overview JNDI documentation}. + * + * @since 1.3 + */ +package javax.naming.directory; diff --git a/src/java.naming/share/classes/javax/naming/directory/package.html b/src/java.naming/share/classes/javax/naming/directory/package.html deleted file mode 100644 index ff4a83b4ce02d..0000000000000 --- a/src/java.naming/share/classes/javax/naming/directory/package.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - -Extends the javax.naming package to provide functionality -for accessing directory services. - -

    -This package defines the directory operations of the Java Naming and -Directory Interface (JNDI).   -JNDI provides naming and directory functionality to applications -written in the Java programming language. It is designed to be -independent of any specific naming or directory service -implementation. Thus a variety of services--new, emerging, and -already deployed ones--can be accessed in a common way. - -

    -This package allows applications to retrieve and update attributes -associated with objects stored in a directory, and to search for -objects using specified attributes. - -

    The Directory Context

    - -The DirContext -interface represents a directory context. -It defines methods for examining and updating attributes associated with a -directory object, or directory entry as it is sometimes -called. -

    -You use getAttributes() to retrieve the attributes -associated with a directory object (for which you supply the name). -Attributes are modified using modifyAttributes(). -You can add, replace, or remove attributes and/or attribute values -using this operation. -

    -DirContext also behaves as a naming context -by extending the Context interface in the javax.naming package. -This means that any directory object can also provide -a naming context. -For example, the directory object for a person might contain -the attributes of that person, and at the same time provide -a context for naming objects relative to that person -such as his printers and home directory. - -

    Searches

    -DirContext contains methods for -performing content-based searching of the directory. -In the simplest and most common form of usage, the application -specifies a set of attributes--possibly with specific -values--to match, and submits this attribute set, to the -search() method. -There are other overloaded forms of search() -that support more sophisticated search filters. - - -

    Package Specification

    - -The JNDI API Specification and related documents can be found in the -{@extLink jndi_overview JNDI documentation}. - -@since 1.3 - - - diff --git a/src/java.naming/share/classes/javax/naming/event/package-info.java b/src/java.naming/share/classes/javax/naming/event/package-info.java new file mode 100644 index 0000000000000..4214ee8597394 --- /dev/null +++ b/src/java.naming/share/classes/javax/naming/event/package-info.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * + * Provides support for event notification when accessing naming and + * directory services. + * + *

    + * This package defines the event notification operations of the Java Naming + * and Directory Interface (JNDI).   + * JNDI provides naming and directory functionality to applications + * written in the Java programming language. It is designed to be + * independent of any specific naming or directory service + * implementation. Thus a variety of services--new, emerging, and + * already deployed ones--can be accessed in a common way. + * + *

    Naming Events

    + *

    + * This package defines a {@code NamingEvent} class to represent an event + * that is generated by a naming/directory service. + * It also defines subinterfaces of {@code Context} and {@code DirContext}, + * called {@code EventContext} and {@code EventDirContext}, + * through which applications can register their interest in events + * fired by the context. + *

    + * {@code NamingEvent} represents an event that occurs in a + * naming or directory service. There are two categories of naming events: + *

      + *
    • Those that affect the namespace (add/remove/rename an object) + *
    • Those that affect the objects' contents. + *
    + * Each category of events is handled by a corresponding listener: + * {@code NamespaceChangeListener}, {@code ObjectChangeListener}. + *

    + * An application, for example, can register its interest in changes to + * objects in a context as follows: + * {@snippet : + * EventContext src = + * (EventContext)(new InitialContext()).lookup("o=wiz,c=us"); + * src.addNamingListener("ou=users", EventContext.ONELEVEL_SCOPE, + * new ChangeHandler()); + * ... + * class ChangeHandler implements ObjectChangeListener { + * public void objectChanged(NamingEvent evt) { + * System.out.println(evt.getNewBinding()); + * } + * public void namingExceptionThrown(NamingExceptionEvent evt) { + * System.out.println(evt.getException()); + * } + * } + * } + * + * + *

    Threading Issues

    + * + * When an event is dispatched to a listener, the listener method (such + * as {@code objectChanged()}) may be executed in a thread other than the + * one in which the call to {@code addNamingListener()} was executed. + * The choice of which thread to use is made by the service provider. + * When an event is dispatched to multiple listeners, the service provider + * may choose (and is generally encouraged) to execute the listener methods + * concurrently in separate threads. + *

    + * When a listener instance invokes {@code NamingEvent.getEventContext()}, + * it must take into account the possibility that other threads will be + * working with that context concurrently. Likewise, when a listener is + * registered via {@code addNamingListener()}, the registering thread + * must take into account the likely possibility that the service provider + * will later invoke the listeners in newly-created threads. As {@code Context} + * instances are not guaranteed to be thread-safe in general, all context + * operations must be synchronized as needed. + * + *

    Exception Handling

    + * + * When a listener registers for events with a context, the context might + * need to do some internal processing in order to collect information + * required to generate the events. The context, for example, might need + * to make a request to the server to register interest in changes + * on the server that will eventually be translated into events. + * If an exception occurs that prevents information about the events from + * being collected, the listener will never be notified of the events. + * When such an exception occurs, a {@code NamingExceptionEvent} is + * fired to notify the listener. The listener's + * {@code namingExceptionThrown()} method is invoked, as shown in the + * sample code above, + * and the listener is automatically deregistered. + * + *

    Package Specification

    + * + * The JNDI API Specification and related documents can be found in the + * {@extLink jndi_overview JNDI documentation}. + * + * @since 1.3 + */ +package javax.naming.event; diff --git a/src/java.naming/share/classes/javax/naming/event/package.html b/src/java.naming/share/classes/javax/naming/event/package.html deleted file mode 100644 index 087e7c869a4bc..0000000000000 --- a/src/java.naming/share/classes/javax/naming/event/package.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - -Provides support for event notification when accessing naming and -directory services. - -

    -This package defines the event notification operations of the Java Naming -and Directory Interface (JNDI).   -JNDI provides naming and directory functionality to applications -written in the Java programming language. It is designed to be -independent of any specific naming or directory service -implementation. Thus a variety of services--new, emerging, and -already deployed ones--can be accessed in a common way. - -

    Naming Events

    -

    -This package defines a NamingEvent class to represent an event -that is generated by a naming/directory service. -It also defines subinterfaces of Context and DirContext, -called EventContext and EventDirContext, -through which applications can register their interest in events -fired by the context. -

    -NamingEvent represents an event that occurs in a -naming or directory service. There are two categories of naming events: -

      -
    • Those that affect the namespace (add/remove/rename an object) -
    • Those that affect the objects' contents. -
    -Each category of events is handled by a corresponding listener: -NamespaceChangeListener, ObjectChangeListener. -

    -An application, for example, can register its interest in changes to -objects in a context as follows: -

    -
    -EventContext src = 
    -    (EventContext)(new InitialContext()).lookup("o=wiz,c=us");
    -src.addNamingListener("ou=users", EventContext.ONELEVEL_SCOPE,
    -    new ChangeHandler());
    -...
    -class ChangeHandler implements ObjectChangeListener {
    -    public void objectChanged(NamingEvent evt) {
    -        System.out.println(evt.getNewBinding());
    -    }
    -    public void namingExceptionThrown(NamingExceptionEvent evt) {
    -        System.out.println(evt.getException());
    -    }
    -}
    -
    -
    - - -

    Threading Issues

    - -When an event is dispatched to a listener, the listener method (such -as objectChanged()) may be executed in a thread other than the -one in which the call to addNamingListener() was executed. -The choice of which thread to use is made by the service provider. -When an event is dispatched to multiple listeners, the service provider -may choose (and is generally encouraged) to execute the listener methods -concurrently in separate threads. -

    -When a listener instance invokes NamingEvent.getEventContext(), -it must take into account the possibility that other threads will be -working with that context concurrently. Likewise, when a listener is -registered via addNamingListener(), the registering thread -must take into account the likely possibility that the service provider -will later invoke the listeners in newly-created threads. As Context -instances are not guaranteed to be thread-safe in general, all context -operations must be synchronized as needed. - -

    Exception Handling

    - -When a listener registers for events with a context, the context might -need to do some internal processing in order to collect information -required to generate the events. The context, for example, might need -to make a request to the server to register interest in changes -on the server that will eventually be translated into events. -If an exception occurs that prevents information about the events from -being collected, the listener will never be notified of the events. -When such an exception occurs, a NamingExceptionEvent is -fired to notify the listener. The listener's -namingExceptionThrown() method is invoked, as shown in the -sample code above, -and the listener is automatically deregistered. - -

    Package Specification

    - - -The JNDI API Specification and related documents can be found in the -{@extLink jndi_overview JNDI documentation}. - -@since 1.3 - - - diff --git a/src/java.naming/share/classes/javax/naming/ldap/package-info.java b/src/java.naming/share/classes/javax/naming/ldap/package-info.java new file mode 100644 index 0000000000000..f5ba4906fd786 --- /dev/null +++ b/src/java.naming/share/classes/javax/naming/ldap/package-info.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * + * Provides support for LDAPv3 extended operations and controls. + * + *

    + * This package extends the directory operations of the Java Naming and + * Directory Interface (JNDI).   + * JNDI provides naming and directory functionality to applications + * written in the Java programming language. It is designed to be + * independent of any specific naming or directory service + * implementation. Thus a variety of services--new, emerging, and + * already deployed ones--can be accessed in a common way. + * + *

    + * This package is for applications and service providers that deal with + * LDAPv3 extended operations and controls, as defined by + * RFC 2251. + * The core interface in this package is {@code LdapContext}, which defines + * methods on a context for performing extended operations and handling + * controls. + * + *

    Extended Operations

    + *

    + * This package defines the interface {@code ExtendedRequest} + * to represent the argument to an extended operation, + * and the interface {@code ExtendedResponse} to represent the result + * of the extended operation. + * An extended response is always paired with an extended request + * but not necessarily vice versa. That is, you can have an extended request + * that has no corresponding extended response. + *

    + * An application typically does not deal directly with these interfaces. + * Instead, it deals with classes that implement these + * interfaces. + * The application gets these classes either as part of a + * repertoire of extended operations standardized through the IETF, or + * from directory vendors for vendor-specific extended operations. + * The request classes should have constructors that accept + * arguments in a type-safe and user-friendly manner, while the + * response classes should have access methods for getting the data + * of the response in a type-safe and user-friendly manner. + * Internally, the request/response classes deal with encoding and decoding + * BER values. + *

    + * For example, suppose an LDAP server supports a "get time" extended operation. + * It would supply classes such as + * {@code GetTimeRequest} and {@code GetTimeResponse}, + * so that applications can use this feature. + * An application would use these classes as follows: + * {@snippet : + * GetTimeResponse resp = + * (GetTimeResponse) ectx.extendedOperation(new GetTimeRequest()); + * long time = resp.getTime(); + * } + *

    + * The {@code GetTimeRequest} and {@code GetTimeResponse} classes might + * be defined as follows: + * {@snippet : + * public class GetTimeRequest implements ExtendedRequest { + * // User-friendly constructor + * public GetTimeRequest() { + * }; + * + * // Methods used by service providers + * public String getID() { + * return GETTIME_REQ_OID; + * } + * public byte[] getEncodedValue() { + * return null; // no value needed for get time request + * } + * public ExtendedResponse createExtendedResponse( + * String id, byte[] berValue, int offset, int length) throws NamingException { + * return new GetTimeResponse(id, berValue, offset, length); + * } + * } + * public class GetTimeResponse implements ExtendedResponse { + * long time; + * // called by GetTimeRequest.createExtendedResponse() + * public GetTimeResponse(String id, byte[] berValue, int offset, int length) + * throws NamingException { + * // check validity of id + * long time = ... // decode berValue to get time + * } + * + * // Type-safe and User-friendly methods + * public java.util.Date getDate() { return new java.util.Date(time); } + * public long getTime() { return time; } + * + * // Low level methods + * public byte[] getEncodedValue() { + * return // berValue saved; + * } + * public String getID() { + * return GETTIME_RESP_OID; + * } + * } + * } + * + *

    Controls

    + * + * This package defines the interface {@code Control} to represent an LDAPv3 + * control. It can be a control that is sent to an LDAP server + * (request control) or a control returned by an LDAP server + * (response control). Unlike extended requests and responses, + * there is not necessarily any pairing between request controls and + * response controls. You can send request controls and expect no + * response controls back, or receive response controls without sending + * any request controls. + *

    + * An application typically does not deal directly with this interface. + * Instead, it deals with classes that implement this interface. + * The application gets control classes either as part of a repertoire of + * controls standardized through the IETF, or from directory vendors for + * vendor-specific controls. The request control classes should have + * constructors that accept arguments in a type-safe and user-friendly + * manner, while the response control classes should have access methods + * for getting the data of the response in a type-safe and user-friendly + * manner. Internally, the request/response control classes deal with + * encoding and decoding BER values. + *

    + * For example, suppose an LDAP server supports a "signed results" + * request control, which when sent with a request, asks the + * server to digitally sign the results of an operation. + * It would supply a class {@code SignedResultsControl} so that applications + * can use this feature. + * An application would use this class as follows: + * {@snippet : + * Control[] reqCtls = new Control[] {new SignedResultsControl(Control.CRITICAL)}; + * ectx.setRequestControls(reqCtls); + * NamingEnumeration enum = ectx.search(...); + * } + * The {@code SignedResultsControl} class might be defined as follows: + * {@snippet : + * public class SignedResultsControl implements Control { + * // User-friendly constructor + * public SignedResultsControl(boolean criticality) { + * // assemble the components of the request control + * }; + * + * // Methods used by service providers + * public String getID() { + * return // control's object identifier + * } + * public byte[] getEncodedValue() { + * return // ASN.1 BER encoded control value + * } + * ... + * } + * } + *

    + * When a service provider receives response controls, it uses + * the {@code ControlFactory} class to produce specific classes + * that implement the {@code Control} interface. + *

    + * An LDAP server can send back response controls with an LDAP operation + * and also with enumeration results, such as those returned + * by a list or search operation. + * The {@code LdapContext} provides a method ({@code getResponseControls()}) + * for getting the response controls sent with an LDAP operation, + * while the {@code HasControls} interface is used to retrieve + * response controls associated with enumeration results. + *

    + * For example, suppose an LDAP server sends back a "change ID" control in response + * to a successful modification. It would supply a class {@code ChangeIDControl} + * so that the application can use this feature. + * An application would perform an update, and then try to get the change ID. + * {@snippet : + * // Perform update + * Context ctx = ectx.createSubsubcontext("cn=newobj"); + * + * // Get response controls + * Control[] respCtls = ectx.getResponseControls(); + * if (respCtls != null) { + * // Find the one we want + * for (int i = 0; i < respCtls.length; i++) { + * if(respCtls[i] instanceof ChangeIDControl) { + * ChangeIDControl cctl = (ChangeIDControl)respCtls[i]; + * System.out.println(cctl.getChangeID()); + * } + * } + * } + * } + * The vendor might supply the following {@code ChangeIDControl} and + * {@code VendorXControlFactory} classes. The {@code VendorXControlFactory} + * will be used by the service provider when the provider receives response + * controls from the LDAP server. + * {@snippet : + * public class ChangeIDControl implements Control { + * long id; + * + * // Constructor used by ControlFactory + * public ChangeIDControl(String OID, byte[] berVal) throws NamingException { + * // check validity of OID + * id = // extract change ID from berVal + * }; + * + * // Type-safe and User-friendly method + * public long getChangeID() { + * return id; + * } + * + * // Low-level methods + * public String getID() { + * return CHANGEID_OID; + * } + * public byte[] getEncodedValue() { + * return // original berVal + * } + * ... + * } + * public class VendorXControlFactory extends ControlFactory { + * public VendorXControlFactory () { + * } + * + * public Control getControlInstance(Control orig) throws NamingException { + * if (isOneOfMyControls(orig.getID())) { + * ... + * + * // determine which of ours it is and call its constructor + * return (new ChangeIDControl(orig.getID(), orig.getEncodedValue())); + * } + * return null; // not one of ours + * } + * } + * } + * + *

    Package Specification

    + * + * The JNDI API Specification and related documents can be found in the + * {@extLink jndi_overview JNDI documentation}. + * + * @since 1.3 + */ +package javax.naming.ldap; diff --git a/src/java.naming/share/classes/javax/naming/ldap/package.html b/src/java.naming/share/classes/javax/naming/ldap/package.html deleted file mode 100644 index 6bd2f78e7890b..0000000000000 --- a/src/java.naming/share/classes/javax/naming/ldap/package.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - - - -Provides support for LDAPv3 extended operations and controls. - -

    -This package extends the directory operations of the Java Naming and -Directory Interface (JNDI).   -JNDI provides naming and directory functionality to applications -written in the Java programming language. It is designed to be -independent of any specific naming or directory service -implementation. Thus a variety of services--new, emerging, and -already deployed ones--can be accessed in a common way. - -

    -This package is for applications and service providers that deal with -LDAPv3 extended operations and controls, as defined by -RFC 2251. -The core interface in this package is LdapContext, which defines -methods on a context for performing extended operations and handling -controls. - -

    Extended Operations

    -

    -This package defines the interface ExtendedRequest -to represent the argument to an extended operation, -and the interface ExtendedResponse to represent the result -of the extended operation. -An extended response is always paired with an extended request -but not necessarily vice versa. That is, you can have an extended request -that has no corresponding extended response. -

    -An application typically does not deal directly with these interfaces. -Instead, it deals with classes that implement these -interfaces. -The application gets these classes either as part of a -repertoire of extended operations standardized through the IETF, or -from directory vendors for vendor-specific extended operations. -The request classes should have constructors that accept -arguments in a type-safe and user-friendly manner, while the -response classes should have access methods for getting the data -of the response in a type-safe and user-friendly manner. -Internally, the request/response classes deal with encoding and decoding -BER values. -

    -For example, suppose an LDAP server supports a "get time" extended operation. -It would supply classes such as -GetTimeRequest and GetTimeResponse, -so that applications can use this feature. -An application would use these classes as follows: -

    -GetTimeResponse resp =
    -    (GetTimeResponse) ectx.extendedOperation(new GetTimeRequest());
    -long time = resp.getTime();
    -
    -

    -The GetTimeRequest and GetTimeResponse classes might -be defined as follows: -

    -public class GetTimeRequest implements ExtendedRequest {
    -    // User-friendly constructor 
    -    public GetTimeRequest() {
    -    };
    -
    -    // Methods used by service providers
    -    public String getID() {
    -        return GETTIME_REQ_OID;
    -    }
    -    public byte[] getEncodedValue() {
    -        return null;  // no value needed for get time request
    -    }
    -    public ExtendedResponse createExtendedResponse(
    -        String id, byte[] berValue, int offset, int length) throws NamingException {
    -        return new GetTimeResponse(id, berValue, offset, length);
    -    }
    -}
    -public class GetTimeResponse() implements ExtendedResponse {
    -    long time;
    -    // called by GetTimeRequest.createExtendedResponse()
    -    public GetTimeResponse(String id, byte[] berValue, int offset, int length)
    -        throws NamingException {
    -        // check validity of id
    -        long time =  ... // decode berValue to get time
    -    }
    -
    -    // Type-safe and User-friendly methods
    -    public java.util.Date getDate() { return new java.util.Date(time); }
    -    public long getTime() { return time; }
    -
    -    // Low level methods
    -    public byte[] getEncodedValue() {
    -        return // berValue saved;
    -    }
    -    public String getID() {
    -        return GETTIME_RESP_OID;
    -    }
    -}
    -
    - -

    Controls

    - -This package defines the interface Control to represent an LDAPv3 -control. It can be a control that is sent to an LDAP server -(request control) or a control returned by an LDAP server -(response control). Unlike extended requests and responses, -there is not necessarily any pairing between request controls and -response controls. You can send request controls and expect no -response controls back, or receive response controls without sending -any request controls. -

    -An application typically does not deal directly with this interface. -Instead, it deals with classes that implement this interface. -The application gets control classes either as part of a repertoire of -controls standardized through the IETF, or from directory vendors for -vendor-specific controls. The request control classes should have -constructors that accept arguments in a type-safe and user-friendly -manner, while the response control classes should have access methods -for getting the data of the response in a type-safe and user-friendly -manner. Internally, the request/response control classes deal with -encoding and decoding BER values. -

    -For example, suppose an LDAP server supports a "signed results" -request control, which when sent with a request, asks the -server to digitally sign the results of an operation. -It would supply a class SignedResultsControl so that applications -can use this feature. -An application would use this class as follows: -

    -
    -Control[] reqCtls = new Control[] {new SignedResultsControl(Control.CRITICAL)};
    -ectx.setRequestControls(reqCtls);
    -NamingEnumeration enum = ectx.search(...);
    -
    -
    -The SignedResultsControl class might be defined as follows: -
    -public class SignedResultsControl implements Control {
    -    // User-friendly constructor 
    -    public SignedResultsControl(boolean criticality) {
    -	// assemble the components of the request control
    -    };
    -
    -    // Methods used by service providers
    -    public String getID() {
    -        return // control's object identifier
    -    }
    -    public byte[] getEncodedValue() {
    -        return // ASN.1 BER encoded control value
    -    }
    -    ...
    -}
    -
    -

    -When a service provider receives response controls, it uses -the ControlFactory class to produce specific classes -that implement the Control interface. -

    -An LDAP server can send back response controls with an LDAP operation -and also with enumeration results, such as those returned -by a list or search operation. -The LdapContext provides a method (getResponseControls()) -for getting the response controls sent with an LDAP operation, -while the HasControls interface is used to retrieve -response controls associated with enumeration results. -

    -For example, suppose an LDAP server sends back a "change ID" control in response -to a successful modification. It would supply a class ChangeIDControl -so that the application can use this feature. -An application would perform an update, and then try to get the change ID. -

    -// Perform update
    -Context ctx = ectx.createSubsubcontext("cn=newobj");
    -
    -// Get response controls
    -Control[] respCtls = ectx.getResponseControls();
    -if (respCtls != null) {
    -    // Find the one we want
    -    for (int i = 0; i < respCtls; i++) {
    -        if(respCtls[i] instanceof ChangeIDControl) {
    -	    ChangeIDControl cctl = (ChangeIDControl)respCtls[i];
    -	    System.out.println(cctl.getChangeID());
    -        }
    -    }
    -}
    -
    -The vendor might supply the following ChangeIDControl and -VendorXControlFactory classes. The VendorXControlFactory -will be used by the service provider when the provider receives response -controls from the LDAP server. -
    -public class ChangeIDControl implements Control {
    -    long id;
    -
    -    // Constructor used by ControlFactory
    -    public ChangeIDControl(String OID, byte[] berVal) throws NamingException {
    -        // check validity of OID
    -        id = // extract change ID from berVal
    -    };
    -
    -    // Type-safe and User-friendly method
    -    public long getChangeID() {
    -        return id;
    -    }
    -
    -    // Low-level methods
    -    public String getID() {
    -        return CHANGEID_OID;
    -    }
    -    public byte[] getEncodedValue() {
    -        return // original berVal
    -    }
    -    ...
    -}
    -public class VendorXControlFactory extends ControlFactory {
    -    public VendorXControlFactory () {
    -    }
    -
    -    public Control getControlInstance(Control orig) throws NamingException {
    -        if (isOneOfMyControls(orig.getID())) {
    -	    ...
    -
    -	    // determine which of ours it is and call its constructor
    -	    return (new ChangeIDControl(orig.getID(), orig.getEncodedValue()));
    -	}
    -        return null;  // not one of ours
    -    }
    -}
    -
    - -

    Package Specification

    - -The JNDI API Specification and related documents can be found in the -{@extLink jndi_overview JNDI documentation}. - -@since 1.3 - - - diff --git a/src/java.naming/share/classes/javax/naming/ldap/spi/package-info.java b/src/java.naming/share/classes/javax/naming/ldap/spi/package-info.java new file mode 100644 index 0000000000000..20f3ea258ef40 --- /dev/null +++ b/src/java.naming/share/classes/javax/naming/ldap/spi/package-info.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * + * Provides the Service Provider Interface for DNS lookups when + * performing LDAP operations. + * + * @since 12 + */ +package javax.naming.ldap.spi; diff --git a/src/java.naming/share/classes/javax/naming/package-info.java b/src/java.naming/share/classes/javax/naming/package-info.java new file mode 100644 index 0000000000000..edcc76506efe1 --- /dev/null +++ b/src/java.naming/share/classes/javax/naming/package-info.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * Provides the classes and interfaces for accessing naming services. + * + *

    + * This package defines the naming operations of the Java Naming and + * Directory Interface (JNDI).   + * JNDI provides naming and directory functionality to applications + * written in the Java programming language. It is designed to be + * independent of any specific naming or directory service + * implementation. Thus a variety of services--new, emerging, and + * already deployed ones--can be accessed in a common way. + * + * + *

    Context

    + *

    + * This package defines the notion of a context, represented + * by the {@code Context} interface. + * A context consists of a set of name-to-object bindings. + * {@code Context} is the core interface for looking up, binding, unbinding, + * and renaming objects, and for creating and destroying subcontexts. + *

    + * {@code lookup()} is the most commonly used operation. + * You supply {@code lookup()} + * the name of the object you want + * to look up, and it returns the object bound to that name. + * For example, the following code fragment looks up + * a printer and sends a document to the printer object + * to be printed: + * + * {@snippet : + * Printer printer = (Printer)ctx.lookup("treekiller"); + * printer.print(report); + * } + * + *

    Names

    + *

    + * Every naming method in the {@code Context} + * interface has two + * overloads: one that accepts a + * {@code Name} argument and one that accepts a string name. + * {@code Name} is an interface that represents a generic + * name--an ordered sequence of zero of more components. + * For these methods, {@code Name} can be used to represent a + * composite name ({@code CompositeName}) + * so that you can name an object using a name which spans multiple namespaces. + *

    + * The overloads that accept {@code Name} + * are useful for applications that need to manipulate names: composing + * them, comparing components, and so on. + * The overloads that accept string names are likely to be more useful + * for simple applications, such as those that simply read in a name + * and look up the corresponding object. + * + *

    Bindings

    + * + * The {@code Binding} class represents a name-to-object binding. + * It is a tuple containing the name of the bound object, + * the name of the object's class, and the object itself. + *

    + * The {@code Binding} class is actually a subclass of + * {@code NameClassPair}, which consists + * simply of the object's name and the object's class name. + * The {@code NameClassPair} is useful when you only want + * information about the object's class and do not want to + * pay the extra cost of getting the object. + * + *

    References

    + * Objects are stored in naming and directory services in different ways. + * If an object store supports storing Java objects, + * it might support storing an object in its serialized form. + * However, some naming and directory services do not support the + * storing of Java objects. Furthermore, for some + * objects in the directory, Java programs are but one group of applications + * that access them. In this case, a serialized Java object might + * not be the most appropriate representation. + * JNDI defines a reference, represented by the {@code Reference} + * class, which contains information on how to construct a copy of the object. + * JNDI will attempt to turn references looked up from the directory + * into the Java objects they represent, so that + * JNDI clients have the illusion that what + * is stored in the directory are Java objects. + * + * + *

    The Initial Context

    + * + * In JNDI, all naming and directory operations are performed relative + * to a context. There are no absolute roots. + * Therefore JNDI defines an initial context, + * {@code InitialContext}, + * which provides a starting point for naming and directory operations. + * Once you have an initial context, you can use it to + * look up other contexts and objects. + * + *

    Exceptions

    + * + * JNDI defines a class hierarchy for exceptions that can be thrown in + * the course of performing naming and directory operations. The root of + * this class hierarchy is {@code NamingException}. + * Programs interested in dealing with a particular exception + * can catch the corresponding subclass of the exception. + * Otherwise, programs should catch {@code NamingException}. + * + * + *

    Package Specification

    + * + * The JNDI API Specification and related documents can be found in the + * {@extLink jndi_overview JNDI documentation}. + * + * @since 1.3 + */ +package javax.naming; diff --git a/src/java.naming/share/classes/javax/naming/package.html b/src/java.naming/share/classes/javax/naming/package.html deleted file mode 100644 index 67e046f84c6ab..0000000000000 --- a/src/java.naming/share/classes/javax/naming/package.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - -Provides the classes and interfaces for accessing naming services. - -

    -This package defines the naming operations of the Java Naming and -Directory Interface (JNDI).   -JNDI provides naming and directory functionality to applications -written in the Java programming language. It is designed to be -independent of any specific naming or directory service -implementation. Thus a variety of services--new, emerging, and -already deployed ones--can be accessed in a common way. - - -

    Context

    -

    -This package defines the notion of a context, represented -by the Context interface. -A context consists of a set of name-to-object bindings. -Context is the core interface for looking up, binding, unbinding, -and renaming objects, and for creating and destroying subcontexts. -

    -lookup() is the most commonly used operation. -You supply lookup() -the name of the object you want -to look up, and it returns the object bound to that name. -For example, the following code fragment looks up -a printer and sends a document to the printer object -to be printed: - -

    -
    -Printer printer = (Printer)ctx.lookup("treekiller");
    -printer.print(report);
    -
    -
    - -

    Names

    -

    -Every naming method in the Context -interface has two -overloads: one that accepts a -Name argument and one that accepts a string name. -Name is an interface that represents a generic -name--an ordered sequence of zero of more components. -For these methods, Name can be used to represent a -composite name (CompositeName) -so that you can name an object using a name which spans multiple namespaces. -

    -The overloads that accept Name -are useful for applications that need to manipulate names: composing -them, comparing components, and so on. -The overloads that accept string names are likely to be more useful -for simple applications, such as those that simply read in a name -and look up the corresponding object. - -

    Bindings

    - -The Binding class represents a name-to-object binding. -It is a tuple containing the name of the bound object, -the name of the object's class, and the object itself. -

    -The Binding class is actually a subclass of -NameClassPair, which consists -simply of the object's name and the object's class name. -The NameClassPair is useful when you only want -information about the object's class and do not want to -pay the extra cost of getting the object. - -

    References

    -Objects are stored in naming and directory services in different ways. -If an object store supports storing Java objects, -it might support storing an object in its serialized form. -However, some naming and directory services do not support the -storing of Java objects. Furthermore, for some -objects in the directory, Java programs are but one group of applications -that access them. In this case, a serialized Java object might -not be the most appropriate representation. -JNDI defines a reference, represented by the Reference -class, which contains information on how to construct a copy of the object. -JNDI will attempt to turn references looked up from the directory -into the Java objects they represent, so that -JNDI clients have the illusion that what -is stored in the directory are Java objects. - - -

    The Initial Context

    - -In JNDI, all naming and directory operations are performed relative -to a context. There are no absolute roots. -Therefore JNDI defines an initial context, -InitialContext, -which provides a starting point for naming and directory operations. -Once you have an initial context, you can use it to -look up other contexts and objects. - -

    Exceptions

    - -JNDI defines a class hierarchy for exceptions that can be thrown in -the course of performing naming and directory operations. The root of -this class hierarchy is NamingException. -Programs interested in dealing with a particular exception -can catch the corresponding subclass of the exception. -Otherwise, programs should catch NamingException. - - -

    Package Specification

    - -The JNDI API Specification and related documents can be found in the -{@extLink jndi_overview JNDI documentation}. - -@since 1.3 - - - diff --git a/src/java.naming/share/classes/javax/naming/spi/package-info.java b/src/java.naming/share/classes/javax/naming/spi/package-info.java new file mode 100644 index 0000000000000..382a35a17e8ba --- /dev/null +++ b/src/java.naming/share/classes/javax/naming/spi/package-info.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + * Provides the means for dynamically plugging in support for accessing + * naming and directory services through the {@code javax.naming} + * and related packages. + * + *

    + * This package defines the service provider interface (SPI) of the Java Naming + * and Directory Interface (JNDI).   + * JNDI provides naming and directory functionality to applications + * written in the Java programming language. It is designed to be + * independent of any specific naming or directory service + * implementation. Thus a variety of services--new, emerging, and + * already deployed ones--can be accessed in a common way. + * + *

    + * The JNDI SPI provides the means for creating JNDI service providers, + * through which JNDI applications access different naming and + * directory services. + * + * + *

    Plug-in Architecture

    + * + * The service provider package allows different implementations to be plugged in + * dynamically. + * These different implementations include those for the + * initial context, + * and implementations for contexts that can be reached + * from the initial context. + * + *

    Java Object Support

    + * + * The service provider package provides support + * for implementors of the + * {@code javax.naming.Context.lookup()} + * method and related methods to return Java objects that are natural + * and intuitive for the Java programmer. + * For example, when looking up a printer name from the directory, + * it is natural for you to expect to get + * back a printer object on which to operate. + * + * + *

    Multiple Naming Systems (Federation)

    + * + * JNDI operations allow applications to supply names that span multiple + * naming systems. So in the process of completing + * an operation, one service provider might need to interact + * with another service provider, for example, to pass on + * the operation to be continued in the next naming system. + * The service provider package provides support for + * different providers to cooperate to complete JNDI operations. + * + * + *

    Package Specification

    + * + * The JNDI SPI Specification and related documents can be found in the + * {@extLink jndi_overview JNDI documentation}. + * + * @since 1.3 + */ +package javax.naming.spi; diff --git a/src/java.naming/share/classes/javax/naming/spi/package.html b/src/java.naming/share/classes/javax/naming/spi/package.html deleted file mode 100644 index f523c76deb4b5..0000000000000 --- a/src/java.naming/share/classes/javax/naming/spi/package.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - -Provides the means for dynamically plugging in support for accessing -naming and directory services through the javax.naming -and related packages. - -

    -This package defines the service provider interface (SPI) of the Java Naming -and Directory Interface (JNDI).   -JNDI provides naming and directory functionality to applications -written in the Java programming language. It is designed to be -independent of any specific naming or directory service -implementation. Thus a variety of services--new, emerging, and -already deployed ones--can be accessed in a common way. - -

    -The JNDI SPI provides the means for creating JNDI service providers, -through which JNDI applications access different naming and -directory services. - - -

    Plug-in Architecture

    - -The service provider package allows different implementations to be plugged in -dynamically. -These different implementations include those for the -initial context, -and implementations for contexts that can be reached -from the initial context. - -

    Java Object Support

    - -The service provider package provides support -for implementors of the -javax.naming.Context.lookup() -method and related methods to return Java objects that are natural -and intuitive for the Java programmer. -For example, when looking up a printer name from the directory, -it is natural for you to expect to get -back a printer object on which to operate. - - -

    Multiple Naming Systems (Federation)

    - -JNDI operations allow applications to supply names that span multiple -naming systems. So in the process of completing -an operation, one service provider might need to interact -with another service provider, for example, to pass on -the operation to be continued in the next naming system. -The service provider package provides support for -different providers to cooperate to complete JNDI operations. - - -

    Package Specification

    - -The JNDI SPI Specification and related documents can be found in the -{@extLink jndi_overview JNDI documentation}. - -@since 1.3 - - - From b0efd7740243916ba22178524ab2ede9e5436d94 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 4 Jul 2024 12:42:47 +0000 Subject: [PATCH 166/288] 8314653: Metaspace: remove allocation guard feature Reviewed-by: azafari, dholmes --- .../share/memory/metaspace/metaspaceArena.cpp | 41 +---------- .../share/memory/metaspace/metaspaceArena.hpp | 24 +------ .../memory/metaspace/metaspaceSettings.cpp | 8 +-- .../memory/metaspace/metaspaceSettings.hpp | 6 +- src/hotspot/share/runtime/globals.hpp | 3 - .../gtest/metaspace/test_allocationGuard.cpp | 69 ------------------- .../gtest/metaspace/test_metaspacearena.cpp | 22 ------ .../metaspace/test_metaspacearena_stress.cpp | 4 +- test/hotspot/jtreg/gtest/MetaspaceGtests.java | 18 ++--- .../runtime/Metaspace/PrintMetaspaceDcmd.java | 13 +--- .../elastic/MetaspaceTestContext.java | 10 +-- .../runtime/Metaspace/elastic/Settings.java | 4 +- .../elastic/TestMetaspaceAllocation.java | 16 ++--- .../elastic/TestMetaspaceAllocationMT1.java | 23 +------ .../elastic/TestMetaspaceAllocationMT2.java | 23 +------ 15 files changed, 21 insertions(+), 263 deletions(-) delete mode 100644 test/hotspot/gtest/metaspace/test_allocationGuard.cpp diff --git a/src/hotspot/share/memory/metaspace/metaspaceArena.cpp b/src/hotspot/share/memory/metaspace/metaspaceArena.cpp index 8c5ebfed289f4..92d7d0ea7eba1 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceArena.cpp +++ b/src/hotspot/share/memory/metaspace/metaspaceArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -117,9 +117,6 @@ MetaspaceArena::MetaspaceArena(ChunkManager* chunk_manager, const ArenaGrowthPol _fbl(nullptr), _total_used_words_counter(total_used_words_counter), _name(name) -#ifdef ASSERT - , _first_fence(nullptr) -#endif { UL(debug, ": born."); @@ -128,14 +125,7 @@ MetaspaceArena::MetaspaceArena(ChunkManager* chunk_manager, const ArenaGrowthPol } MetaspaceArena::~MetaspaceArena() { -#ifdef ASSERT - SOMETIMES(verify();) - if (Settings::use_allocation_guard()) { - verify_allocation_guards(); - } -#endif MemRangeCounter return_counter; - Metachunk* c = _chunks.first(); Metachunk* c2 = nullptr; @@ -239,23 +229,6 @@ MetaWord* MetaspaceArena::allocate(size_t requested_word_size) { // Primary allocation p = allocate_inner(aligned_word_size); -#ifdef ASSERT - // Fence allocation - if (p != nullptr && Settings::use_allocation_guard()) { - STATIC_ASSERT(is_aligned(sizeof(Fence), BytesPerWord)); - MetaWord* guard = allocate_inner(sizeof(Fence) / BytesPerWord); - if (guard != nullptr) { - // Ignore allocation errors for the fence to keep coding simple. If this - // happens (e.g. because right at this time we hit the Metaspace GC threshold) - // we miss adding this one fence. Not a big deal. Note that his would - // be pretty rare. Chances are much higher the primary allocation above - // would have already failed). - Fence* f = new(guard) Fence(_first_fence); - _first_fence = f; - } - } -#endif // ASSERT - return p; } @@ -427,18 +400,6 @@ void MetaspaceArena::verify() const { } } -void MetaspaceArena::Fence::verify() const { - assert(_eye1 == EyeCatcher && _eye2 == EyeCatcher, - "Metaspace corruption: fence block at " PTR_FORMAT " broken.", p2i(this)); -} - -void MetaspaceArena::verify_allocation_guards() const { - assert(Settings::use_allocation_guard(), "Don't call with guards disabled."); - for (const Fence* f = _first_fence; f != nullptr; f = f->next()) { - f->verify(); - } -} - // Returns true if the area indicated by pointer and size have actually been allocated // from this arena. bool MetaspaceArena::is_valid_area(MetaWord* p, size_t word_size) const { diff --git a/src/hotspot/share/memory/metaspace/metaspaceArena.hpp b/src/hotspot/share/memory/metaspace/metaspaceArena.hpp index 58d80e97e172c..77eb939c6b4d8 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceArena.hpp +++ b/src/hotspot/share/memory/metaspace/metaspaceArena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -100,28 +100,6 @@ class MetaspaceArena : public CHeapObj { // A name for purely debugging/logging purposes. const char* const _name; -#ifdef ASSERT - // Allocation guards: When active, arena allocations are interleaved with - // fence allocations. An overwritten fence indicates a buffer overrun in either - // the preceding or the following user block. All fences are linked together; - // validating the fences just means walking that linked list. - // Note that for the Arena, fence blocks are just another form of user blocks. - class Fence { - static const uintx EyeCatcher = - NOT_LP64(0x77698465) LP64_ONLY(0x7769846577698465ULL); // "META" resp "METAMETA" - // Two eyecatchers to easily spot a corrupted _next pointer - const uintx _eye1; - const Fence* const _next; - NOT_LP64(uintx _dummy;) - const uintx _eye2; - public: - Fence(const Fence* next) : _eye1(EyeCatcher), _next(next), _eye2(EyeCatcher) {} - const Fence* next() const { return _next; } - void verify() const; - }; - const Fence* _first_fence; -#endif // ASSERT - ChunkManager* chunk_manager() const { return _chunk_manager; } // free block list diff --git a/src/hotspot/share/memory/metaspace/metaspaceSettings.cpp b/src/hotspot/share/memory/metaspace/metaspaceSettings.cpp index 7dc742755b65e..b812341a2da34 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceSettings.cpp +++ b/src/hotspot/share/memory/metaspace/metaspaceSettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -36,8 +36,6 @@ namespace metaspace { -DEBUG_ONLY(bool Settings::_use_allocation_guard = false;) - void Settings::ergo_initialize() { // Granules must be a multiple of page size, and a power-2-value. @@ -46,9 +44,6 @@ void Settings::ergo_initialize() { "Granule size must be a page-size-aligned power-of-2 value"); assert(commit_granule_words() <= chunklevel::MAX_CHUNK_WORD_SIZE, "Too large granule size"); - // Off for release builds, off by default - but switchable - for debug builds. - DEBUG_ONLY(_use_allocation_guard = MetaspaceGuardAllocations;) - LogStream ls(Log(metaspace)::info()); Settings::print_on(&ls); } @@ -58,7 +53,6 @@ void Settings::print_on(outputStream* st) { st->print_cr(" - commit_granule_words: " SIZE_FORMAT ".", commit_granule_words()); st->print_cr(" - virtual_space_node_default_size: " SIZE_FORMAT ".", virtual_space_node_default_word_size()); st->print_cr(" - enlarge_chunks_in_place: %d.", (int)enlarge_chunks_in_place()); - st->print_cr(" - use_allocation_guard: %d.", (int)use_allocation_guard()); } } // namespace metaspace diff --git a/src/hotspot/share/memory/metaspace/metaspaceSettings.hpp b/src/hotspot/share/memory/metaspace/metaspaceSettings.hpp index 93be0eb6fe63e..84dcf8d2f0f09 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceSettings.hpp +++ b/src/hotspot/share/memory/metaspace/metaspaceSettings.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2023 SAP SE. All rights reserved. - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,9 +56,6 @@ class Settings : public AllStatic { // the requested size, we attempt to double the chunk size in place... static const bool _enlarge_chunks_in_place = true; - // If true, metablock allocations are guarded and periodically checked. - DEBUG_ONLY(static bool _use_allocation_guard;) - public: static size_t commit_granule_bytes() { return _commit_granule_bytes; } @@ -66,7 +63,6 @@ class Settings : public AllStatic { static size_t virtual_space_node_default_word_size() { return _virtual_space_node_default_word_size; } static size_t virtual_space_node_reserve_alignment_words() { return _virtual_space_node_reserve_alignment_words; } static bool enlarge_chunks_in_place() { return _enlarge_chunks_in_place; } - static bool use_allocation_guard() { return DEBUG_ONLY(_use_allocation_guard) NOT_DEBUG(false); } static void ergo_initialize(); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 468e9bd880086..cbd161d86eb48 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1408,9 +1408,6 @@ const int ObjectAlignmentInBytes = 8; product(bool, PrintMetaspaceStatisticsAtExit, false, DIAGNOSTIC, \ "Print metaspace statistics upon VM exit.") \ \ - develop(bool, MetaspaceGuardAllocations, false, \ - "Metapace allocations are guarded.") \ - \ product(uintx, MinHeapFreeRatio, 40, MANAGEABLE, \ "The minimum percentage of heap free after GC to avoid expansion."\ " For most GCs this applies to the old generation. In G1 and" \ diff --git a/test/hotspot/gtest/metaspace/test_allocationGuard.cpp b/test/hotspot/gtest/metaspace/test_allocationGuard.cpp deleted file mode 100644 index 9b0eb3d69a5df..0000000000000 --- a/test/hotspot/gtest/metaspace/test_allocationGuard.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 SAP SE. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "memory/metaspace/metaspaceArena.hpp" -#include "memory/metaspace/metaspaceSettings.hpp" -#include "memory/metaspace/testHelpers.hpp" -#include "utilities/debug.hpp" -#include "utilities/ostream.hpp" - -//#define LOG_PLEASE -#include "metaspaceGtestCommon.hpp" -#include "metaspaceGtestContexts.hpp" - -#ifdef ASSERT - -using metaspace::MetaspaceArena; -using metaspace::MetaspaceTestArena; -using metaspace::Settings; - -// Test that overwriting memory triggers an assert if allocation guards are enabled. -// Note: We use TEST_VM_ASSERT_MSG. However, an assert is only triggered if allocation -// guards are enabled; if guards are disabled for the gtests, this test would fail. -// So for that case, we trigger a fake assert. -TEST_VM_ASSERT_MSG(metaspace, test_overwriter, ".*Metaspace corruption.*") { - - if (Settings::use_allocation_guard()) { - MetaspaceGtestContext context; - MetaspaceTestArena* arena = context.create_arena(Metaspace::StandardMetaspaceType); - // We allocate two blocks. We then write over the end of the first block, which - // should corrupt the fence between the two blocks. - // Note: there is of course no guarantee that blocks allocated sequentially are neighbors; - // but in this case (clean standard-sized test arena and very small allocations) it can - // be safely assumed). - MetaWord* p1 = arena->allocate(8); - MetaWord* p2 = arena->allocate(2); - p1[8] = (MetaWord)0x9345; // Overwriter - // Now we delete the arena (as happens during class unloading); this will check all - // block canaries and should trigger an assert (see MetaspaceArena::verify_allocation_guards()). - delete arena; - } else { - assert(false, "Metaspace corruption - please ignore this, fake message to satisfy tests"); - } - -} - -#endif // ASSERT diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index f7474da22c065..aee53ea32aa16 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -291,11 +291,6 @@ TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_nc) { // Here, we give it an ideal policy which should enable the initial chunk to grow unmolested // until finish. TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_2) { - - if (Settings::use_allocation_guard()) { - return; - } - // Note: internally, chunk in-place enlargement is disallowed if growing the chunk // would cause the arena to claim more memory than its growth policy allows. This // is done to prevent the arena to grow too fast. @@ -337,11 +332,6 @@ TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_2) { // test that in place enlargement correctly fails if growing the chunk would bring us // beyond the max. size of a chunk. TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_max_chunk_size) { - - if (Settings::use_allocation_guard()) { - return; - } - MetaspaceGtestContext context; for (size_t first_allocation_size = 1; first_allocation_size <= MAX_CHUNK_WORD_SIZE / 2; first_allocation_size *= 2) { @@ -372,11 +362,6 @@ TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_max_chunk_siz // test that in place enlargement correctly fails if growing the chunk would cause more // than doubling its size TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_doubling_chunk_size) { - - if (Settings::use_allocation_guard()) { - return; - } - MetaspaceGtestContext context; MetaspaceArenaTestHelper helper(context, Metaspace::StandardMetaspaceType, false); @@ -399,9 +384,6 @@ TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_doubling_chun // Allocate, deallocate, then allocate the same block again. The second allocate should // reuse the deallocated block. TEST_VM(metaspace, MetaspaceArena_deallocate) { - if (Settings::use_allocation_guard()) { - return; - } for (size_t s = 2; s <= MAX_CHUNK_WORD_SIZE; s *= 2) { MetaspaceGtestContext context; MetaspaceArenaTestHelper helper(context, Metaspace::StandardMetaspaceType, false); @@ -505,10 +487,6 @@ static void test_controlled_growth(Metaspace::MetaspaceType type, bool is_class, bool test_in_place_enlargement) { - if (Settings::use_allocation_guard()) { - return; - } - // From a MetaspaceArena in a clean room allocate tiny amounts; // watch it grow. Used/committed/capacity should not grow in // large jumps. Also, different types of MetaspaceArena should diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp index 7d3df0798025e..e94f733e45b2d 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp @@ -106,15 +106,13 @@ class MetaspaceArenaTestBed : public CHeapObj { // - alignment/padding of allocations // - inside used counter contains blocks in free list // - free block list splinter threshold - // - if +MetaspaceGuardAllocations, guard costs // Since what we deallocated may have been given back to us in a following allocation, // we only know fore sure we allocated what we did not give back. const size_t at_least_allocated = _alloc_count.total_size() - _dealloc_count.total_size(); // At most we allocated this: - const size_t max_word_overhead_per_alloc = - 4 + (metaspace::Settings::use_allocation_guard() ? 4 : 0); + constexpr size_t max_word_overhead_per_alloc = 4; const size_t at_most_allocated = _alloc_count.total_size() + max_word_overhead_per_alloc * _alloc_count.count(); ASSERT_LE(at_least_allocated, in_use_stats._used_words - stats._free_blocks_word_size); diff --git a/test/hotspot/jtreg/gtest/MetaspaceGtests.java b/test/hotspot/jtreg/gtest/MetaspaceGtests.java index 4710c5910295e..f1f811d6a7183 100644 --- a/test/hotspot/jtreg/gtest/MetaspaceGtests.java +++ b/test/hotspot/jtreg/gtest/MetaspaceGtests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,8 +25,8 @@ /* * Note: This runs the metaspace-related parts of gtest in configurations which - * are not tested explicitly in the standard gtests. - * + * are not tested explicitly in the standard gtest. Hence, there is no "default-ndebug" + * since that would be equivalent to the normal gtest for release builds. */ /* @test id=default-debug @@ -40,17 +40,7 @@ * @run main/native GTestWrapper --gtest_filter=metaspace* -XX:+UnlockDiagnosticVMOptions -XX:VerifyMetaspaceInterval=1 */ -/* @test id=balanced-with-guards - * @summary Run metaspace-related gtests with allocation guards enabled - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @requires vm.debug - * @requires vm.flagless - * @run main/native GTestWrapper --gtest_filter=metaspace* -XX:VerifyMetaspaceInterval=1 -XX:+MetaspaceGuardAllocations - */ - -/* @test id=balanced-no-ccs +/* @test id=no-ccs * @summary Run metaspace-related gtests with compressed class pointers off * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java b/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java index 56d9c2095b2eb..42f22309d9684 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java +++ b/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, SAP and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -36,17 +36,6 @@ * @run main/othervm -Dwith-compressed-class-space -XX:MaxMetaspaceSize=201M -Xmx100M -XX:+UseCompressedOops -XX:+UseCompressedClassPointers PrintMetaspaceDcmd */ -/* - * @test id=test-64bit-ccs-guarded - * @summary Test the VM.metaspace command - * @requires vm.bits == "64" - * @requires vm.debug == true - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main/othervm -Dwith-compressed-class-space -XX:MaxMetaspaceSize=201M -Xmx100M -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UnlockDiagnosticVMOptions -XX:+MetaspaceGuardAllocations PrintMetaspaceDcmd - */ - /* * @test id=test-64bit-noccs * @summary Test the VM.metaspace command diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java index 5061c828c0693..fe52317d4dd65 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/MetaspaceTestContext.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2023 SAP SE. All rights reserved. - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,17 +195,11 @@ public void checkStatistics() { // - whatever we allocated // - deallocated blocks in fbl // - remains of retired chunks in fbl - // - overhead per allocation (padding for alignment, possibly allocation guards) + // - overhead per allocation (padding for alignment) // Overhead per allocation (see metaspaceArena.cpp, get_raw_allocation_word_size() ) // Any allocation is 3 words least expectedMaxUsage += (numAllocated * 3); - if (Settings.settings().usesAllocationGuards) { - // Guards need space. - expectedMaxUsage += (numAllocated * 2); - // Also, they disable the fbl, so deallocated still counts as used. - expectedMaxUsage += deallocatedWords; - } // Lets add a overhead per arena. Each arena carries a free block list containing // deallocated/retired blocks. We do not know how much. In general, the free block list should not diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/Settings.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/Settings.java index c6d69f341b9dd..222ce44acc65f 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/Settings.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/Settings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,8 +27,6 @@ public final class Settings { - public boolean usesAllocationGuards = WhiteBox.getWhiteBox().getBooleanVMFlag("MetaspaceGuardAllocations"); - final static long rootChunkWordSize = 2048 * 1024; static Settings theSettings; diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocation.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocation.java index 1ecde3f83764e..10d05a867fc61 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocation.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocation.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2023 SAP SE. All rights reserved. - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,30 +27,22 @@ * @test id=debug * @bug 8251158 * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management + * @modules java.base/jdk.internal.misc java.management * @build jdk.test.whitebox.WhiteBox * @requires (vm.debug == true) - * * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:VerifyMetaspaceInterval=10 TestMetaspaceAllocation - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:VerifyMetaspaceInterval=10 -XX:+MetaspaceGuardAllocations TestMetaspaceAllocation - * */ /* * @test id=ndebug * @bug 8251158 * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management + * @modules java.base/jdk.internal.misc java.management * @build jdk.test.whitebox.WhiteBox * @requires (vm.debug == false) - * * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestMetaspaceAllocation + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestMetaspaceAllocation */ public class TestMetaspaceAllocation { diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT1.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT1.java index 8bbab2c71e96a..5676f2c4bdb0a 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT1.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT1.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2023 SAP SE. All rights reserved. - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ */ /* - * @test id=debug-default-strict + * @test id=debug-default-long-manual * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -74,24 +74,6 @@ * TestMetaspaceAllocationMT1 10 */ -/* - * @test id=debug-guard - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @key randomness - * @requires (vm.debug == true) - * - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * - * @run main/othervm/timeout=400 - * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:VerifyMetaspaceInterval=10 - * -XX:+MetaspaceGuardAllocations - * TestMetaspaceAllocationMT1 3 - */ - /* * @test id=ndebug-default * @library /test/lib @@ -130,7 +112,6 @@ public static void main(String[] args) throws Exception { System.out.println("#### seconds: " + seconds); System.out.println("#### commitLimit: " + commitLimit); System.out.println("#### reserveLimit: " + reserveLimit); - System.out.println("#### guards: " + Settings.settings().usesAllocationGuards); MetaspaceTestContext context = new MetaspaceTestContext(commitLimit, reserveLimit); MetaspaceTestOneArenaManyThreads test = new MetaspaceTestOneArenaManyThreads(context, testAllocationCeiling, numThreads, seconds); diff --git a/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT2.java b/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT2.java index 17e3bb99353b2..2c6b3923d9464 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT2.java +++ b/test/hotspot/jtreg/runtime/Metaspace/elastic/TestMetaspaceAllocationMT2.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2023 SAP SE. All rights reserved. - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ */ /* - * @test id=debug-default-strict + * @test id=debug-default-long-manual * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -74,24 +74,6 @@ * TestMetaspaceAllocationMT2 10 */ -/* - * @test id=debug-guard - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @key randomness - * @requires (vm.debug == true) - * - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * - * @run main/othervm/timeout=400 - * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:VerifyMetaspaceInterval=10 - * -XX:+MetaspaceGuardAllocations - * TestMetaspaceAllocationMT2 3 - */ - /* * @test id=ndebug-default * @library /test/lib @@ -129,7 +111,6 @@ public static void main(String[] args) throws Exception { System.out.println("#### seconds: " + seconds); System.out.println("#### commitLimit: " + commitLimit); System.out.println("#### reserveLimit: " + reserveLimit); - System.out.println("#### guards: " + Settings.settings().usesAllocationGuards); MetaspaceTestContext context = new MetaspaceTestContext(commitLimit, reserveLimit); MetaspaceTestManyArenasManyThreads test = new MetaspaceTestManyArenasManyThreads(context, testAllocationCeiling, numThreads, seconds); From da0ffa8b7ff04eb5cbc0fcbe4b858f20d7e46405 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Thu, 4 Jul 2024 13:35:24 +0000 Subject: [PATCH 167/288] 8334031: Generated JfrNativeSettings seems off Reviewed-by: egahlin --- make/src/classes/build/tools/jfr/GenerateJfrFiles.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java index 34e933eb22d23..7532a446aa162 100644 --- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java +++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java @@ -668,7 +668,7 @@ private static void printJfrEventControlHpp(Metadata metadata, File outputFile) out.write(" // add named struct members also."); out.write(" struct {"); out.write(" jfrNativeEventSetting pad[NUMBER_OF_RESERVED_EVENTS];"); - for (TypeElement t : metadata.getEventsAndStructs()) { + for (TypeElement t : metadata.getEvents()) { out.write(" jfrNativeEventSetting " + t.name + ";"); } out.write(" } ev;"); From 3050ba017687ac13e1bbccdd1544d25f8eb2a747 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan Date: Thu, 4 Jul 2024 14:09:45 +0000 Subject: [PATCH 168/288] 8335654: Remove stale hyperlink in divnode.cpp Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/divnode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index 9c6c6ed25dec2..967d6661eec54 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -266,7 +266,6 @@ static Node* long_by_long_mulhi(PhaseGVN* phase, Node* dividend, jlong magic_con } // Taken from Hacker's Delight, Fig. 8-2. Multiply high signed. - // (http://www.hackersdelight.org/HDcode/mulhs.c) // // int mulhs(int u, int v) { // unsigned u0, v0, w0; From f4fa35e28b9881729ac47c8518e758bba676fdec Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 4 Jul 2024 15:44:57 +0000 Subject: [PATCH 169/288] 8330954: since-checker - Fix remaining @ since tags in java.base Reviewed-by: liach, naoto --- .../classes/java/io/FileInputStream.java | 3 +++ .../java/lang/classfile/ClassSignature.java | 6 ++++- .../classes/java/lang/constant/ClassDesc.java | 3 +++ .../java/lang/constant/MethodHandleDesc.java | 3 +++ .../java/lang/constant/MethodTypeDesc.java | 2 ++ .../java/lang/foreign/MemorySegment.java | 2 ++ .../classes/java/lang/ref/Reference.java | 4 +--- .../share/classes/java/text/ChoiceFormat.java | 6 +++++ .../util/concurrent/CompletableFuture.java | 24 +++++++++++++++++++ .../java/util/concurrent/DelayQueue.java | 2 ++ .../java/util/concurrent/ForkJoinTask.java | 9 +++++++ .../java/util/concurrent/FutureTask.java | 9 +++++++ 12 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index 20bf57a56c77a..2750710823771 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -371,6 +371,9 @@ public byte[] readAllBytes() throws IOException { return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); } + /** + * @since 11 + */ @Override public byte[] readNBytes(int len) throws IOException { if (len < 0) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java index b3050b78a8568..852d5f9baf4f1 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java @@ -41,7 +41,11 @@ public sealed interface ClassSignature /** {@return the type parameters of this class} */ List typeParameters(); - /** {@return the instantiation of the superclass in this signature} */ + /** + * {@return the instantiation of the superclass in this signature} + * + * @since 23 + */ Signature.ClassTypeSig superclassSignature(); /** {@return the instantiation of the interfaces in this signature} */ diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 370d2eee507f6..d2da4ec5c85d3 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -374,6 +374,9 @@ else if (isArray()) { */ String descriptorString(); + /** + * @since 21 + */ @Override Class resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException; diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java index 616c5b6736597..6a3541bf5e930 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java @@ -207,6 +207,9 @@ default MethodHandleDesc asType(MethodTypeDesc type) { */ MethodTypeDesc invocationType(); + /** + * @since 21 + */ @Override MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException; diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java index 19bce254d496e..fb90b1f15c586 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java @@ -222,6 +222,8 @@ default String displayDescriptor() { * @apiNote {@linkplain MethodTypeDesc} can represent method type descriptors * that are not representable by {@linkplain MethodType}, such as methods with * more than 255 parameter slots, so attempts to resolve these may result in errors. + * + * @since 21 */ @Override MethodType resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException; diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 1b378512316a6..aa1f1762aec65 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -618,6 +618,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * // Take action (e.g. throw an Exception) * } * } + * + * @since 23 */ long maxByteAlignment(); diff --git a/src/java.base/share/classes/java/lang/ref/Reference.java b/src/java.base/share/classes/java/lang/ref/Reference.java index f29a293ce02c7..747aa64902f8e 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -521,8 +521,6 @@ public boolean enqueue() { * * @return never returns normally * @throws CloneNotSupportedException always - * - * @since 11 */ @Override protected Object clone() throws CloneNotSupportedException { diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index 5d71d9d726296..ccb6cc4a04f47 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -586,12 +586,18 @@ public Number parse(String text, ParsePosition status) { return Double.valueOf(bestNumber); } + /** + * @since 23 + */ @Override public boolean isStrict() { throw new UnsupportedOperationException( "ChoiceFormat does not utilize leniency when parsing"); } + /** + * @since 23 + */ @Override public void setStrict(boolean strict) { throw new UnsupportedOperationException( diff --git a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java index 32545155b53fa..1a43b29d798f3 100644 --- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java +++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java @@ -2178,6 +2178,9 @@ public T getNow(T valueIfAbsent) { return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r, "getNow"); } + /** + * @since 19 + */ @Override public T resultNow() { Object r = result; @@ -2193,6 +2196,9 @@ public T resultNow() { throw new IllegalStateException(); } + /** + * @since 19 + */ @Override public Throwable exceptionNow() { Object r = result; @@ -2440,26 +2446,41 @@ public CompletableFuture exceptionally( return uniExceptionallyStage(null, fn); } + /** + * @since 12 + */ public CompletableFuture exceptionallyAsync( Function fn) { return uniExceptionallyStage(defaultExecutor(), fn); } + /** + * @since 12 + */ public CompletableFuture exceptionallyAsync( Function fn, Executor executor) { return uniExceptionallyStage(screenExecutor(executor), fn); } + /** + * @since 12 + */ public CompletableFuture exceptionallyCompose( Function> fn) { return uniComposeExceptionallyStage(null, fn); } + /** + * @since 12 + */ public CompletableFuture exceptionallyComposeAsync( Function> fn) { return uniComposeExceptionallyStage(defaultExecutor(), fn); } + /** + * @since 12 + */ public CompletableFuture exceptionallyComposeAsync( Function> fn, Executor executor) { @@ -2585,6 +2606,9 @@ public boolean isCompletedExceptionally() { return ((r = result) instanceof AltResult) && r != NIL; } + /** + * @since 19 + */ @Override public State state() { Object r = result; diff --git a/src/java.base/share/classes/java/util/concurrent/DelayQueue.java b/src/java.base/share/classes/java/util/concurrent/DelayQueue.java index c53a02ddf71c3..abd14142da52d 100644 --- a/src/java.base/share/classes/java/util/concurrent/DelayQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/DelayQueue.java @@ -327,6 +327,8 @@ public E poll(long timeout, TimeUnit unit) throws InterruptedException { * @return the expired head of this queue * @throws NoSuchElementException if this queue has no elements with an * expired delay + * + * @since 21 */ public E remove() { return super.remove(); diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index e58af0b0fa5a8..8ca52dc5cb29d 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -887,6 +887,9 @@ public final boolean isCompletedNormally() { return (status & (DONE | ABNORMAL)) == DONE; } + /** + * @since 19 + */ @Override public State state() { int s = status; @@ -896,6 +899,9 @@ public State state() { State.CANCELLED; } + /** + * @since 19 + */ @Override public V resultNow() { int s = status; @@ -910,6 +916,9 @@ public V resultNow() { return getRawResult(); } + /** + * @since 19 + */ @Override public Throwable exceptionNow() { Throwable ex; diff --git a/src/java.base/share/classes/java/util/concurrent/FutureTask.java b/src/java.base/share/classes/java/util/concurrent/FutureTask.java index 371055d2c11d2..627e69559c856 100644 --- a/src/java.base/share/classes/java/util/concurrent/FutureTask.java +++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java @@ -205,6 +205,9 @@ public V get(long timeout, TimeUnit unit) return report(s); } + /** + * @since 19 + */ @Override public V resultNow() { switch (state()) { // Future.State @@ -221,6 +224,9 @@ public V resultNow() { } } + /** + * @since 19 + */ @Override public Throwable exceptionNow() { switch (state()) { // Future.State @@ -236,6 +242,9 @@ public Throwable exceptionNow() { } } + /** + * @since 19 + */ @Override public State state() { int s = state; From cff9e246cc2fbd3914f40bb71daa85dcf7731396 Mon Sep 17 00:00:00 2001 From: Liang Mao Date: Fri, 5 Jul 2024 02:29:07 +0000 Subject: [PATCH 170/288] 8335493: check_gc_overhead_limit should reset SoftRefPolicy::_should_clear_all_soft_refs Reviewed-by: ayang --- src/hotspot/share/gc/shared/gcOverheadChecker.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/gcOverheadChecker.cpp b/src/hotspot/share/gc/shared/gcOverheadChecker.cpp index acbc1d65c26a4..18a92caf5dfb1 100644 --- a/src/hotspot/share/gc/shared/gcOverheadChecker.cpp +++ b/src/hotspot/share/gc/shared/gcOverheadChecker.cpp @@ -40,7 +40,11 @@ void GCOverheadChecker::check_gc_overhead_limit(GCOverheadTester* time_overhead, bool is_full_gc, GCCause::Cause gc_cause, SoftRefPolicy* soft_ref_policy) { - + if (is_full_gc) { + // Explicit Full GC would do the clearing of soft-refs as well + // So reset in the beginning + soft_ref_policy->set_should_clear_all_soft_refs(false); + } // Ignore explicit GC's. Exiting here does not set the flag and // does not reset the count. if (GCCause::is_user_requested_gc(gc_cause) || From b9d8056d5c1528198ad373f9b4a09547e2fcabd6 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Fri, 5 Jul 2024 04:49:01 +0000 Subject: [PATCH 171/288] 8332124: Jcmd should recognise options that look like requests for help Reviewed-by: kevinw, stuefe --- .../share/services/diagnosticFramework.cpp | 29 ++++- .../share/services/diagnosticFramework.hpp | 5 +- .../tools/jcmd/TestJcmdSubcommandHelp.java | 119 ++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 test/jdk/sun/tools/jcmd/TestJcmdSubcommandHelp.java diff --git a/src/hotspot/share/services/diagnosticFramework.cpp b/src/hotspot/share/services/diagnosticFramework.cpp index 984122f2777f5..73aa80a950f93 100644 --- a/src/hotspot/share/services/diagnosticFramework.cpp +++ b/src/hotspot/share/services/diagnosticFramework.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -400,7 +400,15 @@ void DCmd::parse_and_execute(DCmdSource source, outputStream* out, break; } if (line.is_executable()) { + // Allow for " -h|-help|--help" to enable the help diagnostic command. + // Ignores any additional arguments. ResourceMark rm; + stringStream updated_line; + if (reorder_help_cmd(line, updated_line)) { + CmdLine updated_cmd(updated_line.base(), updated_line.size(), false); + line = updated_cmd; + } + DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK); assert(command != nullptr, "command error must be handled before this line"); DCmdMark mark(command); @@ -411,6 +419,25 @@ void DCmd::parse_and_execute(DCmdSource source, outputStream* out, } } +bool DCmd::reorder_help_cmd(CmdLine line, stringStream &updated_line) { + stringStream args; + args.print("%s", line.args_addr()); + char* rest = args.as_string(); + char* token = strtok_r(rest, " ", &rest); + while (token != NULL) { + if (strcmp(token, "-h") == 0 || strcmp(token, "--help") == 0 || + strcmp(token, "-help") == 0) { + updated_line.print("%s", "help "); + updated_line.write(line.cmd_addr(), line.cmd_len()); + updated_line.write("\0", 1); + return true; + } + token = strtok_r(rest, " ", &rest); + } + + return false; +} + void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) { _dcmdparser.parse(line, delim, CHECK); } diff --git a/src/hotspot/share/services/diagnosticFramework.hpp b/src/hotspot/share/services/diagnosticFramework.hpp index 898f29274eaa1..e8881c2364611 100644 --- a/src/hotspot/share/services/diagnosticFramework.hpp +++ b/src/hotspot/share/services/diagnosticFramework.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -312,6 +312,9 @@ class DCmd : public AnyObj { // management.cpp every time. static void register_dcmds(); + // Helper method to substitute help options " -h|-help|--help" + // for "help ". + static bool reorder_help_cmd(CmdLine line, stringStream& updated_line); }; class DCmdWithParser : public DCmd { diff --git a/test/jdk/sun/tools/jcmd/TestJcmdSubcommandHelp.java b/test/jdk/sun/tools/jcmd/TestJcmdSubcommandHelp.java new file mode 100644 index 0000000000000..dee26ac5a17ba --- /dev/null +++ b/test/jdk/sun/tools/jcmd/TestJcmdSubcommandHelp.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8332124 + * @summary Test to verify jcmd accepts the "-help", "--help" and "-h" suboptions as a command argument + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run main/othervm TestJcmdSubcommandHelp + * + */ + +import jdk.test.lib.process.OutputAnalyzer; + + +public class TestJcmdSubcommandHelp { + + private static final String HELP_ONE_DASH = "-help"; + private static final String HELP_TWO_DASH = "--help"; + private static final String SINGLE_H = "-h"; + private static final String CMD = "VM.metaspace"; + private static final String ILLEGAL = "IllegalArgumentException: Unknown argument"; + + public static void main(String[] args) throws Exception { + + // Sanity check with empty input + OutputAnalyzer output = JcmdBase.jcmd(); + output.shouldContain("The following commands are available:"); + + // Sanity check with existing usage for "help " + output = JcmdBase.jcmd("help", CMD); + String expectedOutput = output.getOutput(); + output.shouldNotContain("Unknown diagnostic command"); + + testExpectedUsage(HELP_ONE_DASH, expectedOutput); + testExpectedUsage(HELP_TWO_DASH, expectedOutput); + testExpectedUsage(SINGLE_H, expectedOutput); + + testIgnoreAdditionalArgs(HELP_ONE_DASH, expectedOutput); + testIgnoreAdditionalArgs(HELP_TWO_DASH, expectedOutput); + testIgnoreAdditionalArgs(SINGLE_H, expectedOutput); + + testIgnoreTrailingSpaces(HELP_ONE_DASH, expectedOutput); + testIgnoreTrailingSpaces(HELP_TWO_DASH, expectedOutput); + testIgnoreTrailingSpaces(SINGLE_H, expectedOutput); + + testSimilarCommand(HELP_ONE_DASH + "less", ILLEGAL); + testSimilarCommand(HELP_TWO_DASH + "me", ILLEGAL); + testSimilarCommand(SINGLE_H + "ello", ILLEGAL); + } + + private static void testExpectedUsage(String helpOption, String expectedOutput) throws Exception { + verifyOutput(new String[] {CMD, helpOption}, expectedOutput, + "Expected jcmd to accept '%s' suboption as a command argument and issue the same help output.".formatted(helpOption)); + } + + private static void testIgnoreAdditionalArgs(String helpOption, String expectedOutput) throws Exception { + verifyOutput(new String[] {CMD, helpOption, "basic"}, expectedOutput, + "Expected jcmd to accept '%s' suboption with additional arguments after help.".formatted(helpOption)); + } + + private static void testIgnoreTrailingSpaces(String helpOption, String expectedOutput) throws Exception { + verifyOutput(new String[] {CMD, "%s ".formatted(helpOption)}, expectedOutput, + "Expected jcmd to accept '%s' suboption with trailing spaces".formatted(helpOption)); + } + + private static void testSimilarCommand(String helpOption, String expectedOutput) throws Exception { + verifyOutputContains(new String[] {CMD, helpOption}, expectedOutput, + "Expected jcmd to NOT accept '%s' suboption with trailing content".formatted(helpOption)); + } + + private static void verifyOutputContains(String[] args, String expectedOutput, String errorMessage) throws Exception { + OutputAnalyzer output = JcmdBase.jcmd(args); + String issuedOutput = output.getOutput(); + if (!issuedOutput.contains(expectedOutput)) { + printDifferingOutputs(expectedOutput, issuedOutput); + throw new Exception(errorMessage); + } + } + + private static void verifyOutput(String[] args, String expectedOutput, String errorMessage) throws Exception { + OutputAnalyzer output = JcmdBase.jcmd(args); + String issuedOutput = output.getOutput(); + if (!expectedOutput.equals(issuedOutput)) { + printDifferingOutputs(expectedOutput, issuedOutput); + throw new Exception(errorMessage); + } + } + + private static void printDifferingOutputs(String expectedOutput, String issuedOutput) { + System.out.println("Expected output: "); + System.out.println(expectedOutput); + System.out.println("Issued output: "); + System.out.println(issuedOutput); + } +} From 4ec1ae109710aa150e27acf5706475d335c4655c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 5 Jul 2024 07:18:34 +0000 Subject: [PATCH 172/288] 8331385: G1: Prefix HeapRegion helper classes with G1 Reviewed-by: ayang, dholmes --- src/hotspot/share/gc/g1/g1Arguments.cpp | 6 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 94 ++++++------ src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 54 +++---- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 30 ++-- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 26 ++-- .../share/gc/g1/g1CollectionSetCandidates.hpp | 4 +- .../share/gc/g1/g1CollectionSetChooser.cpp | 4 +- .../share/gc/g1/g1CommittedRegionMap.cpp | 22 +-- .../share/gc/g1/g1CommittedRegionMap.hpp | 12 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 28 ++-- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 4 +- .../gc/g1/g1ConcurrentRebuildAndScrub.cpp | 4 +- .../share/gc/g1/g1ConcurrentRefine.cpp | 6 +- .../share/gc/g1/g1EvacFailureRegions.cpp | 4 +- .../share/gc/g1/g1EvacFailureRegions.hpp | 8 +- src/hotspot/share/gc/g1/g1FullCollector.cpp | 2 +- .../share/gc/g1/g1FullGCAdjustTask.cpp | 4 +- .../share/gc/g1/g1FullGCAdjustTask.hpp | 4 +- .../share/gc/g1/g1FullGCCompactTask.hpp | 4 +- .../share/gc/g1/g1FullGCHeapRegionAttr.hpp | 4 +- .../share/gc/g1/g1FullGCPrepareTask.hpp | 8 +- .../share/gc/g1/g1FullGCResetMetadataTask.hpp | 6 +- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 26 ++-- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 40 ++--- .../share/gc/g1/g1HeapRegionBounds.hpp | 4 +- .../share/gc/g1/g1HeapRegionBounds.inline.hpp | 10 +- .../share/gc/g1/g1HeapRegionEventSender.cpp | 4 +- .../share/gc/g1/g1HeapRegionManager.cpp | 138 +++++++++--------- .../share/gc/g1/g1HeapRegionManager.hpp | 42 +++--- .../gc/g1/g1HeapRegionManager.inline.hpp | 16 +- .../share/gc/g1/g1HeapRegionPrinter.hpp | 2 +- .../share/gc/g1/g1HeapRegionRemSet.cpp | 36 ++--- .../share/gc/g1/g1HeapRegionRemSet.hpp | 8 +- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 18 +-- src/hotspot/share/gc/g1/g1HeapRegionSet.cpp | 62 ++++---- src/hotspot/share/gc/g1/g1HeapRegionSet.hpp | 54 +++---- .../share/gc/g1/g1HeapRegionSet.inline.hpp | 30 ++-- .../share/gc/g1/g1HeapRegionTracer.cpp | 4 +- .../share/gc/g1/g1HeapRegionTracer.hpp | 4 +- src/hotspot/share/gc/g1/g1HeapRegionType.cpp | 18 +-- src/hotspot/share/gc/g1/g1HeapRegionType.hpp | 16 +- src/hotspot/share/gc/g1/g1HeapTransition.cpp | 4 +- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 44 +++--- src/hotspot/share/gc/g1/g1NUMA.cpp | 4 +- src/hotspot/share/gc/g1/g1NUMA.hpp | 6 +- .../share/gc/g1/g1OopClosures.inline.hpp | 6 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 24 +-- src/hotspot/share/gc/g1/g1RemSet.hpp | 4 +- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 14 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 6 +- .../g1/g1YoungGCAllocationFailureInjector.cpp | 2 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 26 ++-- .../share/gc/g1/jvmFlagConstraintsG1.cpp | 6 +- src/hotspot/share/gc/g1/vmStructs_g1.hpp | 38 ++--- src/hotspot/share/prims/whitebox.cpp | 2 +- .../jvm/hotspot/gc/g1/G1CollectedHeap.java | 26 ++-- .../sun/jvm/hotspot/gc/g1/G1HeapRegion.java | 4 +- ...nClosure.java => G1HeapRegionClosure.java} | 4 +- ...nManager.java => G1HeapRegionManager.java} | 8 +- ...nSetBase.java => G1HeapRegionSetBase.java} | 8 +- ...pRegionType.java => G1HeapRegionType.java} | 26 ++-- ...Closure.java => G1PrintRegionClosure.java} | 4 +- .../sun/jvm/hotspot/tools/HeapSummary.java | 4 +- .../gtest/gc/g1/test_freeRegionList.cpp | 4 +- .../gtest/gc/g1/test_g1CardSetContainers.cpp | 4 +- test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp | 6 +- 66 files changed, 576 insertions(+), 578 deletions(-) rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/{HeapRegionClosure.java => G1HeapRegionClosure.java} (89%) rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/{HeapRegionManager.java => G1HeapRegionManager.java} (92%) rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/{HeapRegionSetBase.java => G1HeapRegionSetBase.java} (90%) rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/{HeapRegionType.java => G1HeapRegionType.java} (79%) rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/{PrintRegionClosure.java => G1PrintRegionClosure.java} (91%) diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index a62eb994486f5..3d4ce0d780da9 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -125,15 +125,13 @@ void G1Arguments::initialize_mark_stack_size() { MAX2(MarkStackSize, (size_t)ConcGCThreads * TASKQUEUE_SIZE)); FLAG_SET_ERGO(MarkStackSize, mark_stack_size); } - } - void G1Arguments::initialize_card_set_configuration() { assert(G1HeapRegion::LogOfHRGrainBytes != 0, "not initialized"); // Array of Cards card set container globals. const uint LOG_M = 20; - assert(log2i_exact(HeapRegionBounds::min_size()) == LOG_M, "inv"); + assert(log2i_exact(G1HeapRegionBounds::min_size()) == LOG_M, "inv"); assert(G1HeapRegion::LogOfHRGrainBytes >= LOG_M, "from the above"); uint region_size_log_mb = G1HeapRegion::LogOfHRGrainBytes - LOG_M; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 258f3f667c5cd..afd7b8948598e 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -129,7 +129,7 @@ size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0; // is done by clients of this interface.) void G1RegionMappingChangedListener::reset_from_card_cache(uint start_idx, size_t num_regions) { - HeapRegionRemSet::invalidate_from_card_cache(start_idx, num_regions); + G1HeapRegionRemSet::invalidate_from_card_cache(start_idx, num_regions); } void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) { @@ -162,7 +162,7 @@ G1HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, // Private methods. G1HeapRegion* G1CollectedHeap::new_region(size_t word_size, - HeapRegionType type, + G1HeapRegionType type, bool do_expand, uint node_index) { assert(!is_humongous(word_size) || word_size <= G1HeapRegion::GrainWords, @@ -710,7 +710,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size, ShouldNotReachHere(); } -class PostCompactionPrinterClosure: public HeapRegionClosure { +class PostCompactionPrinterClosure: public G1HeapRegionClosure { public: bool do_heap_region(G1HeapRegion* hr) { assert(!hr->is_young(), "not expecting to find young regions"); @@ -1070,7 +1070,7 @@ void G1CollectedHeap::shrink(size_t shrink_bytes) { _verifier->verify_region_sets_optional(); } -class OldRegionSetChecker : public HeapRegionSetChecker { +class OldRegionSetChecker : public G1HeapRegionSetChecker { public: void check_mt_safety() { // Master Old Set MT safety protocol: @@ -1098,7 +1098,7 @@ class OldRegionSetChecker : public HeapRegionSetChecker { const char* get_description() { return "Old Regions"; } }; -class HumongousRegionSetChecker : public HeapRegionSetChecker { +class HumongousRegionSetChecker : public G1HeapRegionSetChecker { public: void check_mt_safety() { // Humongous Set MT safety protocol: @@ -1352,9 +1352,9 @@ jint G1CollectedHeap::initialize() { guarantee(G1HeapRegion::CardsPerRegion < max_cards_per_region, "too many cards per region"); - HeapRegionRemSet::initialize(_reserved); + G1HeapRegionRemSet::initialize(_reserved); - FreeRegionList::set_unrealistically_long_length(max_regions() + 1); + G1FreeRegionList::set_unrealistically_long_length(max_regions() + 1); _bot = new G1BlockOffsetTable(reserved(), bot_storage); @@ -1536,7 +1536,7 @@ size_t G1CollectedHeap::used_unlocked() const { return _summary_bytes_used; } -class SumUsedClosure: public HeapRegionClosure { +class SumUsedClosure: public G1HeapRegionClosure { size_t _used; public: SumUsedClosure() : _used(0) {} @@ -1887,7 +1887,7 @@ bool G1CollectedHeap::is_in(const void* p) const { // Iterates an ObjectClosure over all objects within a G1HeapRegion. -class IterateObjectClosureRegionClosure: public HeapRegionClosure { +class IterateObjectClosureRegionClosure: public G1HeapRegionClosure { ObjectClosure* _cl; public: IterateObjectClosureRegionClosure(ObjectClosure* cl) : _cl(cl) {} @@ -1907,7 +1907,7 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) { class G1ParallelObjectIterator : public ParallelObjectIteratorImpl { private: G1CollectedHeap* _heap; - HeapRegionClaimer _claimer; + G1HeapRegionClaimer _claimer; public: G1ParallelObjectIterator(uint thread_num) : @@ -1923,7 +1923,7 @@ ParallelObjectIteratorImpl* G1CollectedHeap::parallel_object_iterator(uint threa return new G1ParallelObjectIterator(thread_num); } -void G1CollectedHeap::object_iterate_parallel(ObjectClosure* cl, uint worker_id, HeapRegionClaimer* claimer) { +void G1CollectedHeap::object_iterate_parallel(ObjectClosure* cl, uint worker_id, G1HeapRegionClaimer* claimer) { IterateObjectClosureRegionClosure blk(cl); heap_region_par_iterate_from_worker_offset(&blk, claimer, worker_id); } @@ -1932,43 +1932,43 @@ void G1CollectedHeap::keep_alive(oop obj) { G1BarrierSet::enqueue_preloaded(obj); } -void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const { +void G1CollectedHeap::heap_region_iterate(G1HeapRegionClosure* cl) const { _hrm.iterate(cl); } -void G1CollectedHeap::heap_region_iterate(HeapRegionIndexClosure* cl) const { +void G1CollectedHeap::heap_region_iterate(G1HeapRegionIndexClosure* cl) const { _hrm.iterate(cl); } -void G1CollectedHeap::heap_region_par_iterate_from_worker_offset(HeapRegionClosure* cl, - HeapRegionClaimer *hrclaimer, +void G1CollectedHeap::heap_region_par_iterate_from_worker_offset(G1HeapRegionClosure* cl, + G1HeapRegionClaimer *hrclaimer, uint worker_id) const { _hrm.par_iterate(cl, hrclaimer, hrclaimer->offset_for_worker(worker_id)); } -void G1CollectedHeap::heap_region_par_iterate_from_start(HeapRegionClosure* cl, - HeapRegionClaimer *hrclaimer) const { +void G1CollectedHeap::heap_region_par_iterate_from_start(G1HeapRegionClosure* cl, + G1HeapRegionClaimer *hrclaimer) const { _hrm.par_iterate(cl, hrclaimer, 0); } -void G1CollectedHeap::collection_set_iterate_all(HeapRegionClosure* cl) { +void G1CollectedHeap::collection_set_iterate_all(G1HeapRegionClosure* cl) { _collection_set.iterate(cl); } -void G1CollectedHeap::collection_set_par_iterate_all(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, +void G1CollectedHeap::collection_set_par_iterate_all(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, uint worker_id) { _collection_set.par_iterate(cl, hr_claimer, worker_id); } -void G1CollectedHeap::collection_set_iterate_increment_from(HeapRegionClosure *cl, - HeapRegionClaimer* hr_claimer, +void G1CollectedHeap::collection_set_iterate_increment_from(G1HeapRegionClosure *cl, + G1HeapRegionClaimer* hr_claimer, uint worker_id) { _collection_set.iterate_incremental_part_from(cl, hr_claimer, worker_id); } -void G1CollectedHeap::par_iterate_regions_array(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, +void G1CollectedHeap::par_iterate_regions_array(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, const uint regions[], size_t length, uint worker_id) const { @@ -2046,10 +2046,10 @@ bool G1CollectedHeap::supports_concurrent_gc_breakpoints() const { return true; } -class PrintRegionClosure: public HeapRegionClosure { +class G1PrintRegionClosure: public G1HeapRegionClosure { outputStream* _st; public: - PrintRegionClosure(outputStream* st) : _st(st) {} + G1PrintRegionClosure(outputStream* st) : _st(st) {} bool do_heap_region(G1HeapRegion* r) { r->print_on(_st); return false; @@ -2121,7 +2121,7 @@ void G1CollectedHeap::print_regions_on(outputStream* st) const { "CS=collection set, F=free, " "TAMS=top-at-mark-start, " "PB=parsable bottom"); - PrintRegionClosure blk(st); + G1PrintRegionClosure blk(st); heap_region_iterate(&blk); } @@ -2281,14 +2281,14 @@ void G1CollectedHeap::start_concurrent_cycle(bool concurrent_operation_is_full_m bool G1CollectedHeap::is_potential_eager_reclaim_candidate(G1HeapRegion* r) const { // We don't nominate objects with many remembered set entries, on // the assumption that such objects are likely still live. - HeapRegionRemSet* rem_set = r->rem_set(); + G1HeapRegionRemSet* rem_set = r->rem_set(); return rem_set->occupancy_less_or_equal_than(G1EagerReclaimRemSetThreshold); } #ifndef PRODUCT void G1CollectedHeap::verify_region_attr_remset_is_tracked() { - class VerifyRegionAttrRemSet : public HeapRegionClosure { + class VerifyRegionAttrRemSet : public G1HeapRegionClosure { public: virtual bool do_heap_region(G1HeapRegion* r) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -2538,9 +2538,9 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec } class G1BulkUnregisterNMethodTask : public WorkerTask { - HeapRegionClaimer _hrclaimer; + G1HeapRegionClaimer _hrclaimer; - class UnregisterNMethodsHeapRegionClosure : public HeapRegionClosure { + class UnregisterNMethodsHeapRegionClosure : public G1HeapRegionClosure { public: bool do_heap_region(G1HeapRegion* hr) { @@ -2614,7 +2614,7 @@ void G1CollectedHeap::clear_bitmap_for_region(G1HeapRegion* hr) { concurrent_mark()->clear_bitmap_for_region(hr); } -void G1CollectedHeap::free_region(G1HeapRegion* hr, FreeRegionList* free_list) { +void G1CollectedHeap::free_region(G1HeapRegion* hr, G1FreeRegionList* free_list) { assert(!hr->is_free(), "the region should not be free"); assert(!hr->is_empty(), "the region should not be empty"); assert(_hrm.is_available(hr->hrm_index()), "region should be committed"); @@ -2636,7 +2636,7 @@ void G1CollectedHeap::retain_region(G1HeapRegion* hr) { } void G1CollectedHeap::free_humongous_region(G1HeapRegion* hr, - FreeRegionList* free_list) { + G1FreeRegionList* free_list) { assert(hr->is_humongous(), "this is only for humongous regions"); hr->clear_humongous(); free_region(hr, free_list); @@ -2652,7 +2652,7 @@ void G1CollectedHeap::remove_from_old_gen_sets(const uint old_regions_removed, } -void G1CollectedHeap::prepend_to_freelist(FreeRegionList* list) { +void G1CollectedHeap::prepend_to_freelist(G1FreeRegionList* list) { assert(list != nullptr, "list can't be null"); if (!list->is_empty()) { MutexLocker x(FreeList_lock, Mutex::_no_safepoint_check_flag); @@ -2678,7 +2678,7 @@ void G1CollectedHeap::rebuild_free_region_list() { phase_times()->record_total_rebuild_freelist_time_ms((Ticks::now() - start).seconds() * 1000.0); } -class G1AbandonCollectionSetClosure : public HeapRegionClosure { +class G1AbandonCollectionSetClosure : public G1HeapRegionClosure { public: virtual bool do_heap_region(G1HeapRegion* r) { assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index()); @@ -2707,7 +2707,7 @@ void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) { #ifdef ASSERT -class NoYoungRegionsClosure: public HeapRegionClosure { +class NoYoungRegionsClosure: public G1HeapRegionClosure { private: bool _success; public: @@ -2768,22 +2768,22 @@ void G1CollectedHeap::set_used(size_t bytes) { _summary_bytes_used = bytes; } -class RebuildRegionSetsClosure : public HeapRegionClosure { +class RebuildRegionSetsClosure : public G1HeapRegionClosure { private: bool _free_list_only; - HeapRegionSet* _old_set; - HeapRegionSet* _humongous_set; + G1HeapRegionSet* _old_set; + G1HeapRegionSet* _humongous_set; - HeapRegionManager* _hrm; + G1HeapRegionManager* _hrm; size_t _total_used; public: RebuildRegionSetsClosure(bool free_list_only, - HeapRegionSet* old_set, - HeapRegionSet* humongous_set, - HeapRegionManager* hrm) : + G1HeapRegionSet* old_set, + G1HeapRegionSet* humongous_set, + G1HeapRegionManager* hrm) : _free_list_only(free_list_only), _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm), _total_used(0) { assert(_hrm->num_free_regions() == 0, "pre-condition"); @@ -2849,7 +2849,7 @@ G1HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, bool should_allocate = policy()->should_allocate_mutator_region(); if (should_allocate) { G1HeapRegion* new_alloc_region = new_region(word_size, - HeapRegionType::Eden, + G1HeapRegionType::Eden, false /* do_expand */, node_index); if (new_alloc_region != nullptr) { @@ -2895,11 +2895,11 @@ G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegio return nullptr; } - HeapRegionType type; + G1HeapRegionType type; if (dest.is_young()) { - type = HeapRegionType::Survivor; + type = G1HeapRegionType::Survivor; } else { - type = HeapRegionType::Old; + type = G1HeapRegionType::Old; } G1HeapRegion* new_alloc_region = new_region(word_size, diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 1cf89879fd735..ec3cf8eafe3a0 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -162,7 +162,7 @@ class G1CollectedHeap : public CollectedHeap { // Other related classes. friend class G1HeapPrinterMark; - friend class HeapRegionClaimer; + friend class G1HeapRegionClaimer; // Testing classes. friend class G1CheckRegionAttrTableClosure; @@ -180,8 +180,8 @@ class G1CollectedHeap : public CollectedHeap { static size_t _humongous_object_threshold_in_words; // These sets keep track of old and humongous regions respectively. - HeapRegionSet _old_set; - HeapRegionSet _humongous_set; + G1HeapRegionSet _old_set; + G1HeapRegionSet _humongous_set; // Young gen memory statistics before GC. G1MonotonicArenaMemoryStats _young_gen_card_set_stats; @@ -212,7 +212,7 @@ class G1CollectedHeap : public CollectedHeap { G1NUMA* _numa; // The sequence of all heap regions in the heap. - HeapRegionManager _hrm; + G1HeapRegionManager _hrm; // Manages all allocations with regions except humongous object allocations. G1Allocator* _allocator; @@ -386,9 +386,9 @@ class G1CollectedHeap : public CollectedHeap { // an allocation of the given word_size. If do_expand is true, // attempt to expand the heap if necessary to satisfy the allocation // request. 'type' takes the type of region to be allocated. (Use constants - // Old, Eden, Humongous, Survivor defined in HeapRegionType.) + // Old, Eden, Humongous, Survivor defined in G1HeapRegionType.) G1HeapRegion* new_region(size_t word_size, - HeapRegionType type, + G1HeapRegionType type, bool do_expand, uint node_index = G1NUMA::AnyNodeIndex); @@ -679,7 +679,7 @@ class G1CollectedHeap : public CollectedHeap { // in another way). // Callers must ensure they are the only one calling free on the given region // at the same time. - void free_region(G1HeapRegion* hr, FreeRegionList* free_list); + void free_region(G1HeapRegion* hr, G1FreeRegionList* free_list); // Add the given region to the retained regions collection set candidates. void retain_region(G1HeapRegion* hr); @@ -697,7 +697,7 @@ class G1CollectedHeap : public CollectedHeap { // The method assumes that only a single thread is ever calling // this for a particular region at once. void free_humongous_region(G1HeapRegion* hr, - FreeRegionList* free_list); + G1FreeRegionList* free_list); // Execute func(G1HeapRegion* r, bool is_last) on every region covered by the // given range. @@ -1022,7 +1022,7 @@ class G1CollectedHeap : public CollectedHeap { void remove_from_old_gen_sets(const uint old_regions_removed, const uint humongous_regions_removed); - void prepend_to_freelist(FreeRegionList* list); + void prepend_to_freelist(G1FreeRegionList* list); void decrement_summary_bytes(size_t bytes); bool is_in(const void* p) const override; @@ -1060,7 +1060,7 @@ class G1CollectedHeap : public CollectedHeap { // Iteration functions. - void object_iterate_parallel(ObjectClosure* cl, uint worker_id, HeapRegionClaimer* claimer); + void object_iterate_parallel(ObjectClosure* cl, uint worker_id, G1HeapRegionClaimer* claimer); // Iterate over all objects, calling "cl.do_object" on each. void object_iterate(ObjectClosure* cl) override; @@ -1072,8 +1072,8 @@ class G1CollectedHeap : public CollectedHeap { // Iterate over heap regions, in address order, terminating the // iteration early if the "do_heap_region" method returns "true". - void heap_region_iterate(HeapRegionClosure* blk) const; - void heap_region_iterate(HeapRegionIndexClosure* blk) const; + void heap_region_iterate(G1HeapRegionClosure* blk) const; + void heap_region_iterate(G1HeapRegionIndexClosure* blk) const; // Return the region with the given index. It assumes the index is valid. inline G1HeapRegion* region_at(uint index) const; @@ -1091,41 +1091,41 @@ class G1CollectedHeap : public CollectedHeap { inline HeapWord* bottom_addr_for_region(uint index) const; // Two functions to iterate over the heap regions in parallel. Threads - // compete using the HeapRegionClaimer to claim the regions before + // compete using the G1HeapRegionClaimer to claim the regions before // applying the closure on them. - // The _from_worker_offset version uses the HeapRegionClaimer and + // The _from_worker_offset version uses the G1HeapRegionClaimer and // the worker id to calculate a start offset to prevent all workers to // start from the point. - void heap_region_par_iterate_from_worker_offset(HeapRegionClosure* cl, - HeapRegionClaimer* hrclaimer, + void heap_region_par_iterate_from_worker_offset(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hrclaimer, uint worker_id) const; - void heap_region_par_iterate_from_start(HeapRegionClosure* cl, - HeapRegionClaimer* hrclaimer) const; + void heap_region_par_iterate_from_start(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hrclaimer) const; // Iterate over all regions in the collection set in parallel. - void collection_set_par_iterate_all(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, + void collection_set_par_iterate_all(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, uint worker_id); // Iterate over all regions currently in the current collection set. - void collection_set_iterate_all(HeapRegionClosure* blk); + void collection_set_iterate_all(G1HeapRegionClosure* blk); // Iterate over the regions in the current increment of the collection set. // Starts the iteration so that the start regions of a given worker id over the // set active_workers are evenly spread across the set of collection set regions // to be iterated. - // The variant with the HeapRegionClaimer guarantees that the closure will be + // The variant with the G1HeapRegionClaimer guarantees that the closure will be // applied to a particular region exactly once. - void collection_set_iterate_increment_from(HeapRegionClosure *blk, uint worker_id) { + void collection_set_iterate_increment_from(G1HeapRegionClosure *blk, uint worker_id) { collection_set_iterate_increment_from(blk, nullptr, worker_id); } - void collection_set_iterate_increment_from(HeapRegionClosure *blk, HeapRegionClaimer* hr_claimer, uint worker_id); + void collection_set_iterate_increment_from(G1HeapRegionClosure *blk, G1HeapRegionClaimer* hr_claimer, uint worker_id); // Iterate over the array of region indexes, uint regions[length], applying - // the given HeapRegionClosure on each region. The worker_id will determine where + // the given G1HeapRegionClosure on each region. The worker_id will determine where // to start the iteration to allow for more efficient parallel iteration. - void par_iterate_regions_array(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, + void par_iterate_regions_array(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, const uint regions[], size_t length, uint worker_id) const; diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 5da8f26b3310b..fe4dfafee97bf 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,7 @@ void G1CollectionSet::clear() { _collection_set_cur_length = 0; } -void G1CollectionSet::iterate(HeapRegionClosure* cl) const { +void G1CollectionSet::iterate(G1HeapRegionClosure* cl) const { size_t len = _collection_set_cur_length; OrderAccess::loadload(); @@ -143,13 +143,13 @@ void G1CollectionSet::iterate(HeapRegionClosure* cl) const { } } -void G1CollectionSet::par_iterate(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, +void G1CollectionSet::par_iterate(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, uint worker_id) const { iterate_part_from(cl, hr_claimer, 0, cur_length(), worker_id); } -void G1CollectionSet::iterate_optional(HeapRegionClosure* cl) const { +void G1CollectionSet::iterate_optional(G1HeapRegionClosure* cl) const { assert_at_safepoint(); for (G1HeapRegion* r : _optional_old_regions) { @@ -158,14 +158,14 @@ void G1CollectionSet::iterate_optional(HeapRegionClosure* cl) const { } } -void G1CollectionSet::iterate_incremental_part_from(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, +void G1CollectionSet::iterate_incremental_part_from(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, uint worker_id) const { iterate_part_from(cl, hr_claimer, _inc_part_start, increment_length(), worker_id); } -void G1CollectionSet::iterate_part_from(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, +void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, size_t offset, size_t length, uint worker_id) const { @@ -207,11 +207,11 @@ void G1CollectionSet::add_eden_region(G1HeapRegion* hr) { } #ifndef PRODUCT -class G1VerifyYoungAgesClosure : public HeapRegionClosure { +class G1VerifyYoungAgesClosure : public G1HeapRegionClosure { public: bool _valid; - G1VerifyYoungAgesClosure() : HeapRegionClosure(), _valid(true) { } + G1VerifyYoungAgesClosure() : G1HeapRegionClosure(), _valid(true) { } virtual bool do_heap_region(G1HeapRegion* r) { guarantee(r->is_young(), "Region must be young but is %s", r->get_type_str()); @@ -246,10 +246,10 @@ bool G1CollectionSet::verify_young_ages() { return cl.valid(); } -class G1PrintCollectionSetDetailClosure : public HeapRegionClosure { +class G1PrintCollectionSetDetailClosure : public G1HeapRegionClosure { outputStream* _st; public: - G1PrintCollectionSetDetailClosure(outputStream* st) : HeapRegionClosure(), _st(st) { } + G1PrintCollectionSetDetailClosure(outputStream* st) : G1HeapRegionClosure(), _st(st) { } virtual bool do_heap_region(G1HeapRegion* r) { assert(r->in_collection_set(), "Region %u should be in collection set", r->hrm_index()); @@ -471,12 +471,12 @@ void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* p } #ifdef ASSERT -class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure { +class G1VerifyYoungCSetIndicesClosure : public G1HeapRegionClosure { private: size_t _young_length; uint* _heap_region_indices; public: - G1VerifyYoungCSetIndicesClosure(size_t young_length) : HeapRegionClosure(), _young_length(young_length) { + G1VerifyYoungCSetIndicesClosure(size_t young_length) : G1HeapRegionClosure(), _young_length(young_length) { _heap_region_indices = NEW_C_HEAP_ARRAY(uint, young_length + 1, mtGC); for (size_t i = 0; i < young_length + 1; i++) { _heap_region_indices[i] = UINT_MAX; diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index e78a426e40302..e569d3ee966c3 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,8 +36,8 @@ class G1ParScanThreadStateSet; class G1Policy; class G1SurvivorRegions; class G1HeapRegion; -class HeapRegionClaimer; -class HeapRegionClosure; +class G1HeapRegionClaimer; +class G1HeapRegionClosure; // The collection set. // @@ -197,10 +197,10 @@ class G1CollectionSet { void finalize_old_part(double time_remaining_ms); // Iterate the part of the collection set given by the offset and length applying the given - // HeapRegionClosure. The worker_id will determine where in the part to start the iteration + // G1HeapRegionClosure. The worker_id will determine where in the part to start the iteration // to allow for more efficient parallel iteration. - void iterate_part_from(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, + void iterate_part_from(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, size_t offset, size_t length, uint worker_id) const; @@ -243,9 +243,9 @@ class G1CollectionSet { // Stop adding regions to the current collection set increment. void stop_incremental_building() { _inc_build_state = Inactive; } - // Iterate over the current collection set increment applying the given HeapRegionClosure + // Iterate over the current collection set increment applying the given G1HeapRegionClosure // from a starting position determined by the given worker id. - void iterate_incremental_part_from(HeapRegionClosure* cl, HeapRegionClaimer* hr_claimer, uint worker_id) const; + void iterate_incremental_part_from(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, uint worker_id) const; // Returns the length of the current increment in number of regions. size_t increment_length() const { return _collection_set_cur_length - _inc_part_start; } @@ -253,13 +253,13 @@ class G1CollectionSet { size_t cur_length() const { return _collection_set_cur_length; } // Iterate over the entire collection set (all increments calculated so far), applying - // the given HeapRegionClosure on all of them. - void iterate(HeapRegionClosure* cl) const; - void par_iterate(HeapRegionClosure* cl, - HeapRegionClaimer* hr_claimer, + // the given G1HeapRegionClosure on all of them. + void iterate(G1HeapRegionClosure* cl) const; + void par_iterate(G1HeapRegionClosure* cl, + G1HeapRegionClaimer* hr_claimer, uint worker_id) const; - void iterate_optional(HeapRegionClosure* cl) const; + void iterate_optional(G1HeapRegionClosure* cl) const; // Finalize the initial collection set consisting of all young regions potentially a // few old gen regions. diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index 7d24f02246183..e629aa8f36324 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -36,7 +36,7 @@ class G1CollectionCandidateList; class G1CollectionSetCandidates; class G1HeapRegion; -class HeapRegionClosure; +class G1HeapRegionClosure; using G1CollectionCandidateRegionListIterator = GrowableArrayIterator; @@ -110,7 +110,7 @@ class G1CollectionCandidateList : public CHeapObj { // Restore sorting order by decreasing gc efficiency, using the existing efficiency // values. void sort_by_efficiency(); - // Removes any HeapRegions stored in this list also in the other list. The other + // Removes any heap regions stored in this list also in the other list. The other // list may only contain regions in this list, sorted by gc efficiency. It need // not be a prefix of this list. Returns the number of regions removed. // E.g. if this list is "A B G H", the other list may be "A G H", but not "F" (not in diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index a45e7de67bf37..630fb8a7a1122 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -116,7 +116,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // Per-region closure. In addition to determining whether a region should be // added to the candidates, and calculating those regions' gc efficiencies, also // gather additional statistics. - class G1BuildCandidateRegionsClosure : public HeapRegionClosure { + class G1BuildCandidateRegionsClosure : public G1HeapRegionClosure { G1BuildCandidateArray* _array; uint _cur_chunk_idx; @@ -177,7 +177,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { }; G1CollectedHeap* _g1h; - HeapRegionClaimer _hrclaimer; + G1HeapRegionClaimer _hrclaimer; uint volatile _num_regions_added; diff --git a/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp b/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp index 80cbcf1c7dc20..6919cc7d0c911 100644 --- a/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp +++ b/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "runtime/safepoint.hpp" #include "utilities/debug.hpp" -HeapRegionRange::HeapRegionRange(uint start, uint end) : +G1HeapRegionRange::G1HeapRegionRange(uint start, uint end) : _start(start), _end(end) { assert(start <= end, "Invariant"); @@ -97,21 +97,21 @@ void G1CommittedRegionMap::uncommit(uint start, uint end) { inactive_clear_range(start, end); } -HeapRegionRange G1CommittedRegionMap::next_active_range(uint offset) const { +G1HeapRegionRange G1CommittedRegionMap::next_active_range(uint offset) const { // Find first active index from offset. uint start = (uint) _active.find_first_set_bit(offset); if (start == max_length()) { // Early out when no active regions are found. - return HeapRegionRange(max_length(), max_length()); + return G1HeapRegionRange(max_length(), max_length()); } uint end = (uint) _active.find_first_clear_bit(start); verify_active_range(start, end); - return HeapRegionRange(start, end); + return G1HeapRegionRange(start, end); } -HeapRegionRange G1CommittedRegionMap::next_committable_range(uint offset) const { +G1HeapRegionRange G1CommittedRegionMap::next_committable_range(uint offset) const { // We should only call this function when there are no inactive regions. verify_no_inactive_regons(); @@ -119,28 +119,28 @@ HeapRegionRange G1CommittedRegionMap::next_committable_range(uint offset) const uint start = (uint) _active.find_first_clear_bit(offset); if (start == max_length()) { // Early out when no free regions are found. - return HeapRegionRange(max_length(), max_length()); + return G1HeapRegionRange(max_length(), max_length()); } uint end = (uint) _active.find_first_set_bit(start); verify_free_range(start, end); - return HeapRegionRange(start, end); + return G1HeapRegionRange(start, end); } -HeapRegionRange G1CommittedRegionMap::next_inactive_range(uint offset) const { +G1HeapRegionRange G1CommittedRegionMap::next_inactive_range(uint offset) const { // Find first inactive region from offset. uint start = (uint) _inactive.find_first_set_bit(offset); if (start == max_length()) { // Early when no inactive regions are found. - return HeapRegionRange(max_length(), max_length()); + return G1HeapRegionRange(max_length(), max_length()); } uint end = (uint) _inactive.find_first_clear_bit(start); verify_inactive_range(start, end); - return HeapRegionRange(start, end); + return G1HeapRegionRange(start, end); } void G1CommittedRegionMap::active_set_range(uint start, uint end) { diff --git a/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp b/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp index 38db9bf8f34da..595a6f7f9c9ab 100644 --- a/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp +++ b/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,13 +30,13 @@ #include "utilities/macros.hpp" // Helper class to define a range [start, end) of regions. -class HeapRegionRange : public StackObj { +class G1HeapRegionRange : public StackObj { // Inclusive start of the range. uint _start; // Exclusive end of the range. uint _end; public: - HeapRegionRange(uint start, uint end); + G1HeapRegionRange(uint start, uint end); uint start() const { return _start; } uint end() const { return _end; } @@ -101,13 +101,13 @@ class G1CommittedRegionMap : public CHeapObj { void uncommit(uint start, uint end); // Finds the next range of active regions starting at offset. - HeapRegionRange next_active_range(uint offset) const; + G1HeapRegionRange next_active_range(uint offset) const; // Finds the next range of inactive regions starting at offset. - HeapRegionRange next_inactive_range(uint offset) const; + G1HeapRegionRange next_inactive_range(uint offset) const; // Finds the next range of committable regions starting at offset. // This function must only be called when no inactive regions are // present and can be used to activate more regions. - HeapRegionRange next_committable_range(uint offset) const; + G1HeapRegionRange next_committable_range(uint offset) const; protected: virtual void guarantee_mt_safety_active() const; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 827c538a2e59c..3d56973299ee8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -675,7 +675,7 @@ class G1ClearBitMapTask : public WorkerTask { private: // Heap region closure used for clearing the _mark_bitmap. - class G1ClearBitmapHRClosure : public HeapRegionClosure { + class G1ClearBitmapHRClosure : public G1HeapRegionClosure { private: G1ConcurrentMark* _cm; G1CMBitMap* _bitmap; @@ -715,7 +715,7 @@ class G1ClearBitMapTask : public WorkerTask { public: G1ClearBitmapHRClosure(G1ConcurrentMark* cm, bool suspendible) : - HeapRegionClosure(), + G1HeapRegionClosure(), _cm(cm), _bitmap(cm->mark_bitmap()), _suspendible(suspendible) @@ -759,7 +759,7 @@ class G1ClearBitMapTask : public WorkerTask { }; G1ClearBitmapHRClosure _cl; - HeapRegionClaimer _hr_claimer; + G1HeapRegionClaimer _hr_claimer; bool _suspendible; // If the task is suspendible, workers must join the STS. public: @@ -843,7 +843,7 @@ class G1PreConcurrentStartTask::ResetMarkingStateTask : public G1AbstractSubTask }; class G1PreConcurrentStartTask::NoteStartOfMarkTask : public G1AbstractSubTask { - HeapRegionClaimer _claimer; + G1HeapRegionClaimer _claimer; public: NoteStartOfMarkTask() : G1AbstractSubTask(G1GCPhaseTimes::NoteStartOfMark), _claimer(0) { } @@ -863,11 +863,11 @@ void G1PreConcurrentStartTask::ResetMarkingStateTask::do_work(uint worker_id) { _cm->reset(); } -class NoteStartOfMarkHRClosure : public HeapRegionClosure { +class NoteStartOfMarkHRClosure : public G1HeapRegionClosure { G1ConcurrentMark* _cm; public: - NoteStartOfMarkHRClosure() : HeapRegionClosure(), _cm(G1CollectedHeap::heap()->concurrent_mark()) { } + NoteStartOfMarkHRClosure() : G1HeapRegionClosure(), _cm(G1CollectedHeap::heap()->concurrent_mark()) { } bool do_heap_region(G1HeapRegion* r) override { if (r->is_old_or_humongous() && !r->is_collection_set_candidate() && !r->in_collection_set()) { @@ -1204,14 +1204,14 @@ void G1ConcurrentMark::verify_during_pause(G1HeapVerifier::G1VerifyType type, class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; - HeapRegionClaimer _hrclaimer; + G1HeapRegionClaimer _hrclaimer; uint volatile _total_selected_for_rebuild; // Reclaimed empty regions - FreeRegionList _cleanup_list; + G1FreeRegionList _cleanup_list; - struct G1OnRegionClosure : public HeapRegionClosure { + struct G1OnRegionClosure : public G1HeapRegionClosure { G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; // The number of regions actually selected for rebuild. @@ -1220,11 +1220,11 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { size_t _freed_bytes; uint _num_old_regions_removed; uint _num_humongous_regions_removed; - FreeRegionList* _local_cleanup_list; + G1FreeRegionList* _local_cleanup_list; G1OnRegionClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm, - FreeRegionList* local_cleanup_list) : + G1FreeRegionList* local_cleanup_list) : _g1h(g1h), _cm(cm), _num_selected_for_rebuild(0), @@ -1325,7 +1325,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { } void work(uint worker_id) override { - FreeRegionList local_cleanup_list("Local Cleanup List"); + G1FreeRegionList local_cleanup_list("Local Cleanup List"); G1OnRegionClosure on_region_cl(_g1h, _cm, &local_cleanup_list); _g1h->heap_region_par_iterate_from_worker_offset(&on_region_cl, &_hrclaimer, worker_id); @@ -1352,7 +1352,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { } }; -class G1UpdateRegionsAfterRebuild : public HeapRegionClosure { +class G1UpdateRegionsAfterRebuild : public G1HeapRegionClosure { G1CollectedHeap* _g1h; public: @@ -3078,7 +3078,7 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); _total_remset_bytes += g1h->card_set_freelist_pool()->mem_size(); // add static memory usages to remembered set sizes - _total_remset_bytes += HeapRegionRemSet::static_mem_size(); + _total_remset_bytes += G1HeapRegionRemSet::static_mem_size(); // Print the footer of the output. log_trace(gc, liveness)(G1PPRL_LINE_PREFIX); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index f2206664b257a..918384372bbb8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -949,7 +949,7 @@ class G1CMTask : public TerminatorTerminator { // Class that's used to to print out per-region liveness // information. It's currently used at the end of marking and also // after we sort the old regions at the end of the cleanup operation. -class G1PrintRegionLivenessInfoClosure : public HeapRegionClosure { +class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure { // Accumulators for these values. size_t _total_used_bytes; size_t _total_capacity_bytes; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp index cacb28f84b1e2..1b6b1eed7b13b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp @@ -63,11 +63,11 @@ // a pause. class G1RebuildRSAndScrubTask : public WorkerTask { G1ConcurrentMark* _cm; - HeapRegionClaimer _hr_claimer; + G1HeapRegionClaimer _hr_claimer; const bool _should_rebuild_remset; - class G1RebuildRSAndScrubRegionClosure : public HeapRegionClosure { + class G1RebuildRSAndScrubRegionClosure : public G1HeapRegionClosure { G1ConcurrentMark* _cm; const G1CMBitMap* _bitmap; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 2fabeec980547..b51d0cdf84aee 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,7 +253,7 @@ uint64_t G1ConcurrentRefine::adjust_threads_wait_ms() const { } } -class G1ConcurrentRefine::RemSetSamplingClosure : public HeapRegionClosure { +class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { G1CollectionSet* _cset; size_t _sampled_card_rs_length; size_t _sampled_code_root_rs_length; @@ -263,7 +263,7 @@ class G1ConcurrentRefine::RemSetSamplingClosure : public HeapRegionClosure { _cset(cset), _sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {} bool do_heap_region(G1HeapRegion* r) override { - HeapRegionRemSet* rem_set = r->rem_set(); + G1HeapRegionRemSet* rem_set = r->rem_set(); _sampled_card_rs_length += rem_set->occupied(); _sampled_code_root_rs_length += rem_set->code_roots_list_length(); return false; diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index 845868c3e2415..afc1602639a30 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -64,8 +64,8 @@ bool G1EvacFailureRegions::contains(uint region_idx) const { return _regions_evac_failed.par_at(region_idx, memory_order_relaxed); } -void G1EvacFailureRegions::par_iterate(HeapRegionClosure* closure, - HeapRegionClaimer* hrclaimer, +void G1EvacFailureRegions::par_iterate(G1HeapRegionClosure* closure, + G1HeapRegionClaimer* hrclaimer, uint worker_id) const { G1CollectedHeap::heap()->par_iterate_regions_array(closure, hrclaimer, diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp index b8f9ea8003884..9d29957b782c5 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp @@ -28,8 +28,8 @@ #include "utilities/bitMap.hpp" class G1AbstractSubTask; -class HeapRegionClosure; -class HeapRegionClaimer; +class G1HeapRegionClaimer; +class G1HeapRegionClosure; // This class records for every region on the heap whether it had experienced an // evacuation failure. @@ -70,8 +70,8 @@ class G1EvacFailureRegions { void post_collection(); bool contains(uint region_idx) const; - void par_iterate(HeapRegionClosure* closure, - HeapRegionClaimer* hrclaimer, + void par_iterate(G1HeapRegionClosure* closure, + G1HeapRegionClaimer* hrclaimer, uint worker_id) const; // Return a G1AbstractSubTask which does necessary preparation for evacuation failed regions diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 0fba8c1017f02..219480227d3fd 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -164,7 +164,7 @@ G1FullCollector::~G1FullCollector() { FREE_C_HEAP_ARRAY(G1RegionMarkStats, _live_stats); } -class PrepareRegionsClosure : public HeapRegionClosure { +class PrepareRegionsClosure : public G1HeapRegionClosure { G1FullCollector* _collector; public: diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 75da25199eb7f..0d4adbe632e39 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +51,7 @@ class G1AdjustLiveClosure : public StackObj { } }; -class G1AdjustRegionClosure : public HeapRegionClosure { +class G1AdjustRegionClosure : public G1HeapRegionClosure { G1FullCollector* _collector; G1CMBitMap* _bitmap; uint _worker_id; diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp index 26ac183d10d75..af232188e4660 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ class G1CollectedHeap; class G1FullGCAdjustTask : public G1FullGCTask { G1RootProcessor _root_processor; WeakProcessor::Task _weak_proc_task; - HeapRegionClaimer _hrclaimer; + G1HeapRegionClaimer _hrclaimer; G1AdjustClosure _adjust; public: diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp index 341542f6d6f70..5c3929f1eed7d 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ class G1FullCollector; class G1FullGCCompactTask : public G1FullGCTask { G1FullCollector* _collector; - HeapRegionClaimer _claimer; + G1HeapRegionClaimer _claimer; G1CollectedHeap* _g1h; void compact_region(G1HeapRegion* hr); diff --git a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp index 2fc7d74f331f1..9eaa172b5e51b 100644 --- a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +27,7 @@ #include "gc/g1/g1BiasedArray.hpp" -// This table is used to store attribute values of all HeapRegions that need +// This table is used to store attribute values of all heap regions that need // fast access during the full collection. In particular some parts of the // region type information is encoded in these per-region bytes. Value encoding // has been specifically chosen to make required accesses fast. In particular, diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp index a4dbbf2edbaea..9d2887c01a6c9 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ class G1HeapRegion; // Determines the regions in the heap that should be part of the compaction and // distributes them among the compaction queues in round-robin fashion. -class G1DetermineCompactionQueueClosure : public HeapRegionClosure { +class G1DetermineCompactionQueueClosure : public G1HeapRegionClosure { G1CollectedHeap* _g1h; G1FullCollector* _collector; uint _cur_worker; @@ -62,7 +62,7 @@ class G1DetermineCompactionQueueClosure : public HeapRegionClosure { class G1FullGCPrepareTask : public G1FullGCTask { volatile bool _has_free_compaction_targets; - HeapRegionClaimer _hrclaimer; + G1HeapRegionClaimer _hrclaimer; void set_has_free_compaction_targets(); @@ -74,7 +74,7 @@ class G1FullGCPrepareTask : public G1FullGCTask { bool has_free_compaction_targets(); private: - class G1CalculatePointersClosure : public HeapRegionClosure { + class G1CalculatePointersClosure : public G1HeapRegionClosure { G1CollectedHeap* _g1h; G1FullCollector* _collector; G1CMBitMap* _bitmap; diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp index 98d7af6e2f388..5f046e35001a5 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,9 @@ class G1FullGCResetMetadataTask : public G1FullGCTask { G1FullCollector* _collector; - HeapRegionClaimer _claimer; + G1HeapRegionClaimer _claimer; - class G1ResetMetadataClosure : public HeapRegionClosure { + class G1ResetMetadataClosure : public G1HeapRegionClosure { G1CollectedHeap* _g1h; G1FullCollector* _collector; diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index d611cf7f947ff..9851b1df9c9b5 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -55,20 +55,20 @@ size_t G1HeapRegion::GrainWords = 0; size_t G1HeapRegion::CardsPerRegion = 0; size_t G1HeapRegion::max_region_size() { - return HeapRegionBounds::max_size(); + return G1HeapRegionBounds::max_size(); } size_t G1HeapRegion::min_region_size_in_words() { - return HeapRegionBounds::min_size() >> LogHeapWordSize; + return G1HeapRegionBounds::min_size() >> LogHeapWordSize; } void G1HeapRegion::setup_heap_region_size(size_t max_heap_size) { size_t region_size = G1HeapRegionSize; // G1HeapRegionSize = 0 means decide ergonomically. if (region_size == 0) { - region_size = clamp(max_heap_size / HeapRegionBounds::target_number(), - HeapRegionBounds::min_size(), - HeapRegionBounds::max_ergonomics_size()); + region_size = clamp(max_heap_size / G1HeapRegionBounds::target_number(), + G1HeapRegionBounds::min_size(), + G1HeapRegionBounds::max_ergonomics_size()); } // Make sure region size is a power of 2. Rounding up since this @@ -76,7 +76,7 @@ void G1HeapRegion::setup_heap_region_size(size_t max_heap_size) { region_size = round_up_power_of_2(region_size); // Now make sure that we don't go over or under our limits. - region_size = clamp(region_size, HeapRegionBounds::min_size(), HeapRegionBounds::max_size()); + region_size = clamp(region_size, G1HeapRegionBounds::min_size(), G1HeapRegionBounds::max_size()); // Now, set up the globals. guarantee(LogOfHRGrainBytes == 0, "we should only set it once"); @@ -247,7 +247,7 @@ G1HeapRegion::G1HeapRegion(uint hrm_index, assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()), "invalid space boundaries"); - _rem_set = new HeapRegionRemSet(this, config); + _rem_set = new G1HeapRegionRemSet(this, config); initialize(); } @@ -264,11 +264,11 @@ void G1HeapRegion::initialize(bool clear_space, bool mangle_space) { } void G1HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) { - HeapRegionTracer::send_region_type_change(_hrm_index, - get_trace_type(), - to, - (uintptr_t)bottom(), - used()); + G1HeapRegionTracer::send_region_type_change(_hrm_index, + get_trace_type(), + to, + (uintptr_t)bottom(), + used()); } void G1HeapRegion::note_evacuation_failure() { @@ -377,7 +377,7 @@ bool G1HeapRegion::verify_code_roots(VerifyOption vo) const { return false; } - HeapRegionRemSet* hrrs = rem_set(); + G1HeapRegionRemSet* hrrs = rem_set(); size_t code_roots_length = hrrs->code_roots_list_length(); // if this region is empty then there should be no entries diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index 67d6556203cad..ed953094a679f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -40,9 +40,9 @@ class G1CardSetConfiguration; class G1CollectedHeap; class G1CMBitMap; class G1Predictions; -class HeapRegionRemSet; class G1HeapRegion; -class HeapRegionSetBase; +class G1HeapRegionRemSet; +class G1HeapRegionSetBase; class nmethod; #define HR_FORMAT "%u:(%s)[" PTR_FORMAT "," PTR_FORMAT "," PTR_FORMAT "]" @@ -195,12 +195,12 @@ class G1HeapRegion : public CHeapObj { private: // The remembered set for this region. - HeapRegionRemSet* _rem_set; + G1HeapRegionRemSet* _rem_set; // Cached index of this region in the heap region sequence. const uint _hrm_index; - HeapRegionType _type; + G1HeapRegionType _type; // For a humongous region, region in which it starts. G1HeapRegion* _humongous_start_region; @@ -211,11 +211,11 @@ class G1HeapRegion : public CHeapObj { // is considered optional during a mixed collections. uint _index_in_opt_cset; - // Fields used by the HeapRegionSetBase class and subclasses. + // Fields used by the G1HeapRegionSetBase class and subclasses. G1HeapRegion* _next; G1HeapRegion* _prev; #ifdef ASSERT - HeapRegionSetBase* _containing_set; + G1HeapRegionSetBase* _containing_set; #endif // ASSERT // The area above this limit is fully parsable. This limit @@ -276,7 +276,7 @@ class G1HeapRegion : public CHeapObj { MemRegion mr, G1CardSetConfiguration* config); - // If this region is a member of a HeapRegionManager, the index in that + // If this region is a member of a G1HeapRegionManager, the index in that // sequence, otherwise -1. uint hrm_index() const { return _hrm_index; } @@ -418,9 +418,9 @@ class G1HeapRegion : public CHeapObj { // Unsets the humongous-related fields on the region. void clear_humongous(); - void set_rem_set(HeapRegionRemSet* rem_set) { _rem_set = rem_set; } + void set_rem_set(G1HeapRegionRemSet* rem_set) { _rem_set = rem_set; } // If the region has a remembered set, return a pointer to it. - HeapRegionRemSet* rem_set() const { + G1HeapRegionRemSet* rem_set() const { return _rem_set; } @@ -428,7 +428,7 @@ class G1HeapRegion : public CHeapObj { void prepare_remset_for_scan(); - // Methods used by the HeapRegionSetBase class and subclasses. + // Methods used by the G1HeapRegionSetBase class and subclasses. // Getter and setter for the next and prev fields used to link regions into // linked lists. @@ -445,7 +445,7 @@ class G1HeapRegion : public CHeapObj { // the contents of a set are as they should be and it's only // available in non-product builds. #ifdef ASSERT - void set_containing_set(HeapRegionSetBase* containing_set) { + void set_containing_set(G1HeapRegionSetBase* containing_set) { assert((containing_set != nullptr && _containing_set == nullptr) || containing_set == nullptr, "containing_set: " PTR_FORMAT " " @@ -455,9 +455,9 @@ class G1HeapRegion : public CHeapObj { _containing_set = containing_set; } - HeapRegionSetBase* containing_set() { return _containing_set; } + G1HeapRegionSetBase* containing_set() { return _containing_set; } #else // ASSERT - void set_containing_set(HeapRegionSetBase* containing_set) { } + void set_containing_set(G1HeapRegionSetBase* containing_set) { } // containing_set() is only used in asserts so there's no reason // to provide a dummy version of it. @@ -552,10 +552,10 @@ class G1HeapRegion : public CHeapObj { bool verify(VerifyOption vo) const; }; -// HeapRegionClosure is used for iterating over regions. +// G1HeapRegionClosure is used for iterating over regions. // Terminates the iteration when the "do_heap_region" method returns "true". -class HeapRegionClosure : public StackObj { - friend class HeapRegionManager; +class G1HeapRegionClosure : public StackObj { + friend class G1HeapRegionManager; friend class G1CollectionSet; friend class G1CollectionSetCandidates; @@ -563,7 +563,7 @@ class HeapRegionClosure : public StackObj { void set_incomplete() { _is_complete = false; } public: - HeapRegionClosure(): _is_complete(true) {} + G1HeapRegionClosure(): _is_complete(true) {} // Typically called on each region until it returns true. virtual bool do_heap_region(G1HeapRegion* r) = 0; @@ -573,8 +573,8 @@ class HeapRegionClosure : public StackObj { bool is_complete() { return _is_complete; } }; -class HeapRegionIndexClosure : public StackObj { - friend class HeapRegionManager; +class G1HeapRegionIndexClosure : public StackObj { + friend class G1HeapRegionManager; friend class G1CollectionSet; friend class G1CollectionSetCandidates; @@ -582,7 +582,7 @@ class HeapRegionIndexClosure : public StackObj { void set_incomplete() { _is_complete = false; } public: - HeapRegionIndexClosure(): _is_complete(true) {} + G1HeapRegionIndexClosure(): _is_complete(true) {} // Typically called on each region until it returns true. virtual bool do_heap_region_index(uint region_index) = 0; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionBounds.hpp b/src/hotspot/share/gc/g1/g1HeapRegionBounds.hpp index 3cde2f77d4a5b..83314820c830c 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionBounds.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionBounds.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ #include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" -class HeapRegionBounds : public AllStatic { +class G1HeapRegionBounds : public AllStatic { private: // Minimum region size; we won't go lower than that. // We might want to decrease this in the future, to deal with small diff --git a/src/hotspot/share/gc/g1/g1HeapRegionBounds.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionBounds.inline.hpp index 473057144d30c..63c086c178abb 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionBounds.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionBounds.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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,19 +27,19 @@ #include "gc/g1/g1HeapRegionBounds.hpp" -size_t HeapRegionBounds::min_size() { +size_t G1HeapRegionBounds::min_size() { return MIN_REGION_SIZE; } -size_t HeapRegionBounds::max_ergonomics_size() { +size_t G1HeapRegionBounds::max_ergonomics_size() { return MAX_ERGONOMICS_SIZE; } -size_t HeapRegionBounds::max_size() { +size_t G1HeapRegionBounds::max_size() { return MAX_REGION_SIZE; } -size_t HeapRegionBounds::target_number() { +size_t G1HeapRegionBounds::target_number() { return TARGET_REGION_NUMBER; } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp index 6f01524a14b61..3be3ec2410c7e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "jfr/jfrEvents.hpp" #include "runtime/vmThread.hpp" -class DumpEventInfoClosure : public HeapRegionClosure { +class DumpEventInfoClosure : public G1HeapRegionClosure { public: bool do_heap_region(G1HeapRegion* r) { EventG1HeapRegionInformation evt; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 2cf6a4088d3f5..b37e65f8b868a 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ #include "runtime/orderAccess.hpp" #include "utilities/bitMap.inline.hpp" -class MasterFreeRegionListChecker : public HeapRegionSetChecker { +class G1MasterFreeRegionListChecker : public G1HeapRegionSetChecker { public: void check_mt_safety() { // Master Free List MT safety protocol: @@ -62,20 +62,20 @@ class MasterFreeRegionListChecker : public HeapRegionSetChecker { const char* get_description() { return "Free Regions"; } }; -HeapRegionManager::HeapRegionManager() : +G1HeapRegionManager::G1HeapRegionManager() : _bot_mapper(nullptr), _cardtable_mapper(nullptr), _committed_map(), _allocated_heapregions_length(0), _regions(), _heap_mapper(nullptr), _bitmap_mapper(nullptr), - _free_list("Free list", new MasterFreeRegionListChecker()) + _free_list("Free list", new G1MasterFreeRegionListChecker()) { } -void HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage, - G1RegionToSpaceMapper* bitmap, - G1RegionToSpaceMapper* bot, - G1RegionToSpaceMapper* cardtable) { +void G1HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage, + G1RegionToSpaceMapper* bitmap, + G1RegionToSpaceMapper* bot, + G1RegionToSpaceMapper* cardtable) { _allocated_heapregions_length = 0; _heap_mapper = heap_storage; @@ -90,7 +90,7 @@ void HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage, _committed_map.initialize(reserved_length()); } -G1HeapRegion* HeapRegionManager::allocate_free_region(HeapRegionType type, uint requested_node_index) { +G1HeapRegion* G1HeapRegionManager::allocate_free_region(G1HeapRegionType type, uint requested_node_index) { G1HeapRegion* hr = nullptr; bool from_head = !type.is_young(); G1NUMA* numa = G1NUMA::numa(); @@ -118,7 +118,7 @@ G1HeapRegion* HeapRegionManager::allocate_free_region(HeapRegionType type, uint return hr; } -G1HeapRegion* HeapRegionManager::allocate_humongous_from_free_list(uint num_regions) { +G1HeapRegion* G1HeapRegionManager::allocate_humongous_from_free_list(uint num_regions) { uint candidate = find_contiguous_in_free_list(num_regions); if (candidate == G1_NO_HRM_INDEX) { return nullptr; @@ -126,7 +126,7 @@ G1HeapRegion* HeapRegionManager::allocate_humongous_from_free_list(uint num_regi return allocate_free_regions_starting_at(candidate, num_regions); } -G1HeapRegion* HeapRegionManager::allocate_humongous_allow_expand(uint num_regions) { +G1HeapRegion* G1HeapRegionManager::allocate_humongous_allow_expand(uint num_regions) { uint candidate = find_contiguous_allow_expand(num_regions); if (candidate == G1_NO_HRM_INDEX) { return nullptr; @@ -135,25 +135,25 @@ G1HeapRegion* HeapRegionManager::allocate_humongous_allow_expand(uint num_region return allocate_free_regions_starting_at(candidate, num_regions); } -G1HeapRegion* HeapRegionManager::allocate_humongous(uint num_regions) { +G1HeapRegion* G1HeapRegionManager::allocate_humongous(uint num_regions) { // Special case a single region to avoid expensive search. if (num_regions == 1) { - return allocate_free_region(HeapRegionType::Humongous, G1NUMA::AnyNodeIndex); + return allocate_free_region(G1HeapRegionType::Humongous, G1NUMA::AnyNodeIndex); } return allocate_humongous_from_free_list(num_regions); } -G1HeapRegion* HeapRegionManager::expand_and_allocate_humongous(uint num_regions) { +G1HeapRegion* G1HeapRegionManager::expand_and_allocate_humongous(uint num_regions) { return allocate_humongous_allow_expand(num_regions); } #ifdef ASSERT -bool HeapRegionManager::is_free(G1HeapRegion* hr) const { +bool G1HeapRegionManager::is_free(G1HeapRegion* hr) const { return _free_list.contains(hr); } #endif -G1HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { +G1HeapRegion* G1HeapRegionManager::new_heap_region(uint hrm_index) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); HeapWord* bottom = g1h->bottom_addr_for_region(hrm_index); MemRegion mr(bottom, bottom + G1HeapRegion::GrainWords); @@ -161,7 +161,7 @@ G1HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { return g1h->new_heap_region(hrm_index, mr); } -void HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pretouch_workers) { +void G1HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pretouch_workers) { commit_regions(start, num_regions, pretouch_workers); for (uint i = start; i < start + num_regions; i++) { G1HeapRegion* hr = _regions.get_by_index(i); @@ -176,7 +176,7 @@ void HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pret activate_regions(start, num_regions); } -void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkerThreads* pretouch_workers) { +void G1HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkerThreads* pretouch_workers) { guarantee(num_regions > 0, "Must commit more than zero regions"); guarantee(num_regions <= available(), "Cannot commit more than the maximum amount of regions"); @@ -190,7 +190,7 @@ void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkerThr _cardtable_mapper->commit_regions(index, num_regions, pretouch_workers); } -void HeapRegionManager::uncommit_regions(uint start, uint num_regions) { +void G1HeapRegionManager::uncommit_regions(uint start, uint num_regions) { guarantee(num_regions > 0, "No point in calling this for zero regions"); uint end = start + num_regions; @@ -215,7 +215,7 @@ void HeapRegionManager::uncommit_regions(uint start, uint num_regions) { _committed_map.uncommit(start, end); } -void HeapRegionManager::initialize_regions(uint start, uint num_regions) { +void G1HeapRegionManager::initialize_regions(uint start, uint num_regions) { for (uint i = start; i < start + num_regions; i++) { assert(is_available(i), "Just made region %u available but is apparently not.", i); G1HeapRegion* hr = at(i); @@ -227,12 +227,12 @@ void HeapRegionManager::initialize_regions(uint start, uint num_regions) { } } -void HeapRegionManager::activate_regions(uint start, uint num_regions) { +void G1HeapRegionManager::activate_regions(uint start, uint num_regions) { _committed_map.activate(start, start + num_regions); initialize_regions(start, num_regions); } -void HeapRegionManager::reactivate_regions(uint start, uint num_regions) { +void G1HeapRegionManager::reactivate_regions(uint start, uint num_regions) { assert(num_regions > 0, "No point in calling this for zero regions"); clear_auxiliary_data_structures(start, num_regions); @@ -241,7 +241,7 @@ void HeapRegionManager::reactivate_regions(uint start, uint num_regions) { initialize_regions(start, num_regions); } -void HeapRegionManager::deactivate_regions(uint start, uint num_regions) { +void G1HeapRegionManager::deactivate_regions(uint start, uint num_regions) { assert(num_regions > 0, "Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start); assert(length() >= num_regions, "pre-condition"); @@ -256,7 +256,7 @@ void HeapRegionManager::deactivate_regions(uint start, uint num_regions) { _committed_map.deactivate(start, end); } -void HeapRegionManager::clear_auxiliary_data_structures(uint start, uint num_regions) { +void G1HeapRegionManager::clear_auxiliary_data_structures(uint start, uint num_regions) { // Signal marking bitmaps to clear the given regions. _bitmap_mapper->signal_mapping_changed(start, num_regions); // Signal G1BlockOffsetTable to clear the given regions. @@ -265,7 +265,7 @@ void HeapRegionManager::clear_auxiliary_data_structures(uint start, uint num_reg _cardtable_mapper->signal_mapping_changed(start, num_regions); } -MemoryUsage HeapRegionManager::get_auxiliary_data_memory_usage() const { +MemoryUsage G1HeapRegionManager::get_auxiliary_data_memory_usage() const { size_t used_sz = _bitmap_mapper->committed_size() + _bot_mapper->committed_size() + @@ -279,18 +279,18 @@ MemoryUsage HeapRegionManager::get_auxiliary_data_memory_usage() const { return MemoryUsage(0, used_sz, committed_sz, committed_sz); } -bool HeapRegionManager::has_inactive_regions() const { +bool G1HeapRegionManager::has_inactive_regions() const { return _committed_map.num_inactive() > 0; } -uint HeapRegionManager::uncommit_inactive_regions(uint limit) { +uint G1HeapRegionManager::uncommit_inactive_regions(uint limit) { assert(limit > 0, "Need to specify at least one region to uncommit"); uint uncommitted = 0; uint offset = 0; do { MutexLocker uc(Uncommit_lock, Mutex::_no_safepoint_check_flag); - HeapRegionRange range = _committed_map.next_inactive_range(offset); + G1HeapRegionRange range = _committed_map.next_inactive_range(offset); // No more regions available for uncommit. Return the number of regions // already uncommitted or 0 if there were no longer any inactive regions. if (range.length() == 0) { @@ -307,12 +307,12 @@ uint HeapRegionManager::uncommit_inactive_regions(uint limit) { return uncommitted; } -uint HeapRegionManager::expand_inactive(uint num_regions) { +uint G1HeapRegionManager::expand_inactive(uint num_regions) { uint offset = 0; uint expanded = 0; do { - HeapRegionRange regions = _committed_map.next_inactive_range(offset); + G1HeapRegionRange regions = _committed_map.next_inactive_range(offset); if (regions.length() == 0) { // No more unavailable regions. break; @@ -327,14 +327,14 @@ uint HeapRegionManager::expand_inactive(uint num_regions) { return expanded; } -uint HeapRegionManager::expand_any(uint num_regions, WorkerThreads* pretouch_workers) { +uint G1HeapRegionManager::expand_any(uint num_regions, WorkerThreads* pretouch_workers) { assert(num_regions > 0, "Must expand at least 1 region"); uint offset = 0; uint expanded = 0; do { - HeapRegionRange regions = _committed_map.next_committable_range(offset); + G1HeapRegionRange regions = _committed_map.next_committable_range(offset); if (regions.length() == 0) { // No more unavailable regions. break; @@ -349,7 +349,7 @@ uint HeapRegionManager::expand_any(uint num_regions, WorkerThreads* pretouch_wor return expanded; } -uint HeapRegionManager::expand_by(uint num_regions, WorkerThreads* pretouch_workers) { +uint G1HeapRegionManager::expand_by(uint num_regions, WorkerThreads* pretouch_workers) { assert(num_regions > 0, "Must expand at least 1 region"); // First "undo" any requests to uncommit memory concurrently by @@ -365,7 +365,7 @@ uint HeapRegionManager::expand_by(uint num_regions, WorkerThreads* pretouch_work return expanded; } -void HeapRegionManager::expand_exact(uint start, uint num_regions, WorkerThreads* pretouch_workers) { +void G1HeapRegionManager::expand_exact(uint start, uint num_regions, WorkerThreads* pretouch_workers) { assert(num_regions != 0, "Need to request at least one region"); uint end = start + num_regions; @@ -393,7 +393,7 @@ void HeapRegionManager::expand_exact(uint start, uint num_regions, WorkerThreads verify_optional(); } -uint HeapRegionManager::expand_on_preferred_node(uint preferred_index) { +uint G1HeapRegionManager::expand_on_preferred_node(uint preferred_index) { uint expand_candidate = UINT_MAX; if (available() >= 1) { @@ -420,13 +420,13 @@ uint HeapRegionManager::expand_on_preferred_node(uint preferred_index) { return 1; } -bool HeapRegionManager::is_on_preferred_index(uint region_index, uint preferred_node_index) { +bool G1HeapRegionManager::is_on_preferred_index(uint region_index, uint preferred_node_index) { uint region_node_index = G1NUMA::numa()->preferred_node_index_for_index(region_index); return region_node_index == preferred_node_index; } #ifdef ASSERT -void HeapRegionManager::assert_contiguous_range(uint start, uint num_regions) { +void G1HeapRegionManager::assert_contiguous_range(uint start, uint num_regions) { // General sanity check, regions found should either be available and empty // or not available so that we can make them available and use them. for (uint i = start; i < (start + num_regions); i++) { @@ -439,7 +439,7 @@ void HeapRegionManager::assert_contiguous_range(uint start, uint num_regions) { } #endif -uint HeapRegionManager::find_contiguous_in_range(uint start, uint end, uint num_regions) { +uint G1HeapRegionManager::find_contiguous_in_range(uint start, uint end, uint num_regions) { assert(start <= end, "precondition"); assert(num_regions >= 1, "precondition"); uint candidate = start; // First region in candidate sequence. @@ -465,9 +465,9 @@ uint HeapRegionManager::find_contiguous_in_range(uint start, uint end, uint num_ return G1_NO_HRM_INDEX; } -uint HeapRegionManager::find_contiguous_in_free_list(uint num_regions) { +uint G1HeapRegionManager::find_contiguous_in_free_list(uint num_regions) { uint candidate = G1_NO_HRM_INDEX; - HeapRegionRange range(0,0); + G1HeapRegionRange range(0,0); do { range = _committed_map.next_active_range(range.end()); @@ -477,7 +477,7 @@ uint HeapRegionManager::find_contiguous_in_free_list(uint num_regions) { return candidate; } -uint HeapRegionManager::find_contiguous_allow_expand(uint num_regions) { +uint G1HeapRegionManager::find_contiguous_allow_expand(uint num_regions) { // Check if we can actually satisfy the allocation. if (num_regions > available()) { return G1_NO_HRM_INDEX; @@ -486,7 +486,7 @@ uint HeapRegionManager::find_contiguous_allow_expand(uint num_regions) { return find_contiguous_in_range(0, reserved_length(), num_regions); } -G1HeapRegion* HeapRegionManager::next_region_in_heap(const G1HeapRegion* r) const { +G1HeapRegion* G1HeapRegionManager::next_region_in_heap(const G1HeapRegion* r) const { guarantee(r != nullptr, "Start region must be a valid region"); guarantee(is_available(r->hrm_index()), "Trying to iterate starting from region %u which is not in the heap", r->hrm_index()); for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) { @@ -498,7 +498,7 @@ G1HeapRegion* HeapRegionManager::next_region_in_heap(const G1HeapRegion* r) cons return nullptr; } -void HeapRegionManager::iterate(HeapRegionClosure* blk) const { +void G1HeapRegionManager::iterate(G1HeapRegionClosure* blk) const { uint len = reserved_length(); for (uint i = 0; i < len; i++) { @@ -514,7 +514,7 @@ void HeapRegionManager::iterate(HeapRegionClosure* blk) const { } } -void HeapRegionManager::iterate(HeapRegionIndexClosure* blk) const { +void G1HeapRegionManager::iterate(G1HeapRegionIndexClosure* blk) const { uint len = reserved_length(); for (uint i = 0; i < len; i++) { @@ -529,7 +529,7 @@ void HeapRegionManager::iterate(HeapRegionIndexClosure* blk) const { } } -uint HeapRegionManager::find_highest_free(bool* expanded) { +uint G1HeapRegionManager::find_highest_free(bool* expanded) { // Loop downwards from the highest region index, looking for an // entry which is either free or not yet committed. If not yet // committed, expand at that index. @@ -551,7 +551,7 @@ uint HeapRegionManager::find_highest_free(bool* expanded) { return G1_NO_HRM_INDEX; } -bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count, WorkerThreads* pretouch_workers) { +bool G1HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count, WorkerThreads* pretouch_workers) { size_t commits = 0; uint start_index = (uint)_regions.get_index_by_address(range.start()); uint last_index = (uint)_regions.get_index_by_address(range.last()); @@ -574,7 +574,7 @@ bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* com return true; } -void HeapRegionManager::par_iterate(HeapRegionClosure* blk, HeapRegionClaimer* hrclaimer, const uint start_index) const { +void G1HeapRegionManager::par_iterate(G1HeapRegionClosure* blk, G1HeapRegionClaimer* hrclaimer, const uint start_index) const { // Every worker will actually look at all regions, skipping over regions that // are currently not committed. // This also (potentially) iterates over regions newly allocated during GC. This @@ -603,7 +603,7 @@ void HeapRegionManager::par_iterate(HeapRegionClosure* blk, HeapRegionClaimer* h } } -uint HeapRegionManager::shrink_by(uint num_regions_to_remove) { +uint G1HeapRegionManager::shrink_by(uint num_regions_to_remove) { assert(length() > 0, "the region sequence should not be empty"); assert(length() <= _allocated_heapregions_length, "invariant"); assert(_allocated_heapregions_length > 0, "we should have at least one region committed"); @@ -633,7 +633,7 @@ uint HeapRegionManager::shrink_by(uint num_regions_to_remove) { return removed; } -void HeapRegionManager::shrink_at(uint index, size_t num_regions) { +void G1HeapRegionManager::shrink_at(uint index, size_t num_regions) { #ifdef ASSERT for (uint i = index; i < (index + num_regions); i++) { assert(is_available(i), "Expected available region at index %u", i); @@ -645,7 +645,7 @@ void HeapRegionManager::shrink_at(uint index, size_t num_regions) { deactivate_regions(index, (uint) num_regions); } -uint HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const { +uint G1HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const { guarantee(start_idx <= _allocated_heapregions_length, "checking"); guarantee(res_idx != nullptr, "checking"); @@ -679,7 +679,7 @@ uint HeapRegionManager::find_empty_from_idx_reverse(uint start_idx, uint* res_id return num_regions_found; } -void HeapRegionManager::verify() { +void G1HeapRegionManager::verify() { guarantee(length() <= _allocated_heapregions_length, "invariant: _length: %u _allocated_length: %u", length(), _allocated_heapregions_length); @@ -724,65 +724,65 @@ void HeapRegionManager::verify() { } #ifndef PRODUCT -void HeapRegionManager::verify_optional() { +void G1HeapRegionManager::verify_optional() { verify(); } #endif // PRODUCT -HeapRegionClaimer::HeapRegionClaimer(uint n_workers) : +G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) : _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._allocated_heapregions_length), _claims(nullptr) { uint* new_claims = NEW_C_HEAP_ARRAY(uint, _n_regions, mtGC); memset(new_claims, Unclaimed, sizeof(*_claims) * _n_regions); _claims = new_claims; } -HeapRegionClaimer::~HeapRegionClaimer() { +G1HeapRegionClaimer::~G1HeapRegionClaimer() { FREE_C_HEAP_ARRAY(uint, _claims); } -uint HeapRegionClaimer::offset_for_worker(uint worker_id) const { +uint G1HeapRegionClaimer::offset_for_worker(uint worker_id) const { assert(_n_workers > 0, "must be set"); assert(worker_id < _n_workers, "Invalid worker_id."); return _n_regions * worker_id / _n_workers; } -bool HeapRegionClaimer::is_region_claimed(uint region_index) const { +bool G1HeapRegionClaimer::is_region_claimed(uint region_index) const { assert(region_index < _n_regions, "Invalid index."); return _claims[region_index] == Claimed; } -bool HeapRegionClaimer::claim_region(uint region_index) { +bool G1HeapRegionClaimer::claim_region(uint region_index) { assert(region_index < _n_regions, "Invalid index."); uint old_val = Atomic::cmpxchg(&_claims[region_index], Unclaimed, Claimed); return old_val == Unclaimed; } class G1RebuildFreeListTask : public WorkerTask { - HeapRegionManager* _hrm; - FreeRegionList* _worker_freelists; - uint _worker_chunk_size; - uint _num_workers; + G1HeapRegionManager* _hrm; + G1FreeRegionList* _worker_freelists; + uint _worker_chunk_size; + uint _num_workers; public: - G1RebuildFreeListTask(HeapRegionManager* hrm, uint num_workers) : + G1RebuildFreeListTask(G1HeapRegionManager* hrm, uint num_workers) : WorkerTask("G1 Rebuild Free List Task"), _hrm(hrm), - _worker_freelists(NEW_C_HEAP_ARRAY(FreeRegionList, num_workers, mtGC)), + _worker_freelists(NEW_C_HEAP_ARRAY(G1FreeRegionList, num_workers, mtGC)), _worker_chunk_size((_hrm->reserved_length() + num_workers - 1) / num_workers), _num_workers(num_workers) { for (uint worker = 0; worker < _num_workers; worker++) { - ::new (&_worker_freelists[worker]) FreeRegionList("Appendable Worker Free List"); + ::new (&_worker_freelists[worker]) G1FreeRegionList("Appendable Worker Free List"); } } ~G1RebuildFreeListTask() { for (uint worker = 0; worker < _num_workers; worker++) { - _worker_freelists[worker].~FreeRegionList(); + _worker_freelists[worker].~G1FreeRegionList(); } - FREE_C_HEAP_ARRAY(FreeRegionList, _worker_freelists); + FREE_C_HEAP_ARRAY(G1FreeRegionList, _worker_freelists); } - FreeRegionList* worker_freelist(uint worker) { + G1FreeRegionList* worker_freelist(uint worker) { return &_worker_freelists[worker]; } @@ -800,7 +800,7 @@ class G1RebuildFreeListTask : public WorkerTask { return; } - FreeRegionList* free_list = worker_freelist(worker_id); + G1FreeRegionList* free_list = worker_freelist(worker_id); for (uint i = start; i < end; i++) { G1HeapRegion* region = _hrm->at_or_null(i); if (region != nullptr && region->is_free()) { @@ -815,7 +815,7 @@ class G1RebuildFreeListTask : public WorkerTask { } }; -void HeapRegionManager::rebuild_free_list(WorkerThreads* workers) { +void G1HeapRegionManager::rebuild_free_list(WorkerThreads* workers) { // Abandon current free list to allow a rebuild. _free_list.abandon(); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp index 3162cc39a9938..d3f1843f07dbf 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,9 @@ #include "services/memoryUsage.hpp" class G1HeapRegion; -class HeapRegionClosure; -class HeapRegionClaimer; -class FreeRegionList; +class G1HeapRegionClaimer; +class G1HeapRegionClosure; +class G1FreeRegionList; class WorkerThreads; class G1HeapRegionTable : public G1BiasedMappedArray { @@ -49,7 +49,7 @@ class G1HeapRegionTable : public G1BiasedMappedArray { // This allows maximum flexibility for deciding what to commit or uncommit given // a request from outside. // -// HeapRegions are kept in the _regions array in address order. A region's +// G1HeapRegions are kept in the _regions array in address order. A region's // index in the array corresponds to its index in the heap (i.e., 0 is the // region at the bottom of the heap, 1 is the one after it, etc.). Two // regions that are consecutive in the array should also be adjacent in the @@ -65,14 +65,14 @@ class G1HeapRegionTable : public G1BiasedMappedArray { // * _num_committed (returned by length()) is the number of currently // committed regions. These may not be contiguous. // * _allocated_heapregions_length (not exposed outside this class) is the -// number of regions+1 for which we have HeapRegions. +// number of regions+1 for which we have G1HeapRegions. // * max_length() returns the maximum number of regions the heap may commit. // * reserved_length() returns the maximum number of regions the heap has reserved. // -class HeapRegionManager: public CHeapObj { +class G1HeapRegionManager: public CHeapObj { friend class VMStructs; - friend class HeapRegionClaimer; + friend class G1HeapRegionClaimer; G1RegionToSpaceMapper* _bot_mapper; G1RegionToSpaceMapper* _cardtable_mapper; @@ -90,7 +90,7 @@ class HeapRegionManager: public CHeapObj { // Pass down commit calls to the VirtualSpace. void commit_regions(uint index, size_t num_regions = 1, WorkerThreads* pretouch_workers = nullptr); - // Initialize the HeapRegions in the range and put them on the free list. + // Initialize the G1HeapRegions in the range and put them on the free list. void initialize_regions(uint start, uint num_regions); // Find a contiguous set of empty or uncommitted regions of length num_regions and return @@ -123,7 +123,7 @@ class HeapRegionManager: public CHeapObj { G1HeapRegionTable _regions; G1RegionToSpaceMapper* _heap_mapper; G1RegionToSpaceMapper* _bitmap_mapper; - FreeRegionList _free_list; + G1FreeRegionList _free_list; void expand(uint index, uint num_regions, WorkerThreads* pretouch_workers = nullptr); @@ -157,7 +157,7 @@ class HeapRegionManager: public CHeapObj { #endif public: // Empty constructor, we'll initialize it with the initialize() method. - HeapRegionManager(); + G1HeapRegionManager(); void initialize(G1RegionToSpaceMapper* heap_storage, G1RegionToSpaceMapper* bitmap, @@ -196,12 +196,12 @@ class HeapRegionManager: public CHeapObj { void rebuild_free_list(WorkerThreads* workers); // Insert the given region list into the global free region list. - void insert_list_into_free_list(FreeRegionList* list) { + void insert_list_into_free_list(G1FreeRegionList* list) { _free_list.add_ordered(list); } // Allocate a free region with specific node index. If fails allocate with next node index. - G1HeapRegion* allocate_free_region(HeapRegionType type, uint requested_node_index); + G1HeapRegion* allocate_free_region(G1HeapRegionType type, uint requested_node_index); // Allocate a humongous object from the free list G1HeapRegion* allocate_humongous(uint num_regions); @@ -246,7 +246,7 @@ class HeapRegionManager: public CHeapObj { MemRegion reserved() const { return MemRegion(heap_bottom(), heap_end()); } // Expand the sequence to reflect that the heap has grown. Either create new - // HeapRegions, or re-use existing ones. Returns the number of regions the + // G1HeapRegions, or re-use existing ones. Returns the number of regions the // sequence was expanded by. If a G1HeapRegion allocation fails, the resulting // number of regions might be smaller than what's desired. uint expand_by(uint num_regions, WorkerThreads* pretouch_workers); @@ -268,10 +268,10 @@ class HeapRegionManager: public CHeapObj { // Apply blk->do_heap_region() on all committed regions in address order, // terminating the iteration early if do_heap_region() returns true. - void iterate(HeapRegionClosure* blk) const; - void iterate(HeapRegionIndexClosure* blk) const; + void iterate(G1HeapRegionClosure* blk) const; + void iterate(G1HeapRegionIndexClosure* blk) const; - void par_iterate(HeapRegionClosure* blk, HeapRegionClaimer* hrclaimer, const uint start_index) const; + void par_iterate(G1HeapRegionClosure* blk, G1HeapRegionClaimer* hrclaimer, const uint start_index) const; // Uncommit up to num_regions_to_remove regions that are completely free. // Return the actual number of uncommitted regions. @@ -294,9 +294,9 @@ class HeapRegionManager: public CHeapObj { void verify_optional() PRODUCT_RETURN; }; -// The HeapRegionClaimer is used during parallel iteration over heap regions, +// The G1HeapRegionClaimer is used during parallel iteration over heap regions, // allowing workers to claim heap regions, gaining exclusive rights to these regions. -class HeapRegionClaimer : public StackObj { +class G1HeapRegionClaimer : public StackObj { uint _n_workers; uint _n_regions; volatile uint* _claims; @@ -305,8 +305,8 @@ class HeapRegionClaimer : public StackObj { static const uint Claimed = 1; public: - HeapRegionClaimer(uint n_workers); - ~HeapRegionClaimer(); + G1HeapRegionClaimer(uint n_workers); + ~G1HeapRegionClaimer(); inline uint n_regions() const { return _n_regions; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp index 0a74a22c52e1e..f78f12672e3ce 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,11 @@ #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1HeapRegionSet.inline.hpp" -inline bool HeapRegionManager::is_available(uint region) const { +inline bool G1HeapRegionManager::is_available(uint region) const { return _committed_map.active(region); } -inline G1HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { +inline G1HeapRegion* G1HeapRegionManager::addr_to_region(HeapWord* addr) const { assert(addr < heap_end(), "addr: " PTR_FORMAT " end: " PTR_FORMAT, p2i(addr), p2i(heap_end())); assert(addr >= heap_bottom(), @@ -43,7 +43,7 @@ inline G1HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { return _regions.get_by_address(addr); } -inline G1HeapRegion* HeapRegionManager::at(uint index) const { +inline G1HeapRegion* G1HeapRegionManager::at(uint index) const { assert(is_available(index), "pre-condition"); G1HeapRegion* hr = _regions.get_by_index(index); assert(hr != nullptr, "sanity"); @@ -51,7 +51,7 @@ inline G1HeapRegion* HeapRegionManager::at(uint index) const { return hr; } -inline G1HeapRegion* HeapRegionManager::at_or_null(uint index) const { +inline G1HeapRegion* G1HeapRegionManager::at_or_null(uint index) const { if (!is_available(index)) { return nullptr; } @@ -61,7 +61,7 @@ inline G1HeapRegion* HeapRegionManager::at_or_null(uint index) const { return hr; } -inline G1HeapRegion* HeapRegionManager::next_region_in_humongous(G1HeapRegion* hr) const { +inline G1HeapRegion* G1HeapRegionManager::next_region_in_humongous(G1HeapRegion* hr) const { uint index = hr->hrm_index(); assert(is_available(index), "pre-condition"); assert(hr->is_humongous(), "next_region_in_humongous should only be called for a humongous region."); @@ -73,11 +73,11 @@ inline G1HeapRegion* HeapRegionManager::next_region_in_humongous(G1HeapRegion* h } } -inline void HeapRegionManager::insert_into_free_list(G1HeapRegion* hr) { +inline void G1HeapRegionManager::insert_into_free_list(G1HeapRegion* hr) { _free_list.add_ordered(hr); } -inline G1HeapRegion* HeapRegionManager::allocate_free_regions_starting_at(uint first, uint num_regions) { +inline G1HeapRegion* G1HeapRegionManager::allocate_free_regions_starting_at(uint first, uint num_regions) { G1HeapRegion* start = at(first); _free_list.remove_starting_at(start, num_regions); return start; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp index bd686f3809d05..d7b1a6da92c17 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp @@ -29,7 +29,7 @@ #include "logging/log.hpp" #include "memory/allStatic.hpp" -class FreeRegionList; +class G1FreeRegionList; class G1HeapRegionPrinter : public AllStatic { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 2610fbde298e8..6e98b64adbc24 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,17 +45,17 @@ #include "utilities/growableArray.hpp" #include "utilities/powerOfTwo.hpp" -HeapWord* HeapRegionRemSet::_heap_base_address = nullptr; +HeapWord* G1HeapRegionRemSet::_heap_base_address = nullptr; -const char* HeapRegionRemSet::_state_strings[] = {"Untracked", "Updating", "Complete"}; -const char* HeapRegionRemSet::_short_state_strings[] = {"UNTRA", "UPDAT", "CMPLT"}; +const char* G1HeapRegionRemSet::_state_strings[] = {"Untracked", "Updating", "Complete"}; +const char* G1HeapRegionRemSet::_short_state_strings[] = {"UNTRA", "UPDAT", "CMPLT"}; -void HeapRegionRemSet::initialize(MemRegion reserved) { +void G1HeapRegionRemSet::initialize(MemRegion reserved) { G1CardSet::initialize(reserved); _heap_base_address = reserved.start(); } -HeapRegionRemSet::HeapRegionRemSet(G1HeapRegion* hr, +G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config) : _code_roots(), _card_set_mm(config, G1CollectedHeap::heap()->card_set_freelist_pool()), @@ -63,11 +63,11 @@ HeapRegionRemSet::HeapRegionRemSet(G1HeapRegion* hr, _hr(hr), _state(Untracked) { } -void HeapRegionRemSet::clear_fcc() { +void G1HeapRegionRemSet::clear_fcc() { G1FromCardCache::clear(_hr->hrm_index()); } -void HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { +void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { if (!only_cardset) { _code_roots.clear(); } @@ -81,17 +81,17 @@ void HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { assert(occupied() == 0, "Should be clear."); } -void HeapRegionRemSet::reset_table_scanner() { +void G1HeapRegionRemSet::reset_table_scanner() { _code_roots.reset_table_scanner(); _card_set.reset_table_scanner(); } -G1MonotonicArenaMemoryStats HeapRegionRemSet::card_set_memory_stats() const { +G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const { return _card_set_mm.memory_stats(); } -void HeapRegionRemSet::print_static_mem_size(outputStream* out) { - out->print_cr(" Static structures = " SIZE_FORMAT, HeapRegionRemSet::static_mem_size()); +void G1HeapRegionRemSet::print_static_mem_size(outputStream* out) { + out->print_cr(" Static structures = " SIZE_FORMAT, G1HeapRegionRemSet::static_mem_size()); } // Code roots support @@ -101,12 +101,12 @@ void HeapRegionRemSet::print_static_mem_size(outputStream* out) { // except when doing a full gc. // When not at safepoint the CodeCache_lock must be held during modifications. -void HeapRegionRemSet::add_code_root(nmethod* nm) { +void G1HeapRegionRemSet::add_code_root(nmethod* nm) { assert(nm != nullptr, "sanity"); _code_roots.add(nm); } -void HeapRegionRemSet::remove_code_root(nmethod* nm) { +void G1HeapRegionRemSet::remove_code_root(nmethod* nm) { assert(nm != nullptr, "sanity"); _code_roots.remove(nm); @@ -115,18 +115,18 @@ void HeapRegionRemSet::remove_code_root(nmethod* nm) { guarantee(!_code_roots.contains(nm), "duplicate entry found"); } -void HeapRegionRemSet::bulk_remove_code_roots() { +void G1HeapRegionRemSet::bulk_remove_code_roots() { _code_roots.bulk_remove(); } -void HeapRegionRemSet::code_roots_do(NMethodClosure* blk) const { +void G1HeapRegionRemSet::code_roots_do(NMethodClosure* blk) const { _code_roots.nmethods_do(blk); } -void HeapRegionRemSet::clean_code_roots(G1HeapRegion* hr) { +void G1HeapRegionRemSet::clean_code_roots(G1HeapRegion* hr) { _code_roots.clean(hr); } -size_t HeapRegionRemSet::code_roots_mem_size() { +size_t G1HeapRegionRemSet::code_roots_mem_size() { return _code_roots.mem_size(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index fb0a64ac0d18c..e92ecdc9cf9b0 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ class G1CardSetMemoryManager; class outputStream; -class HeapRegionRemSet : public CHeapObj { +class G1HeapRegionRemSet : public CHeapObj { friend class VMStructs; // A set of nmethods whose code contains pointers into @@ -57,7 +57,7 @@ class HeapRegionRemSet : public CHeapObj { void clear_fcc(); public: - HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config); + G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config); bool cardset_is_empty() const { return _card_set.is_empty(); @@ -126,7 +126,7 @@ class HeapRegionRemSet : public CHeapObj { // root set. size_t mem_size() { return _card_set.mem_size() - + (sizeof(HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet. + + (sizeof(G1HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet. + code_roots_mem_size(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index 78153cc0c3023..457027ad1260a 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ #include "runtime/atomic.hpp" #include "utilities/bitMap.inline.hpp" -void HeapRegionRemSet::set_state_untracked() { +void G1HeapRegionRemSet::set_state_untracked() { guarantee(SafepointSynchronize::is_at_safepoint() || !is_tracked(), "Should only set to Untracked during safepoint but is %s.", get_state_str()); if (_state == Untracked) { @@ -43,14 +43,14 @@ void HeapRegionRemSet::set_state_untracked() { _state = Untracked; } -void HeapRegionRemSet::set_state_updating() { +void G1HeapRegionRemSet::set_state_updating() { guarantee(SafepointSynchronize::is_at_safepoint() && !is_tracked(), "Should only set to Updating from Untracked during safepoint but is %s", get_state_str()); clear_fcc(); _state = Updating; } -void HeapRegionRemSet::set_state_complete() { +void G1HeapRegionRemSet::set_state_complete() { clear_fcc(); _state = Complete; } @@ -107,7 +107,7 @@ class G1HeapRegionRemSetMergeCardClosure : public G1CardSet::ContainerPtrClosure }; template -inline void HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) { +inline void G1HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) { G1HeapRegionRemSetMergeCardClosure cl2(&_card_set, cl, _card_set.config()->log2_card_regions_per_heap_region(), @@ -116,11 +116,11 @@ inline void HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) { } -uintptr_t HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { +uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { return pointer_delta(from, _heap_base_address, 1) >> CardTable::card_shift(); } -void HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { +void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { assert(_state != Untracked, "must be"); uint cur_idx = _hr->hrm_index(); @@ -136,11 +136,11 @@ void HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { _card_set.add_card(to_card(from)); } -bool HeapRegionRemSet::contains_reference(OopOrNarrowOopStar from) { +bool G1HeapRegionRemSet::contains_reference(OopOrNarrowOopStar from) { return _card_set.contains_card(to_card(from)); } -void HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) { +void G1HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) { _card_set.print_info(st, to_card(from)); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp index eaf475aff34e3..38796239168ef 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,10 @@ #include "gc/g1/g1HeapRegionSet.inline.hpp" #include "gc/g1/g1NUMA.hpp" -uint FreeRegionList::_unrealistically_long_length = 0; +uint G1FreeRegionList::_unrealistically_long_length = 0; #ifndef PRODUCT -void HeapRegionSetBase::verify_region(G1HeapRegion* hr) { +void G1HeapRegionSetBase::verify_region(G1HeapRegion* hr) { assert(hr->containing_set() == this, "Inconsistent containing set for %u", hr->hrm_index()); assert(!hr->is_young(), "Adding young region %u", hr->hrm_index()); // currently we don't use these sets for young regions assert(_checker == nullptr || _checker->is_correct_type(hr), "Wrong type of region %u (%s) and set %s", @@ -41,7 +41,7 @@ void HeapRegionSetBase::verify_region(G1HeapRegion* hr) { } #endif -void HeapRegionSetBase::verify() { +void G1HeapRegionSetBase::verify() { // It's important that we also observe the MT safety protocol even // for the verification calls. If we do verification without the // appropriate locks and the set changes underneath our feet @@ -53,18 +53,18 @@ void HeapRegionSetBase::verify() { "invariant"); } -void HeapRegionSetBase::verify_start() { +void G1HeapRegionSetBase::verify_start() { // See comment in verify() about MT safety and verification. check_mt_safety(); assert_heap_region_set(!_verify_in_progress, "verification should not be in progress"); // Do the basic verification first before we do the checks over the regions. - HeapRegionSetBase::verify(); + G1HeapRegionSetBase::verify(); _verify_in_progress = true; } -void HeapRegionSetBase::verify_end() { +void G1HeapRegionSetBase::verify_end() { // See comment in verify() about MT safety and verification. check_mt_safety(); assert_heap_region_set(_verify_in_progress, "verification should be in progress"); @@ -72,30 +72,30 @@ void HeapRegionSetBase::verify_end() { _verify_in_progress = false; } -void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { +void G1HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->cr(); out->print_cr("Set: %s (" PTR_FORMAT ")", name(), p2i(this)); out->print_cr(" Region Type : %s", _checker->get_description()); out->print_cr(" Length : %14u", length()); } -HeapRegionSetBase::HeapRegionSetBase(const char* name, HeapRegionSetChecker* checker) +G1HeapRegionSetBase::G1HeapRegionSetBase(const char* name, G1HeapRegionSetChecker* checker) : _checker(checker), _length(0), _name(name), _verify_in_progress(false) { } -void FreeRegionList::set_unrealistically_long_length(uint len) { +void G1FreeRegionList::set_unrealistically_long_length(uint len) { guarantee(_unrealistically_long_length == 0, "should only be set once"); _unrealistically_long_length = len; } -void FreeRegionList::abandon() { +void G1FreeRegionList::abandon() { check_mt_safety(); clear(); verify_optional(); } -void FreeRegionList::remove_all() { +void G1FreeRegionList::remove_all() { check_mt_safety(); verify_optional(); @@ -117,7 +117,7 @@ void FreeRegionList::remove_all() { verify_optional(); } -void FreeRegionList::add_list_common_start(FreeRegionList* from_list) { +void G1FreeRegionList::add_list_common_start(G1FreeRegionList* from_list) { check_mt_safety(); from_list->check_mt_safety(); verify_optional(); @@ -132,7 +132,7 @@ void FreeRegionList::add_list_common_start(FreeRegionList* from_list) { } #ifdef ASSERT - FreeRegionListIterator iter(from_list); + G1FreeRegionListIterator iter(from_list); while (iter.more_available()) { G1HeapRegion* hr = iter.get_next(); // In set_containing_set() we check that we either set the value @@ -144,7 +144,7 @@ void FreeRegionList::add_list_common_start(FreeRegionList* from_list) { #endif // ASSERT } -void FreeRegionList::add_list_common_end(FreeRegionList* from_list) { +void G1FreeRegionList::add_list_common_end(G1FreeRegionList* from_list) { _length += from_list->length(); from_list->clear(); @@ -152,7 +152,7 @@ void FreeRegionList::add_list_common_end(FreeRegionList* from_list) { from_list->verify_optional(); } -void FreeRegionList::append_ordered(FreeRegionList* from_list) { +void G1FreeRegionList::append_ordered(G1FreeRegionList* from_list) { add_list_common_start(from_list); if (from_list->is_empty()) { @@ -177,7 +177,7 @@ void FreeRegionList::append_ordered(FreeRegionList* from_list) { add_list_common_end(from_list); } -void FreeRegionList::add_ordered(FreeRegionList* from_list) { +void G1FreeRegionList::add_ordered(G1FreeRegionList* from_list) { add_list_common_start(from_list); if (from_list->is_empty()) { @@ -227,7 +227,7 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { } #ifdef ASSERT -void FreeRegionList::verify_region_to_remove(G1HeapRegion* curr, G1HeapRegion* next) { +void G1FreeRegionList::verify_region_to_remove(G1HeapRegion* curr, G1HeapRegion* next) { assert_free_region_list(_head != next, "invariant"); if (next != nullptr) { assert_free_region_list(next->prev() == curr, "invariant"); @@ -244,7 +244,7 @@ void FreeRegionList::verify_region_to_remove(G1HeapRegion* curr, G1HeapRegion* n } #endif -void FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions) { +void G1FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions) { check_mt_safety(); assert_free_region_list(num_regions >= 1, "pre-condition"); assert_free_region_list(!is_empty(), "pre-condition"); @@ -304,8 +304,8 @@ void FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions) { verify_optional(); } -void FreeRegionList::verify() { - // See comment in HeapRegionSetBase::verify() about MT safety and +void G1FreeRegionList::verify() { + // See comment in G1HeapRegionSetBase::verify() about MT safety and // verification. check_mt_safety(); @@ -317,7 +317,7 @@ void FreeRegionList::verify() { verify_end(); } -void FreeRegionList::clear() { +void G1FreeRegionList::clear() { _length = 0; _head = nullptr; _tail = nullptr; @@ -328,7 +328,7 @@ void FreeRegionList::clear() { } } -void FreeRegionList::verify_list() { +void G1FreeRegionList::verify_list() { G1HeapRegion* curr = _head; G1HeapRegion* prev1 = nullptr; G1HeapRegion* prev0 = nullptr; @@ -364,37 +364,37 @@ void FreeRegionList::verify_list() { } -FreeRegionList::FreeRegionList(const char* name, HeapRegionSetChecker* checker): - HeapRegionSetBase(name, checker), +G1FreeRegionList::G1FreeRegionList(const char* name, G1HeapRegionSetChecker* checker): + G1HeapRegionSetBase(name, checker), _node_info(G1NUMA::numa()->is_enabled() ? new NodeInfo() : nullptr) { clear(); } -FreeRegionList::~FreeRegionList() { +G1FreeRegionList::~G1FreeRegionList() { if (_node_info != nullptr) { delete _node_info; } } -FreeRegionList::NodeInfo::NodeInfo() : _numa(G1NUMA::numa()), _length_of_node(nullptr), - _num_nodes(_numa->num_active_nodes()) { +G1FreeRegionList::NodeInfo::NodeInfo() : _numa(G1NUMA::numa()), _length_of_node(nullptr), + _num_nodes(_numa->num_active_nodes()) { assert(UseNUMA, "Invariant"); _length_of_node = NEW_C_HEAP_ARRAY(uint, _num_nodes, mtGC); } -FreeRegionList::NodeInfo::~NodeInfo() { +G1FreeRegionList::NodeInfo::~NodeInfo() { FREE_C_HEAP_ARRAY(uint, _length_of_node); } -void FreeRegionList::NodeInfo::clear() { +void G1FreeRegionList::NodeInfo::clear() { for (uint i = 0; i < _num_nodes; ++i) { _length_of_node[i] = 0; } } -void FreeRegionList::NodeInfo::add(NodeInfo* info) { +void G1FreeRegionList::NodeInfo::add(NodeInfo* info) { for (uint i = 0; i < _num_nodes; ++i) { _length_of_node[i] += info->_length_of_node[i]; } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp index e401b38aadc94..19e98e8c54cfa 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,14 +48,14 @@ // Interface collecting various instance specific verification methods of -// HeapRegionSets. -class HeapRegionSetChecker : public CHeapObj { +// G1HeapRegionSets. +class G1HeapRegionSetChecker : public CHeapObj { public: - // Verify MT safety for this HeapRegionSet. + // Verify MT safety for this G1HeapRegionSet. virtual void check_mt_safety() = 0; - // Returns true if the given G1HeapRegion is of the correct type for this HeapRegionSet. + // Returns true if the given G1HeapRegion is of the correct type for this G1HeapRegionSet. virtual bool is_correct_type(G1HeapRegion* hr) = 0; - // Return a description of the type of regions this HeapRegionSet contains. + // Return a description of the type of regions this G1HeapRegionSet contains. virtual const char* get_description() = 0; }; @@ -64,10 +64,10 @@ class HeapRegionSetChecker : public CHeapObj { // (e.g., length, region num, used bytes sum) plus any shared // functionality (e.g., verification). -class HeapRegionSetBase { +class G1HeapRegionSetBase { friend class VMStructs; - HeapRegionSetChecker* _checker; + G1HeapRegionSetChecker* _checker; protected: // The number of regions in to the set. @@ -87,7 +87,7 @@ class HeapRegionSetBase { } } - HeapRegionSetBase(const char* name, HeapRegionSetChecker* verifier); + G1HeapRegionSetBase(const char* name, G1HeapRegionSetChecker* verifier); public: const char* name() { return _name; } @@ -117,12 +117,12 @@ class HeapRegionSetBase { // This class represents heap region sets whose members are not // explicitly tracked. It's helpful to group regions using such sets // so that we can reason about all the region groups in the heap using -// the same interface (namely, the HeapRegionSetBase API). +// the same interface (namely, the G1HeapRegionSetBase API). -class HeapRegionSet : public HeapRegionSetBase { +class G1HeapRegionSet : public G1HeapRegionSetBase { public: - HeapRegionSet(const char* name, HeapRegionSetChecker* checker): - HeapRegionSetBase(name, checker) { + G1HeapRegionSet(const char* name, G1HeapRegionSetChecker* checker): + G1HeapRegionSetBase(name, checker) { } void bulk_remove(const uint removed) { @@ -135,11 +135,11 @@ class HeapRegionSet : public HeapRegionSetBase { // such lists in performance critical paths. Typically we should // add / remove one region at a time or concatenate two lists. -class FreeRegionListIterator; +class G1FreeRegionListIterator; class G1NUMA; -class FreeRegionList : public HeapRegionSetBase { - friend class FreeRegionListIterator; +class G1FreeRegionList : public G1HeapRegionSetBase { + friend class G1FreeRegionListIterator; private: @@ -181,17 +181,17 @@ class FreeRegionList : public HeapRegionSetBase { inline void decrease_length(uint node_index); // Common checks for adding a list. - void add_list_common_start(FreeRegionList* from_list); - void add_list_common_end(FreeRegionList* from_list); + void add_list_common_start(G1FreeRegionList* from_list); + void add_list_common_end(G1FreeRegionList* from_list); void verify_region_to_remove(G1HeapRegion* curr, G1HeapRegion* next) NOT_DEBUG_RETURN; protected: - // See the comment for HeapRegionSetBase::clear() + // See the comment for G1HeapRegionSetBase::clear() virtual void clear(); public: - FreeRegionList(const char* name, HeapRegionSetChecker* checker = nullptr); - ~FreeRegionList(); + G1FreeRegionList(const char* name, G1HeapRegionSetChecker* checker = nullptr); + ~G1FreeRegionList(); void verify_list(); @@ -218,8 +218,8 @@ class FreeRegionList : public HeapRegionSetBase { // Merge two ordered lists. The result is also ordered. The order is // determined by hrm_index. - void add_ordered(FreeRegionList* from_list); - void append_ordered(FreeRegionList* from_list); + void add_ordered(G1FreeRegionList* from_list); + void append_ordered(G1FreeRegionList* from_list); // It empties the list by removing all regions from it. void remove_all(); @@ -235,16 +235,16 @@ class FreeRegionList : public HeapRegionSetBase { virtual void verify(); - using HeapRegionSetBase::length; + using G1HeapRegionSetBase::length; uint length(uint node_index) const; }; // Iterator class that provides a convenient way to iterate over the // regions of a FreeRegionList. -class FreeRegionListIterator : public StackObj { +class G1FreeRegionListIterator : public StackObj { private: - FreeRegionList* _list; + G1FreeRegionList* _list; G1HeapRegion* _curr; public: @@ -265,7 +265,7 @@ class FreeRegionListIterator : public StackObj { return hr; } - FreeRegionListIterator(FreeRegionList* list) + G1FreeRegionListIterator(G1FreeRegionList* list) : _list(list), _curr(list->_head) { } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp index f0a38a4175436..80b23616f9205 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ #include "gc/g1/g1NUMA.hpp" -inline void HeapRegionSetBase::add(G1HeapRegion* hr) { +inline void G1HeapRegionSetBase::add(G1HeapRegion* hr) { check_mt_safety(); assert_heap_region_set(hr->containing_set() == nullptr, "should not already have a containing set"); assert_heap_region_set(hr->next() == nullptr, "should not already be linked"); @@ -40,7 +40,7 @@ inline void HeapRegionSetBase::add(G1HeapRegion* hr) { verify_region(hr); } -inline void HeapRegionSetBase::remove(G1HeapRegion* hr) { +inline void G1HeapRegionSetBase::remove(G1HeapRegion* hr) { check_mt_safety(); verify_region(hr); assert_heap_region_set(hr->next() == nullptr, "should already be unlinked"); @@ -51,7 +51,7 @@ inline void HeapRegionSetBase::remove(G1HeapRegion* hr) { _length--; } -inline void FreeRegionList::add_to_tail(G1HeapRegion* region_to_add) { +inline void G1FreeRegionList::add_to_tail(G1HeapRegion* region_to_add) { assert_free_region_list((length() == 0 && _head == nullptr && _tail == nullptr && _last == nullptr) || (length() > 0 && _head != nullptr && _tail != nullptr && _tail->hrm_index() < region_to_add->hrm_index()), "invariant"); @@ -71,7 +71,7 @@ inline void FreeRegionList::add_to_tail(G1HeapRegion* region_to_add) { increase_length(region_to_add->node_index()); } -inline void FreeRegionList::add_ordered(G1HeapRegion* hr) { +inline void G1FreeRegionList::add_ordered(G1HeapRegion* hr) { assert_free_region_list((length() == 0 && _head == nullptr && _tail == nullptr && _last == nullptr) || (length() > 0 && _head != nullptr && _tail != nullptr), "invariant"); @@ -120,7 +120,7 @@ inline void FreeRegionList::add_ordered(G1HeapRegion* hr) { increase_length(hr->node_index()); } -inline G1HeapRegion* FreeRegionList::remove_from_head_impl() { +inline G1HeapRegion* G1FreeRegionList::remove_from_head_impl() { G1HeapRegion* result = _head; _head = result->next(); if (_head == nullptr) { @@ -132,7 +132,7 @@ inline G1HeapRegion* FreeRegionList::remove_from_head_impl() { return result; } -inline G1HeapRegion* FreeRegionList::remove_from_tail_impl() { +inline G1HeapRegion* G1FreeRegionList::remove_from_tail_impl() { G1HeapRegion* result = _tail; _tail = result->prev(); @@ -145,7 +145,7 @@ inline G1HeapRegion* FreeRegionList::remove_from_tail_impl() { return result; } -inline G1HeapRegion* FreeRegionList::remove_region(bool from_head) { +inline G1HeapRegion* G1FreeRegionList::remove_region(bool from_head) { check_mt_safety(); verify_optional(); @@ -174,7 +174,7 @@ inline G1HeapRegion* FreeRegionList::remove_region(bool from_head) { return hr; } -inline G1HeapRegion* FreeRegionList::remove_region_with_node_index(bool from_head, +inline G1HeapRegion* G1FreeRegionList::remove_region_with_node_index(bool from_head, uint requested_node_index) { assert(UseNUMA, "Invariant"); @@ -232,13 +232,13 @@ inline G1HeapRegion* FreeRegionList::remove_region_with_node_index(bool from_hea return cur; } -inline void FreeRegionList::NodeInfo::increase_length(uint node_index) { +inline void G1FreeRegionList::NodeInfo::increase_length(uint node_index) { if (node_index < _num_nodes) { _length_of_node[node_index] += 1; } } -inline void FreeRegionList::NodeInfo::decrease_length(uint node_index) { +inline void G1FreeRegionList::NodeInfo::decrease_length(uint node_index) { if (node_index < _num_nodes) { assert(_length_of_node[node_index] > 0, "Current length %u should be greater than zero for node %u", @@ -247,23 +247,23 @@ inline void FreeRegionList::NodeInfo::decrease_length(uint node_index) { } } -inline uint FreeRegionList::NodeInfo::length(uint node_index) const { +inline uint G1FreeRegionList::NodeInfo::length(uint node_index) const { return _length_of_node[node_index]; } -inline void FreeRegionList::increase_length(uint node_index) { +inline void G1FreeRegionList::increase_length(uint node_index) { if (_node_info != nullptr) { return _node_info->increase_length(node_index); } } -inline void FreeRegionList::decrease_length(uint node_index) { +inline void G1FreeRegionList::decrease_length(uint node_index) { if (_node_info != nullptr) { return _node_info->decrease_length(node_index); } } -inline uint FreeRegionList::length(uint node_index) const { +inline uint G1FreeRegionList::length(uint node_index) const { if (_node_info != nullptr) { return _node_info->length(node_index); } else { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionTracer.cpp b/src/hotspot/share/gc/g1/g1HeapRegionTracer.cpp index c66ae0cb06941..749b7d2d1f5cc 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionTracer.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionTracer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "gc/g1/g1HeapRegionTracer.hpp" #include "jfr/jfrEvents.hpp" -void HeapRegionTracer::send_region_type_change(uint index, +void G1HeapRegionTracer::send_region_type_change(uint index, G1HeapRegionTraceType::Type from, G1HeapRegionTraceType::Type to, uintptr_t start, diff --git a/src/hotspot/share/gc/g1/g1HeapRegionTracer.hpp b/src/hotspot/share/gc/g1/g1HeapRegionTracer.hpp index 137bc6189aed0..42c88aa5f0fad 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionTracer.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionTracer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ #include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" -class HeapRegionTracer : AllStatic { +class G1HeapRegionTracer : AllStatic { public: static void send_region_type_change(uint index, G1HeapRegionTraceType::Type from, diff --git a/src/hotspot/share/gc/g1/g1HeapRegionType.cpp b/src/hotspot/share/gc/g1/g1HeapRegionType.cpp index e55759b3bf38d..c6d38e341be33 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionType.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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,12 +26,12 @@ #include "gc/g1/g1HeapRegionTraceType.hpp" #include "gc/g1/g1HeapRegionType.hpp" -const HeapRegionType HeapRegionType::Eden = HeapRegionType(EdenTag); -const HeapRegionType HeapRegionType::Survivor = HeapRegionType(SurvTag); -const HeapRegionType HeapRegionType::Old = HeapRegionType(OldTag); -const HeapRegionType HeapRegionType::Humongous = HeapRegionType(StartsHumongousTag); +const G1HeapRegionType G1HeapRegionType::Eden = G1HeapRegionType(EdenTag); +const G1HeapRegionType G1HeapRegionType::Survivor = G1HeapRegionType(SurvTag); +const G1HeapRegionType G1HeapRegionType::Old = G1HeapRegionType(OldTag); +const G1HeapRegionType G1HeapRegionType::Humongous = G1HeapRegionType(StartsHumongousTag); -bool HeapRegionType::is_valid(Tag tag) { +bool G1HeapRegionType::is_valid(Tag tag) { switch (tag) { case FreeTag: case EdenTag: @@ -45,7 +45,7 @@ bool HeapRegionType::is_valid(Tag tag) { } } -const char* HeapRegionType::get_str() const { +const char* G1HeapRegionType::get_str() const { hrt_assert_is_valid(_tag); switch (_tag) { case FreeTag: return "FREE"; @@ -60,7 +60,7 @@ const char* HeapRegionType::get_str() const { } } -const char* HeapRegionType::get_short_str() const { +const char* G1HeapRegionType::get_short_str() const { hrt_assert_is_valid(_tag); switch (_tag) { case FreeTag: return "F"; @@ -75,7 +75,7 @@ const char* HeapRegionType::get_short_str() const { } } -G1HeapRegionTraceType::Type HeapRegionType::get_trace_type() { +G1HeapRegionTraceType::Type G1HeapRegionType::get_trace_type() { hrt_assert_is_valid(_tag); switch (_tag) { case FreeTag: return G1HeapRegionTraceType::Free; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionType.hpp b/src/hotspot/share/gc/g1/g1HeapRegionType.hpp index b62699cc3fb9e..839df68febd90 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionType.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionType.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +31,7 @@ #define hrt_assert_is_valid(tag) \ assert(is_valid((tag)), "invalid HR type: %u", (uint) (tag)) -class HeapRegionType { +class G1HeapRegionType { friend class VMStructs; private: @@ -101,7 +101,7 @@ friend class VMStructs; } // Private constructor used for static constants - HeapRegionType(Tag t) : _tag(t) { hrt_assert_is_valid(_tag); } + G1HeapRegionType(Tag t) : _tag(t) { hrt_assert_is_valid(_tag); } public: // Queries @@ -159,12 +159,12 @@ friend class VMStructs; const char* get_short_str() const; G1HeapRegionTraceType::Type get_trace_type(); - HeapRegionType() : _tag(FreeTag) { hrt_assert_is_valid(_tag); } + G1HeapRegionType() : _tag(FreeTag) { hrt_assert_is_valid(_tag); } - static const HeapRegionType Eden; - static const HeapRegionType Survivor; - static const HeapRegionType Old; - static const HeapRegionType Humongous; + static const G1HeapRegionType Eden; + static const G1HeapRegionType Survivor; + static const G1HeapRegionType Old; + static const G1HeapRegionType Humongous; }; #endif // SHARE_GC_G1_G1HEAPREGIONTYPE_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index 8804d37cc719a..815b701c4be90 100644 --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ struct G1HeapTransition::DetailedUsage : public StackObj { _humongous_region_count(0) {} }; -class G1HeapTransition::DetailedUsageClosure: public HeapRegionClosure { +class G1HeapTransition::DetailedUsageClosure: public G1HeapRegionClosure { public: DetailedUsage _usage; bool do_heap_region(G1HeapRegion* r) { diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 9201fc98c8a14..7d399b8265e65 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,7 @@ class G1VerifyCodeRootOopClosure: public OopClosure { // Now fetch the region containing the object G1HeapRegion* hr = _g1h->heap_region_containing(obj); - HeapRegionRemSet* hrrs = hr->rem_set(); + G1HeapRegionRemSet* hrrs = hr->rem_set(); // Verify that the code root list for this region // contains the nmethod if (!hrrs->code_roots_list_contains(_nm)) { @@ -231,7 +231,7 @@ class VerifyObjsInRegionClosure: public ObjectClosure { size_t live_bytes() { return _live_bytes; } }; -class VerifyRegionClosure: public HeapRegionClosure { +class VerifyRegionClosure: public G1HeapRegionClosure { private: VerifyOption _vo; bool _failures; @@ -287,10 +287,10 @@ class VerifyRegionClosure: public HeapRegionClosure { class G1VerifyTask: public WorkerTask { private: - G1CollectedHeap* _g1h; - VerifyOption _vo; - bool _failures; - HeapRegionClaimer _hrclaimer; + G1CollectedHeap* _g1h; + VerifyOption _vo; + bool _failures; + G1HeapRegionClaimer _hrclaimer; public: G1VerifyTask(G1CollectedHeap* g1h, VerifyOption vo) : @@ -377,20 +377,20 @@ void G1HeapVerifier::verify(VerifyOption vo) { // Heap region set verification -class VerifyRegionListsClosure : public HeapRegionClosure { +class VerifyRegionListsClosure : public G1HeapRegionClosure { private: - HeapRegionSet* _old_set; - HeapRegionSet* _humongous_set; - HeapRegionManager* _hrm; + G1HeapRegionSet* _old_set; + G1HeapRegionSet* _humongous_set; + G1HeapRegionManager* _hrm; public: uint _old_count; uint _humongous_count; uint _free_count; - VerifyRegionListsClosure(HeapRegionSet* old_set, - HeapRegionSet* humongous_set, - HeapRegionManager* hrm) : + VerifyRegionListsClosure(G1HeapRegionSet* old_set, + G1HeapRegionSet* humongous_set, + G1HeapRegionManager* hrm) : _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm), _old_count(), _humongous_count(), _free_count(){ } @@ -412,7 +412,7 @@ class VerifyRegionListsClosure : public HeapRegionClosure { return false; } - void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) { + void verify_counts(G1HeapRegionSet* old_set, G1HeapRegionSet* humongous_set, G1HeapRegionManager* free_list) { guarantee(old_set->length() == _old_count, "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count); guarantee(humongous_set->length() == _humongous_count, "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count); guarantee(free_list->num_free_regions() == _free_count, "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count); @@ -435,7 +435,7 @@ void G1HeapVerifier::verify_region_sets() { _g1h->collection_set()->candidates()->verify(); } -class G1VerifyRegionMarkingStateClosure : public HeapRegionClosure { +class G1VerifyRegionMarkingStateClosure : public G1HeapRegionClosure { class MarkedBytesClosure { size_t _marked_words; @@ -535,7 +535,7 @@ void G1HeapVerifier::verify_bitmap_clear(bool from_tams) { return; } - class G1VerifyBitmapClear : public HeapRegionClosure { + class G1VerifyBitmapClear : public G1HeapRegionClosure { bool _from_tams; public: @@ -557,7 +557,7 @@ void G1HeapVerifier::verify_bitmap_clear(bool from_tams) { } #ifndef PRODUCT -class G1VerifyCardTableCleanup: public HeapRegionClosure { +class G1VerifyCardTableCleanup: public G1HeapRegionClosure { G1HeapVerifier* _verifier; public: G1VerifyCardTableCleanup(G1HeapVerifier* verifier) @@ -603,11 +603,11 @@ void G1HeapVerifier::verify_dirty_region(G1HeapRegion* hr) { } } -class G1VerifyDirtyYoungListClosure : public HeapRegionClosure { +class G1VerifyDirtyYoungListClosure : public G1HeapRegionClosure { private: G1HeapVerifier* _verifier; public: - G1VerifyDirtyYoungListClosure(G1HeapVerifier* verifier) : HeapRegionClosure(), _verifier(verifier) { } + G1VerifyDirtyYoungListClosure(G1HeapVerifier* verifier) : G1HeapRegionClosure(), _verifier(verifier) { } virtual bool do_heap_region(G1HeapRegion* r) { _verifier->verify_dirty_region(r); return false; @@ -619,12 +619,12 @@ void G1HeapVerifier::verify_dirty_young_regions() { _g1h->collection_set()->iterate(&cl); } -class G1CheckRegionAttrTableClosure : public HeapRegionClosure { +class G1CheckRegionAttrTableClosure : public G1HeapRegionClosure { private: bool _failures; public: - G1CheckRegionAttrTableClosure() : HeapRegionClosure(), _failures(false) { } + G1CheckRegionAttrTableClosure() : G1HeapRegionClosure(), _failures(false) { } virtual bool do_heap_region(G1HeapRegion* hr) { uint i = hr->hrm_index(); diff --git a/src/hotspot/share/gc/g1/g1NUMA.cpp b/src/hotspot/share/gc/g1/g1NUMA.cpp index fd80bd52ce17e..923d3af621d70 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.cpp +++ b/src/hotspot/share/gc/g1/g1NUMA.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -224,7 +224,7 @@ void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint G1NUMA::max_search_depth() const { // Multiple of 3 is just random number to limit iterations. - // There would be some cases that 1 page may be consisted of multiple HeapRegions. + // There would be some cases that 1 page may be consisted of multiple heap regions. return 3 * MAX2((uint)(page_size() / region_size()), (uint)1) * num_active_nodes(); } diff --git a/src/hotspot/share/gc/g1/g1NUMA.hpp b/src/hotspot/share/gc/g1/g1NUMA.hpp index e9726fcad1b49..72d6702822bb1 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.hpp +++ b/src/hotspot/share/gc/g1/g1NUMA.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,7 @@ class G1NUMA: public CHeapObj { uint index_of_current_thread() const; // Returns the preferred index for the given G1HeapRegion index. - // This assumes that HeapRegions are evenly spit, so we can decide preferred index + // This assumes that heap regions are evenly spit, so we can decide preferred index // with the given G1HeapRegion index. // Result is less than num_active_nodes(). uint preferred_node_index_for_index(uint region_index) const; @@ -127,7 +127,7 @@ class G1NUMA: public CHeapObj { void print_statistics() const; }; -class G1NodeIndexCheckClosure : public HeapRegionClosure { +class G1NodeIndexCheckClosure : public G1HeapRegionClosure { const char* _desc; G1NUMA* _numa; // Records matched count of each node. diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 1d4a1d5ab8661..26cc88de0beb5 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,7 +146,7 @@ inline void G1ConcurrentRefineOopClosure::do_oop_work(T* p) { return; } - HeapRegionRemSet* to_rem_set = _g1h->heap_region_containing(obj)->rem_set(); + G1HeapRegionRemSet* to_rem_set = _g1h->heap_region_containing(obj)->rem_set(); assert(to_rem_set != nullptr, "Need per-region 'into' remsets."); if (to_rem_set->is_tracked()) { @@ -266,7 +266,7 @@ template void G1RebuildRemSetClosure::do_oop_work(T* p) { } G1HeapRegion* to = _g1h->heap_region_containing(obj); - HeapRegionRemSet* rem_set = to->rem_set(); + G1HeapRegionRemSet* rem_set = to->rem_set(); if (rem_set->is_tracked()) { rem_set->add_reference(p, _worker_id); } diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 39c9c2c7a30e9..f2426cdfca5f9 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -365,7 +365,7 @@ class G1RemSetScanState : public CHeapObj { _next_dirty_regions = nullptr; } - void iterate_dirty_regions_from(HeapRegionClosure* cl, uint worker_id) { + void iterate_dirty_regions_from(G1HeapRegionClosure* cl, uint worker_id) { uint num_regions = _next_dirty_regions->size(); if (num_regions == 0) { @@ -481,7 +481,7 @@ class G1CardTableChunkClaimer { }; // Scans a heap region for dirty cards. -class G1ScanHRForRegionClosure : public HeapRegionClosure { +class G1ScanHRForRegionClosure : public G1HeapRegionClosure { using CardValue = CardTable::CardValue; G1CollectedHeap* _g1h; @@ -755,7 +755,7 @@ class G1ScanAndCountNMethodClosure : public NMethodClosure { // Heap region closure to be applied to all regions in the current collection set // increment to fix up non-card related roots. -class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { +class G1ScanCollectionSetRegionClosure : public G1HeapRegionClosure { G1ParScanThreadState* _pss; G1RemSetScanState* _scan_state; @@ -972,13 +972,13 @@ class G1MergeHeapRootsTask : public WorkerTask { // Visitor for remembered sets. Several methods of it are called by a region's // card set iterator to drop card set remembered set entries onto the card. - // table. This is in addition to being the HeapRegionClosure to iterate over + // table. This is in addition to being the HG1eapRegionClosure to iterate over // all region's remembered sets. // // We add a small prefetching cache in front of the actual work as dropping // onto the card table is basically random memory access. This improves // performance of this operation significantly. - class G1MergeCardSetClosure : public HeapRegionClosure { + class G1MergeCardSetClosure : public G1HeapRegionClosure { friend class G1MergeCardSetCache; G1RemSetScanState* _scan_state; @@ -1074,7 +1074,7 @@ class G1MergeHeapRootsTask : public WorkerTask { void merge_card_set_for_region(G1HeapRegion* r) { assert(r->in_collection_set() || r->is_starts_humongous(), "must be"); - HeapRegionRemSet* rem_set = r->rem_set(); + G1HeapRegionRemSet* rem_set = r->rem_set(); if (!rem_set->is_empty()) { rem_set->iterate_for_merge(*this); } @@ -1098,7 +1098,7 @@ class G1MergeHeapRootsTask : public WorkerTask { // Closure to make sure that the marking bitmap is clear for any old region in // the collection set. // This is needed to be able to use the bitmap for evacuation failure handling. - class G1ClearBitmapClosure : public HeapRegionClosure { + class G1ClearBitmapClosure : public G1HeapRegionClosure { G1CollectedHeap* _g1h; void assert_bitmap_clear(G1HeapRegion* hr, const G1CMBitMap* bitmap) { @@ -1144,11 +1144,11 @@ class G1MergeHeapRootsTask : public WorkerTask { // Helper to allow two closure to be applied when // iterating through the collection set. - class G1CombinedClosure : public HeapRegionClosure { - HeapRegionClosure* _closure1; - HeapRegionClosure* _closure2; + class G1CombinedClosure : public G1HeapRegionClosure { + G1HeapRegionClosure* _closure1; + G1HeapRegionClosure* _closure2; public: - G1CombinedClosure(HeapRegionClosure* cl1, HeapRegionClosure* cl2) : + G1CombinedClosure(G1HeapRegionClosure* cl1, G1HeapRegionClosure* cl2) : _closure1(cl1), _closure2(cl2) { } @@ -1160,7 +1160,7 @@ class G1MergeHeapRootsTask : public WorkerTask { // Visitor for the remembered sets of humongous candidate regions to merge their // remembered set into the card table. - class G1FlushHumongousCandidateRemSets : public HeapRegionIndexClosure { + class G1FlushHumongousCandidateRemSets : public G1HeapRegionIndexClosure { G1MergeCardSetClosure _cl; public: diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index 65eabc312a6c5..0445ad185d3e9 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ class CardTableBarrierSet; class G1AbstractSubTask; class G1CollectedHeap; class G1CMBitMap; +class G1HeapRegionClaimer; class G1RemSetScanState; class G1ParScanThreadState; class G1ParScanThreadStateSet; @@ -49,7 +50,6 @@ class G1Policy; class G1RemSetSamplingTask; class G1ScanCardClosure; class G1ServiceThread; -class HeapRegionClaimer; // A G1RemSet in which each heap region has a rem set that records the // external heap references into it. Uses a mod ref bs to track updates, diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index b8a0c709276cc..14fb8c0b8d273 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,7 +181,7 @@ class RegionTypeCounter { }; -class HRRSStatsIter: public HeapRegionClosure { +class HRRSStatsIter: public G1HeapRegionClosure { private: RegionTypeCounter _young; RegionTypeCounter _humongous; @@ -216,9 +216,9 @@ class HRRSStatsIter: public HeapRegionClosure { {} bool do_heap_region(G1HeapRegion* r) { - HeapRegionRemSet* hrrs = r->rem_set(); + G1HeapRegionRemSet* hrrs = r->rem_set(); - // HeapRegionRemSet::mem_size() includes the + // G1HeapRegionRemSet::mem_size() includes the // size of the code roots size_t rs_unused_mem_sz = hrrs->unused_mem_size(); size_t rs_mem_sz = hrrs->mem_size(); @@ -274,19 +274,19 @@ class HRRSStatsIter: public HeapRegionClosure { } // Largest sized rem set region statistics - HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); + G1HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); out->print_cr(" Region with largest rem set = " HR_FORMAT ", " "size = " SIZE_FORMAT " occupied = " SIZE_FORMAT, HR_FORMAT_PARAMS(max_rs_mem_sz_region()), rem_set->mem_size(), rem_set->occupied()); - HeapRegionRemSet::print_static_mem_size(out); + G1HeapRegionRemSet::print_static_mem_size(out); G1CollectedHeap* g1h = G1CollectedHeap::heap(); g1h->card_set_freelist_pool()->print_on(out); // Code root statistics - HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); + G1HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); out->print_cr(" Total heap region code root sets sizes = " SIZE_FORMAT "%s." " Max = " SIZE_FORMAT "%s.", byte_size_in_proper_unit(total_code_root_mem_sz()), diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index d0d49fa6d4000..cadab2fbc489d 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -259,7 +259,7 @@ void G1YoungCollector::wait_for_root_region_scanning() { phase_times()->record_root_region_scan_wait_time(wait_time.seconds() * MILLIUNITS); } -class G1PrintCollectionSetClosure : public HeapRegionClosure { +class G1PrintCollectionSetClosure : public G1HeapRegionClosure { public: virtual bool do_heap_region(G1HeapRegion* r) { G1HeapRegionPrinter::cset(r); @@ -286,7 +286,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou } class G1PrepareEvacuationTask : public WorkerTask { - class G1PrepareRegionsClosure : public HeapRegionClosure { + class G1PrepareRegionsClosure : public G1HeapRegionClosure { G1CollectedHeap* _g1h; G1PrepareEvacuationTask* _parent_task; uint _worker_humongous_total; @@ -418,7 +418,7 @@ class G1PrepareEvacuationTask : public WorkerTask { }; G1CollectedHeap* _g1h; - HeapRegionClaimer _claimer; + G1HeapRegionClaimer _claimer; volatile uint _humongous_total; volatile uint _humongous_candidates; diff --git a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp index 066f4353d4c0b..dcf42b31bb133 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp @@ -30,7 +30,7 @@ #if ALLOCATION_FAILURE_INJECTOR -class SelectAllocationFailureRegionClosure : public HeapRegionClosure { +class SelectAllocationFailureRegionClosure : public G1HeapRegionClosure { CHeapBitMap& _allocation_failure_regions; size_t _allocation_failure_regions_num; diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 90c85250c05fa..c5ebdb3d22dd0 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -333,7 +333,7 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1 } } -class G1FreeHumongousRegionClosure : public HeapRegionIndexClosure { +class G1FreeHumongousRegionClosure : public G1HeapRegionIndexClosure { uint _humongous_objects_reclaimed; uint _humongous_regions_reclaimed; size_t _freed_bytes; @@ -537,9 +537,9 @@ class RedirtyLoggedCardTableEntryClosure : public G1CardTableEntryClosure { class G1PostEvacuateCollectionSetCleanupTask2::ProcessEvacuationFailedRegionsTask : public G1AbstractSubTask { G1EvacFailureRegions* _evac_failure_regions; - HeapRegionClaimer _claimer; + G1HeapRegionClaimer _claimer; - class ProcessEvacuationFailedRegionsClosure : public HeapRegionClosure { + class ProcessEvacuationFailedRegionsClosure : public G1HeapRegionClosure { public: bool do_heap_region(G1HeapRegion* r) override { @@ -706,7 +706,7 @@ class FreeCSetStats { }; // Closure applied to all regions in the collection set. -class FreeCSetClosure : public HeapRegionClosure { +class FreeCSetClosure : public G1HeapRegionClosure { // Helper to send JFR events for regions. class JFREventForRegion { EventGCPhaseParallel _event; @@ -807,7 +807,7 @@ class FreeCSetClosure : public HeapRegionClosure { uint worker_id, FreeCSetStats* stats, G1EvacFailureRegions* evac_failure_regions) : - HeapRegionClosure(), + G1HeapRegionClosure(), _g1h(G1CollectedHeap::heap()), _surviving_young_words(surviving_young_words), _worker_id(worker_id), @@ -853,14 +853,14 @@ class FreeCSetClosure : public HeapRegionClosure { }; class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1AbstractSubTask { - G1CollectedHeap* _g1h; - G1EvacInfo* _evacuation_info; - FreeCSetStats* _worker_stats; - HeapRegionClaimer _claimer; - const size_t* _surviving_young_words; - uint _active_workers; + G1CollectedHeap* _g1h; + G1EvacInfo* _evacuation_info; + FreeCSetStats* _worker_stats; + G1HeapRegionClaimer _claimer; + const size_t* _surviving_young_words; + uint _active_workers; G1EvacFailureRegions* _evac_failure_regions; - volatile uint _num_retained_regions; + volatile uint _num_retained_regions; FreeCSetStats* worker_stats(uint worker) { return &_worker_stats[worker]; diff --git a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp index 46c850cb643a4..0a29caed8ccd8 100644 --- a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1HeapRegionSize=0 means will be set ergonomically. - if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { + if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < G1HeapRegionBounds::min_size())) { JVMFlag::printError(verbose, "G1HeapRegionSize (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic heap region minimum size\n", @@ -180,7 +180,7 @@ JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { } size_t MaxSizeForHeapAlignmentG1() { - return HeapRegionBounds::max_size(); + return G1HeapRegionBounds::max_size(); } static JVMFlag::Error buffer_size_constraint_helper(JVMFlagsEnum flagid, diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index ec0db2d978215..22c4cfc584aba 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -37,13 +37,13 @@ static_field(G1HeapRegion, GrainBytes, size_t) \ static_field(G1HeapRegion, LogOfHRGrainBytes, uint) \ \ - nonstatic_field(G1HeapRegion, _type, HeapRegionType) \ + nonstatic_field(G1HeapRegion, _type, G1HeapRegionType) \ nonstatic_field(G1HeapRegion, _bottom, HeapWord* const) \ nonstatic_field(G1HeapRegion, _top, HeapWord* volatile) \ nonstatic_field(G1HeapRegion, _end, HeapWord* const) \ volatile_nonstatic_field(G1HeapRegion, _pinned_object_count, size_t) \ \ - nonstatic_field(HeapRegionType, _tag, HeapRegionType::Tag volatile) \ + nonstatic_field(G1HeapRegionType, _tag, G1HeapRegionType::Tag volatile) \ \ \ nonstatic_field(G1HeapRegionTable, _base, address) \ @@ -52,13 +52,13 @@ nonstatic_field(G1HeapRegionTable, _bias, size_t) \ nonstatic_field(G1HeapRegionTable, _shift_by, uint) \ \ - nonstatic_field(HeapRegionManager, _regions, G1HeapRegionTable) \ + nonstatic_field(G1HeapRegionManager, _regions, G1HeapRegionTable) \ \ volatile_nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \ - nonstatic_field(G1CollectedHeap, _hrm, HeapRegionManager) \ + nonstatic_field(G1CollectedHeap, _hrm, G1HeapRegionManager) \ nonstatic_field(G1CollectedHeap, _monitoring_support, G1MonitoringSupport*) \ - nonstatic_field(G1CollectedHeap, _old_set, HeapRegionSetBase) \ - nonstatic_field(G1CollectedHeap, _humongous_set, HeapRegionSetBase) \ + nonstatic_field(G1CollectedHeap, _old_set, G1HeapRegionSetBase) \ + nonstatic_field(G1CollectedHeap, _humongous_set, G1HeapRegionSetBase) \ \ nonstatic_field(G1MonitoringSupport, _eden_space_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _eden_space_used, size_t) \ @@ -67,21 +67,21 @@ nonstatic_field(G1MonitoringSupport, _old_gen_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _old_gen_used, size_t) \ \ - nonstatic_field(HeapRegionSetBase, _length, uint) \ + nonstatic_field(G1HeapRegionSetBase, _length, uint) \ \ nonstatic_field(SATBMarkQueue, _active, bool) \ nonstatic_field(PtrQueue, _buf, void**) \ nonstatic_field(PtrQueue, _index, size_t) #define VM_INT_CONSTANTS_G1GC(declare_constant, declare_constant_with_value) \ - declare_constant(HeapRegionType::FreeTag) \ - declare_constant(HeapRegionType::YoungMask) \ - declare_constant(HeapRegionType::EdenTag) \ - declare_constant(HeapRegionType::SurvTag) \ - declare_constant(HeapRegionType::HumongousMask) \ - declare_constant(HeapRegionType::StartsHumongousTag) \ - declare_constant(HeapRegionType::ContinuesHumongousTag) \ - declare_constant(HeapRegionType::OldMask) \ + declare_constant(G1HeapRegionType::FreeTag) \ + declare_constant(G1HeapRegionType::YoungMask) \ + declare_constant(G1HeapRegionType::EdenTag) \ + declare_constant(G1HeapRegionType::SurvTag) \ + declare_constant(G1HeapRegionType::HumongousMask) \ + declare_constant(G1HeapRegionType::StartsHumongousTag) \ + declare_constant(G1HeapRegionType::ContinuesHumongousTag) \ + declare_constant(G1HeapRegionType::OldMask) \ declare_constant(BarrierSet::G1BarrierSet) \ declare_constant(G1CardTable::g1_young_gen) @@ -94,11 +94,11 @@ declare_type(G1CollectedHeap, CollectedHeap) \ \ declare_toplevel_type(G1HeapRegion) \ - declare_toplevel_type(HeapRegionManager) \ - declare_toplevel_type(HeapRegionSetBase) \ + declare_toplevel_type(G1HeapRegionManager) \ + declare_toplevel_type(G1HeapRegionSetBase) \ declare_toplevel_type(G1MonitoringSupport) \ declare_toplevel_type(PtrQueue) \ - declare_toplevel_type(HeapRegionType) \ + declare_toplevel_type(G1HeapRegionType) \ declare_toplevel_type(SATBMarkQueue) \ declare_toplevel_type(G1DirtyCardQueue) \ \ @@ -106,6 +106,6 @@ declare_toplevel_type(G1HeapRegion*) \ declare_toplevel_type(G1MonitoringSupport*) \ \ - declare_integer_type(HeapRegionType::Tag volatile) + declare_integer_type(G1HeapRegionType::Tag volatile) #endif // SHARE_GC_G1_VMSTRUCTS_G1_HPP diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index c480f8a09ac1c..a799d5b5de42d 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -608,7 +608,7 @@ WB_ENTRY(jintArray, WB_G1MemoryNodeIds(JNIEnv* env, jobject o)) THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1MemoryNodeIds: G1 GC is not enabled"); WB_END -class OldRegionsLivenessClosure: public HeapRegionClosure { +class OldRegionsLivenessClosure: public G1HeapRegionClosure { private: const int _liveness; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java index 16e91d0a0cdec..a68b8b596b45a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java @@ -30,8 +30,8 @@ import sun.jvm.hotspot.utilities.Observer; import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.gc.g1.HeapRegionClosure; -import sun.jvm.hotspot.gc.g1.PrintRegionClosure; +import sun.jvm.hotspot.gc.g1.G1HeapRegionClosure; +import sun.jvm.hotspot.gc.g1.G1PrintRegionClosure; import sun.jvm.hotspot.gc.shared.CollectedHeap; import sun.jvm.hotspot.gc.shared.CollectedHeapName; import sun.jvm.hotspot.gc.shared.LiveRegionsClosure; @@ -47,7 +47,7 @@ // Mirror class for G1CollectedHeap. public class G1CollectedHeap extends CollectedHeap { - // HeapRegionManager _hrm; + // G1HeapRegionManager _hrm; private static long hrmFieldOffset; // MemRegion _g1_reserved; private static long g1ReservedFieldOffset; @@ -55,9 +55,9 @@ public class G1CollectedHeap extends CollectedHeap { private static CIntegerField summaryBytesUsedField; // G1MonitoringSupport* _monitoring_support; private static AddressField monitoringSupportField; - // HeapRegionSet _old_set; + // G1HeapRegionSet _old_set; private static long oldSetFieldOffset; - // HeapRegionSet _humongous_set; + // G1HeapRegionSet _humongous_set; private static long humongousSetFieldOffset; static { @@ -90,9 +90,9 @@ public long n_regions() { return hrm().length(); } - public HeapRegionManager hrm() { + public G1HeapRegionManager hrm() { Address hrmAddr = addr.addOffsetTo(hrmFieldOffset); - return VMObjectFactory.newObject(HeapRegionManager.class, hrmAddr); + return VMObjectFactory.newObject(G1HeapRegionManager.class, hrmAddr); } public G1MonitoringSupport monitoringSupport() { @@ -100,21 +100,21 @@ public G1MonitoringSupport monitoringSupport() { return VMObjectFactory.newObject(G1MonitoringSupport.class, monitoringSupportAddr); } - public HeapRegionSetBase oldSet() { + public G1HeapRegionSetBase oldSet() { Address oldSetAddr = addr.addOffsetTo(oldSetFieldOffset); - return VMObjectFactory.newObject(HeapRegionSetBase.class, oldSetAddr); + return VMObjectFactory.newObject(G1HeapRegionSetBase.class, oldSetAddr); } - public HeapRegionSetBase humongousSet() { + public G1HeapRegionSetBase humongousSet() { Address humongousSetAddr = addr.addOffsetTo(humongousSetFieldOffset); - return VMObjectFactory.newObject(HeapRegionSetBase.class, humongousSetAddr); + return VMObjectFactory.newObject(G1HeapRegionSetBase.class, humongousSetAddr); } private Iterator heapRegionIterator() { return hrm().heapRegionIterator(); } - public void heapRegionIterate(HeapRegionClosure hrcl) { + public void heapRegionIterate(G1HeapRegionClosure hrcl) { Iterator iter = heapRegionIterator(); while (iter.hasNext()) { G1HeapRegion hr = iter.next(); @@ -159,7 +159,7 @@ public void printOn(PrintStream tty) { } public void printRegionDetails(PrintStream tty) { - PrintRegionClosure prc = new PrintRegionClosure(tty); + G1PrintRegionClosure prc = new G1PrintRegionClosure(tty); heapRegionIterate(prc); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java index ef270ba5671b7..5cf9b3c3b7586 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java @@ -55,7 +55,7 @@ public class G1HeapRegion extends ContiguousSpace implements LiveRegionsProvider private static long typeFieldOffset; private static long pointerSize; - private HeapRegionType type; + private G1HeapRegionType type; static { VM.registerVMInitializedObserver(new Observer() { @@ -88,7 +88,7 @@ public G1HeapRegion(Address addr) { super(addr); Address typeAddr = (addr instanceof OopHandle) ? addr.addOffsetToAsOopHandle(typeFieldOffset) : addr.addOffsetTo(typeFieldOffset); - type = VMObjectFactory.newObject(HeapRegionType.class, typeAddr); + type = VMObjectFactory.newObject(G1HeapRegionType.class, typeAddr); } public Address bottom() { return bottomField.getValue(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionClosure.java similarity index 89% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionClosure.java index d63679d309957..4203e6952f8d7 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionClosure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,6 @@ package sun.jvm.hotspot.gc.g1; -public interface HeapRegionClosure { +public interface G1HeapRegionClosure { public void doHeapRegion(G1HeapRegion hr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionManager.java similarity index 92% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionManager.java index d79723c2c80f5..d1e2a4687314c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionManager.java @@ -37,9 +37,9 @@ import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -// Mirror class for HeapRegionManager. +// Mirror class for G1HeapRegionManager. -public class HeapRegionManager extends VMObject { +public class G1HeapRegionManager extends VMObject { // G1HeapRegionTable _regions private static long regionsFieldOffset; @@ -52,7 +52,7 @@ public void update(Observable o, Object data) { } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("HeapRegionManager"); + Type type = db.lookupType("G1HeapRegionManager"); regionsFieldOffset = type.getField("_regions").getOffset(); } @@ -74,7 +74,7 @@ public Iterator heapRegionIterator() { return regions().heapRegionIterator(length()); } - public HeapRegionManager(Address addr) { + public G1HeapRegionManager(Address addr) { super(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionSetBase.java similarity index 90% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionSetBase.java index 7cfcf938d9ecc..5d44c46d01388 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionSetBase.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionSetBase.java @@ -37,9 +37,9 @@ import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -// Mirror class for HeapRegionSetBase. Represents a group of regions. +// Mirror class for G1HeapRegionSetBase. Represents a group of regions. -public class HeapRegionSetBase extends VMObject { +public class G1HeapRegionSetBase extends VMObject { // uint _length private static CIntegerField lengthField; @@ -53,7 +53,7 @@ public void update(Observable o, Object data) { } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("HeapRegionSetBase"); + Type type = db.lookupType("G1HeapRegionSetBase"); lengthField = type.getCIntegerField("_length"); } @@ -62,7 +62,7 @@ public long length() { return lengthField.getValue(addr); } - public HeapRegionSetBase(Address addr) { + public G1HeapRegionSetBase(Address addr) { super(addr); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionType.java similarity index 79% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionType.java index 1e5787849005a..e5536bbe70390 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,10 +33,10 @@ import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -// Mirror class for HeapRegionType. Currently we don't actually include +// Mirror class for G1HeapRegionType. Currently we don't actually include // any of its fields but only iterate over it. -public class HeapRegionType extends VMObject { +public class G1HeapRegionType extends VMObject { private static int freeTag; private static int youngMask; @@ -58,18 +58,18 @@ public void update(Observable o, Object data) { } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("HeapRegionType"); + Type type = db.lookupType("G1HeapRegionType"); tagField = type.getCIntegerField("_tag"); - freeTag = db.lookupIntConstant("HeapRegionType::FreeTag"); - youngMask = db.lookupIntConstant("HeapRegionType::YoungMask"); - edenTag = db.lookupIntConstant("HeapRegionType::EdenTag"); - survTag = db.lookupIntConstant("HeapRegionType::SurvTag"); - startsHumongousTag = db.lookupIntConstant("HeapRegionType::StartsHumongousTag"); - continuesHumongousTag = db.lookupIntConstant("HeapRegionType::ContinuesHumongousTag"); - humongousMask = db.lookupIntConstant("HeapRegionType::HumongousMask"); - oldMask = db.lookupIntConstant("HeapRegionType::OldMask"); + freeTag = db.lookupIntConstant("G1HeapRegionType::FreeTag"); + youngMask = db.lookupIntConstant("G1HeapRegionType::YoungMask"); + edenTag = db.lookupIntConstant("G1HeapRegionType::EdenTag"); + survTag = db.lookupIntConstant("G1HeapRegionType::SurvTag"); + startsHumongousTag = db.lookupIntConstant("G1HeapRegionType::StartsHumongousTag"); + continuesHumongousTag = db.lookupIntConstant("G1HeapRegionType::ContinuesHumongousTag"); + humongousMask = db.lookupIntConstant("G1HeapRegionType::HumongousMask"); + oldMask = db.lookupIntConstant("G1HeapRegionType::OldMask"); } public boolean isFree() { @@ -104,7 +104,7 @@ public boolean isOld() { return (tagField.getValue(addr) & oldMask) != 0; } - public HeapRegionType(Address addr) { + public G1HeapRegionType(Address addr) { super(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1PrintRegionClosure.java similarity index 91% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1PrintRegionClosure.java index fb777f35167c5..340f40e288d5f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1PrintRegionClosure.java @@ -27,10 +27,10 @@ import java.io.PrintStream; import sun.jvm.hotspot.gc.g1.G1HeapRegion; -public class PrintRegionClosure implements HeapRegionClosure { +public class G1PrintRegionClosure implements G1HeapRegionClosure { private PrintStream tty; - public PrintRegionClosure(PrintStream tty) { + public G1PrintRegionClosure(PrintStream tty) { this.tty = tty; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index 22eb627d39ff5..86a1216bbd3d4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -252,8 +252,8 @@ public void printG1HeapSummary(PrintStream tty, G1CollectedHeap g1h) { G1MonitoringSupport monitoringSupport = g1h.monitoringSupport(); long edenSpaceRegionNum = monitoringSupport.edenSpaceRegionNum(); long survivorSpaceRegionNum = monitoringSupport.survivorSpaceRegionNum(); - HeapRegionSetBase oldSet = g1h.oldSet(); - HeapRegionSetBase humongousSet = g1h.humongousSet(); + G1HeapRegionSetBase oldSet = g1h.oldSet(); + G1HeapRegionSetBase humongousSet = g1h.humongousSet(); long oldGenRegionNum = oldSet.length() + humongousSet.length(); printG1Space(tty, "G1 Heap:", g1h.n_regions(), g1h.used(), g1h.capacity()); diff --git a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp index 60ebf3c72082a..bc45626deecb0 100644 --- a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp +++ b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp @@ -34,12 +34,12 @@ #include "unittest.hpp" // @requires UseG1GC -TEST_OTHER_VM(FreeRegionList, length) { +TEST_OTHER_VM(G1FreeRegionList, length) { if (!UseG1GC) { return; } - FreeRegionList l("test"); + G1FreeRegionList l("test"); const uint num_regions_in_test = 5; // Create a fake heap. It does not need to be valid, as the G1HeapRegion constructor diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index 21ae6e9c1da04..fcc3053bd851e 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -236,8 +236,8 @@ void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_b } TEST_VM_F(G1CardSetContainersTest, basic_cardset_inptr_test) { - uint const min = (uint)log2i(HeapRegionBounds::min_size()); - uint const max = (uint)log2i(HeapRegionBounds::max_size()); + uint const min = (uint)log2i(G1HeapRegionBounds::min_size()); + uint const max = (uint)log2i(G1HeapRegionBounds::max_size()); for (uint i = min; i <= max; i++) { G1CardSetContainersTest::cardset_inlineptr_test(i - CardTable::card_shift()); diff --git a/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp b/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp index feb5f58bbde52..f9075f27bd48f 100644 --- a/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp @@ -62,7 +62,7 @@ static void generate_random_map(G1CommittedRegionMap* map) { static void random_deactivate(G1CommittedRegionMap* map) { uint current_offset = 0; do { - HeapRegionRange current = map->next_active_range(current_offset); + G1HeapRegionRange current = map->next_active_range(current_offset); if (mutate()) { if (current.length() < 5) { // For short ranges, deactivate whole. @@ -79,7 +79,7 @@ static void random_deactivate(G1CommittedRegionMap* map) { static void random_uncommit_or_reactive(G1CommittedRegionMap* map) { uint current_offset = 0; do { - HeapRegionRange current = map->next_inactive_range(current_offset); + G1HeapRegionRange current = map->next_inactive_range(current_offset); // Randomly either reactivate or uncommit if (mutate()) { map->reactivate(current.start(), current.end()); @@ -94,7 +94,7 @@ static void random_uncommit_or_reactive(G1CommittedRegionMap* map) { static void random_activate_free(G1CommittedRegionMap* map) { uint current_offset = 0; do { - HeapRegionRange current = map->next_committable_range(current_offset); + G1HeapRegionRange current = map->next_committable_range(current_offset); // Randomly either reactivate or uncommit if (mutate()) { if (current.length() < 5) { From 6409ec336af647044d0746c219496ad070de5e9d Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 5 Jul 2024 08:43:27 +0000 Subject: [PATCH 173/288] 8335711: G1: Remove unused bot_updates argument in G1AllocRegion constructor Reviewed-by: iwalulya, tschatzl --- src/hotspot/share/gc/g1/g1AllocRegion.cpp | 4 +--- src/hotspot/share/gc/g1/g1AllocRegion.hpp | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index c4ab81cda8fc4..b06f8fd32235f 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -236,9 +236,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_ } #endif // PRODUCT -G1AllocRegion::G1AllocRegion(const char* name, - bool bot_updates, - uint node_index) +G1AllocRegion::G1AllocRegion(const char* name, uint node_index) : _alloc_region(nullptr), _count(0), _name(name), diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index 391ded283885f..4d2d18dd6b8c3 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -118,7 +118,7 @@ class G1AllocRegion : public CHeapObj { virtual G1HeapRegion* allocate_new_region(size_t word_size) = 0; virtual void retire_region(G1HeapRegion* alloc_region) = 0; - G1AllocRegion(const char* name, bool bot_updates, uint node_index); + G1AllocRegion(const char* name, uint node_index); public: static void setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region); @@ -188,7 +188,7 @@ class MutatorAllocRegion : public G1AllocRegion { size_t retire(bool fill_up) override; public: MutatorAllocRegion(uint node_index) - : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */, node_index), + : G1AllocRegion("Mutator Alloc Region", node_index), _wasted_bytes(0), _retained_alloc_region(nullptr) { } @@ -228,9 +228,9 @@ class G1GCAllocRegion : public G1AllocRegion { size_t retire(bool fill_up) override; - G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, + G1GCAllocRegion(const char* name, G1EvacStats* stats, G1HeapRegionAttr::region_type_t purpose, uint node_index = G1NUMA::AnyNodeIndex) - : G1AllocRegion(name, bot_updates, node_index), _used_bytes_before(0), _stats(stats), _purpose(purpose) { + : G1AllocRegion(name, node_index), _used_bytes_before(0), _stats(stats), _purpose(purpose) { assert(stats != nullptr, "Must pass non-null PLAB statistics"); } public: @@ -243,13 +243,13 @@ class G1GCAllocRegion : public G1AllocRegion { class SurvivorGCAllocRegion : public G1GCAllocRegion { public: SurvivorGCAllocRegion(G1EvacStats* stats, uint node_index) - : G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, G1HeapRegionAttr::Young, node_index) { } + : G1GCAllocRegion("Survivor GC Alloc Region", stats, G1HeapRegionAttr::Young, node_index) { } }; class OldGCAllocRegion : public G1GCAllocRegion { public: OldGCAllocRegion(G1EvacStats* stats) - : G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, G1HeapRegionAttr::Old) { } + : G1GCAllocRegion("Old GC Alloc Region", stats, G1HeapRegionAttr::Old) { } }; #endif // SHARE_GC_G1_G1ALLOCREGION_HPP From bdf470b3b8f8814cb29f2877490d5bc1e79bdecb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 5 Jul 2024 09:06:37 +0000 Subject: [PATCH 174/288] 8335742: Problemlist gc/g1/TestMixedGCLiveThreshold.java#25percent with virtual threads Reviewed-by: aboldtch, kbarrett --- test/hotspot/jtreg/ProblemList-Virtual.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index e7627be7b8c0b..ac35f60e66153 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -86,6 +86,11 @@ vmTestbase/nsk/jdi/ExceptionEvent/catchLocation/location002/TestDescription.java vmTestbase/nsk/jdi/VMOutOfMemoryException/VMOutOfMemoryException001/VMOutOfMemoryException001.java 8285417 generic-all +### +# Fails on Windows because of additional memory allocation. + +gc/g1/TestMixedGCLiveThreshold.java#25percent JDK-8334759 windows-x64 + ########## ## Tests incompatible with with virtual test thread factory. ## There is no goal to run all test with virtual test thread factory. From c8acea87e2c5ba6672c011ec4e57a53c55fee74b Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Fri, 5 Jul 2024 09:10:30 +0000 Subject: [PATCH 175/288] 8335706: G1: Remove unused G1ConcurrentRefine::RemSetSamplingClosure::_cset Reviewed-by: ayang, tschatzl --- src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index b51d0cdf84aee..7d6cc9a41cb64 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -254,13 +254,12 @@ uint64_t G1ConcurrentRefine::adjust_threads_wait_ms() const { } class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { - G1CollectionSet* _cset; size_t _sampled_card_rs_length; size_t _sampled_code_root_rs_length; public: - explicit RemSetSamplingClosure(G1CollectionSet* cset) : - _cset(cset), _sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {} + RemSetSamplingClosure() : + _sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {} bool do_heap_region(G1HeapRegion* r) override { G1HeapRegionRemSet* rem_set = r->rem_set(); @@ -287,8 +286,8 @@ class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { // gen size to keep pause time length goal. void G1ConcurrentRefine::adjust_young_list_target_length() { if (_policy->use_adaptive_young_list_length()) { + RemSetSamplingClosure cl; G1CollectionSet* cset = G1CollectedHeap::heap()->collection_set(); - RemSetSamplingClosure cl{cset}; cset->iterate(&cl); _policy->revise_young_list_target_length(cl.sampled_card_rs_length(), cl.sampled_code_root_rs_length()); } From 194425d7875ef42fce52516ed59c81ee97720399 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 5 Jul 2024 12:50:09 +0000 Subject: [PATCH 176/288] 8335645: j.u.Formatter#trailingZeros improved with String repeat Reviewed-by: liach, jlu, naoto --- src/java.base/share/classes/java/util/Formatter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index 41b9540001c83..dfdb77cc6ace2 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -4249,8 +4249,8 @@ private int adjustWidth(int width, int flags, boolean neg) { // Add trailing zeros private void trailingZeros(StringBuilder sb, int nzeros) { - for (int i = 0; i < nzeros; i++) { - sb.append('0'); + if (nzeros > 0) { + sb.repeat('0', nzeros); } } From ff49f677ee5017019c90823bc412ceb90068ffbd Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 5 Jul 2024 13:44:35 +0000 Subject: [PATCH 177/288] 8335775: Remove extraneous 's' in comment of rawmonitor.cpp test file Reviewed-by: gdams, stuefe --- .../nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp index 11ef7e18d7bd9..6ee955ae420dd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp @@ -1,5 +1,4 @@ /* -s * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * From 7efe16038e5df9894a265ea1214068060f595c4e Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 5 Jul 2024 16:44:41 +0000 Subject: [PATCH 178/288] 8335730: JFR: Clean up jdk.jfr Reviewed-by: mgronlun --- .../share/classes/jdk/jfr/consumer/RecordedClass.java | 4 ++-- .../share/classes/jdk/jfr/consumer/RecordedFrame.java | 6 +++--- .../share/classes/jdk/jfr/consumer/RecordedMethod.java | 4 ++-- .../share/classes/jdk/jfr/consumer/RecordedObject.java | 5 ++++- .../share/classes/jdk/jfr/consumer/RecordedThread.java | 6 +++--- .../jdk/jfr/events/AbstractBufferStatisticsEvent.java | 4 ++-- .../classes/jdk/jfr/events/ActiveRecordingEvent.java | 1 - .../share/classes/jdk/jfr/events/ActiveSettingEvent.java | 1 - .../classes/jdk/jfr/events/ExceptionStatisticsEvent.java | 1 - .../share/classes/jdk/jfr/internal/EventControl.java | 1 - .../classes/jdk/jfr/internal/MetadataRepository.java | 2 -- .../share/classes/jdk/jfr/internal/OldObjectSample.java | 3 +-- .../share/classes/jdk/jfr/internal/RepositoryChunk.java | 5 +---- .../share/classes/jdk/jfr/internal/ShutdownHook.java | 2 -- .../classes/jdk/jfr/internal/dcmd/QueryRecording.java | 7 +------ src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java | 4 ++-- .../classes/jdk/jfr/internal/jfc/model/XmlSetting.java | 4 ++-- src/jdk.jfr/share/classes/jdk/jfr/internal/query/Row.java | 4 ++-- .../share/classes/jdk/jfr/internal/query/TableSorter.java | 5 +---- .../classes/jdk/jfr/internal/settings/LevelSetting.java | 4 ++-- .../share/classes/jdk/jfr/internal/tool/Disassemble.java | 8 ++++---- .../share/classes/jdk/jfr/internal/tool/PrettyWriter.java | 3 +-- src/jdk.jfr/share/classes/jdk/jfr/internal/tool/View.java | 3 +-- .../share/classes/jdk/jfr/internal/util/ValueParser.java | 4 ++-- 24 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClass.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClass.java index 8d6b5647f2f58..d0ae1e7d297e1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClass.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ public final class RecordedClass extends RecordedObject { * @see java.lang.reflect.Modifier */ public int getModifiers() { - return getTyped("modifiers", Integer.class, -1); + return getTyped("modifiers", Integer.class, INTEGER_MINUS_ONE); } /** diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedFrame.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedFrame.java index 9640330fca2fc..cdb893274acd0 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedFrame.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public boolean isJavaFrame() { * @return byte code index, or {@code -1} if doesn't exist */ public int getBytecodeIndex() { - return getTyped("bytecodeIndex", Integer.class, Integer.valueOf(-1)); + return getTyped("bytecodeIndex", Integer.class, INTEGER_MINUS_ONE); } /** @@ -75,7 +75,7 @@ public int getBytecodeIndex() { * @return the line number, or {@code -1} if doesn't exist */ public int getLineNumber() { - return getTyped("lineNumber", Integer.class, Integer.valueOf(-1)); + return getTyped("lineNumber", Integer.class, INTEGER_MINUS_ONE); } /** diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java index a82b43ffc363b..6c8f23aa02a86 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,7 +94,7 @@ public String getDescriptor() { * @see RecordedFrame#isJavaFrame */ public int getModifiers() { - return getTyped("modifiers", Integer.class, Integer.valueOf(0)); + return getTyped("modifiers", Integer.class, INTEGER_ZERO); } /** diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java index e5825b8ea07c5..21bd30a8248d1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -154,6 +154,9 @@ public MetadataEvent newMetadataEvent(List previous, List private static final record UnsignedValue(Object value) { } + static final Integer INTEGER_MINUS_ONE = Integer.valueOf(-1); + static final Integer INTEGER_ZERO = Integer.valueOf(0); + static final Long LONG_MINUS_ONE = Long.valueOf(-1L); final Object[] objects; final ObjectContext objectContext; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThread.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThread.java index 4031e70d24b56..d12d65faf10ea 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThread.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public long getOSThreadId() { if (isVirtual()) { return -1L; } - Long l = getTyped("osThreadId", Long.class, -1L); + Long l = getTyped("osThreadId", Long.class, LONG_MINUS_ONE); return l.longValue(); } @@ -92,7 +92,7 @@ public String getJavaName() { * @see java.lang.Thread#threadId() */ public long getJavaThreadId() { - Long l = getTyped("javaThreadId", Long.class, -1L); + Long l = getTyped("javaThreadId", Long.class, LONG_MINUS_ONE); long id = l.longValue(); return id == 0 ? -1L : id; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/AbstractBufferStatisticsEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/AbstractBufferStatisticsEvent.java index d436b32db83e3..f7a03c7446e84 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/AbstractBufferStatisticsEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/AbstractBufferStatisticsEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import jdk.jfr.*; @Category({ "Java Application", "Statistics" }) -public abstract class AbstractBufferStatisticsEvent extends AbstractPeriodicEvent { +abstract class AbstractBufferStatisticsEvent extends AbstractPeriodicEvent { protected AbstractBufferStatisticsEvent(BufferPool bufferPool) { count = bufferPool.getCount(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java index 352a8b6a07397..ffb45caa42cf9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveRecordingEvent.java @@ -29,7 +29,6 @@ import jdk.jfr.Label; import jdk.jfr.DataAmount; import jdk.jfr.Name; -import jdk.jfr.StackTrace; import jdk.jfr.Timespan; import jdk.jfr.Timestamp; import jdk.jfr.internal.RemoveFields; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveSettingEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveSettingEvent.java index 3658b06eb14a8..6aade8e01f5d5 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveSettingEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ActiveSettingEvent.java @@ -28,7 +28,6 @@ import jdk.jfr.Category; import jdk.jfr.Label; import jdk.jfr.Name; -import jdk.jfr.StackTrace; import jdk.jfr.internal.RemoveFields; import jdk.jfr.internal.Type; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionStatisticsEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionStatisticsEvent.java index 795f618b4e62a..0cdd987227193 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionStatisticsEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionStatisticsEvent.java @@ -29,7 +29,6 @@ import jdk.jfr.Description; import jdk.jfr.Label; import jdk.jfr.Name; -import jdk.jfr.StackTrace; import jdk.jfr.internal.MirrorEvent; import jdk.jfr.internal.RemoveFields; import jdk.jfr.internal.Type; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java index 2a758aa8addc6..71569c30273be 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java @@ -46,7 +46,6 @@ import jdk.jfr.Threshold; import jdk.jfr.events.ActiveSettingEvent; import jdk.jfr.events.StackFilter; -import jdk.jfr.internal.JVM; import jdk.jfr.internal.settings.CutoffSetting; import jdk.jfr.internal.settings.EnabledSetting; import jdk.jfr.internal.settings.LevelSetting; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 75be70a0d1dae..4a7bc734d7571 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -44,8 +44,6 @@ import jdk.jfr.EventType; import jdk.jfr.Name; import jdk.jfr.Period; -import jdk.jfr.StackTrace; -import jdk.jfr.Threshold; import jdk.jfr.ValueDescriptor; import jdk.jfr.internal.consumer.RepositoryFiles; import jdk.jfr.internal.event.EventConfiguration; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java index 5fa9eb709ef08..21079fab3a912 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import jdk.jfr.RecordingState; import jdk.jfr.internal.settings.CutoffSetting; import jdk.jfr.internal.test.WhiteBox; -import jdk.jfr.internal.util.Utils; // The Old Object event could have been implemented as a periodic event, but // due to chunk rotations and how settings are calculated when multiple recordings diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java index 72d3a719452f4..e46b6020d5dbd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RepositoryChunk.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,10 +29,7 @@ import java.io.RandomAccessFile; import java.nio.channels.ReadableByteChannel; import java.time.Instant; -import java.time.Period; -import java.time.Duration; import java.util.Comparator; -import java.util.Optional; import jdk.jfr.internal.SecuritySupport.SafePath; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java index afd9ec09bd9f1..8375dab0bcce3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ShutdownHook.java @@ -25,14 +25,12 @@ package jdk.jfr.internal; -import java.io.IOException; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import jdk.jfr.RecordingState; -import jdk.jfr.internal.util.Utils; /** * Class responsible for dumping recordings on exit diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/QueryRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/QueryRecording.java index 75fefca0f08af..fa60079b52247 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/QueryRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/QueryRecording.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +27,6 @@ import java.io.IOException; import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; import java.util.List; import java.util.ListIterator; @@ -37,12 +36,8 @@ import jdk.jfr.internal.PrivateAccess; import jdk.jfr.internal.RepositoryChunk; import jdk.jfr.internal.query.Configuration; -import jdk.jfr.internal.query.QueryPrinter; -import jdk.jfr.internal.query.ViewPrinter; import jdk.jfr.internal.query.Configuration.Truncate; import jdk.jfr.internal.util.UserDataException; -import jdk.jfr.internal.util.UserSyntaxException; -import jdk.jfr.internal.util.Output; /** * Helper class that holds recording chunks alive during a query. It also helps diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java index 6d7cccfb2a6d0..0511ce57001c6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,7 +293,7 @@ public static Reader newReader(SafePath sf) throws IOException { public static String formatException(String prefix, Exception e, String input) { String message = prefix + " " + JFC.exceptionToVerb(e) + " file '" + input + "'"; String details = e.getMessage(); - if (e instanceof JFCModelException m) { + if (e instanceof JFCModelException) { return message + ". " + details; } if (e instanceof ParseException && !details.isEmpty()) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSetting.java index 56f2208ded313..536c5051f54e1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/XmlSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public void onChange() { @Override final void setContent(String value) { super.setContent(value); - if (getParent() instanceof XmlEvent event) { + if (getParent() instanceof XmlEvent) { SettingsLog.log(this, value); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Row.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Row.java index da32f86c171ba..cb54b6b651abd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Row.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Row.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,6 @@ public void putText(int index, String text) { @Override public String toString() { - return Arrays.asList(values).toString(); + return Arrays.toString(values); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java index 65f664018bab2..8869516280960 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableSorter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,10 +24,7 @@ */ package jdk.jfr.internal.query; -import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; -import java.util.List; import java.util.function.Predicate; import jdk.jfr.internal.query.Query.OrderElement; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java index acf67c0aa06a5..b6aa7500d4b68 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ @MetadataDefinition @Label("Level") @Name(Type.SETTINGS_PREFIX + "Level") -public class LevelSetting extends JDKSettingControl { +public final class LevelSetting extends JDKSettingControl { private final PlatformEventType eventType; private final List levels; private String value; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java index 06616771cf9cf..48dd52475685a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -223,9 +223,9 @@ private void splitFile(Path directory, Path file, List splitPositions) thr Path p = directory.resolve(formattedFilename); File splittedFile = p.toFile(); println("Writing " + splittedFile + " ... " + bytes.length); - FileOutputStream fos = new FileOutputStream(splittedFile); - fos.write(bytes); - fos.close(); + try (var fos = new FileOutputStream(splittedFile)) { + fos.write(bytes); + } } } catch (IOException ioe) { throw new UserDataException("i/o error writing file " + file); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java index aec1f18546c77..77b3f4d1e8c41 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.util.ArrayList; import java.util.List; import java.util.StringJoiner; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/View.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/View.java index a22c64c931e8f..613e315ff1390 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/View.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/View.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.util.List; import jdk.jfr.consumer.EventStream; -import jdk.jfr.internal.util.Columnizer; import jdk.jfr.internal.query.ViewPrinter; import jdk.jfr.internal.query.Configuration; import jdk.jfr.internal.query.Configuration.Truncate; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java index 1c6561f45c4a6..730c83daaae67 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +31,7 @@ import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; -public class ValueParser { +public final class ValueParser { private static final String INFINITY = "infinity"; public static long parseTimespanWithInfinity(String s) { From b83766e59063a41ea8801ac9e7c15dce67727c62 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 5 Jul 2024 17:07:22 +0000 Subject: [PATCH 179/288] 8335632: jdk/jfr/api/consumer/streaming/TestJVMExit.java failed with "Process [...] is no longer alive" Reviewed-by: mgronlun --- .../jfr/api/consumer/streaming/TestJVMExit.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java index 5b30a52e4b757..77eba735d7a3b 100644 --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestJVMExit.java @@ -34,12 +34,29 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @modules jdk.jfr jdk.attach java.base/jdk.internal.misc + * @build jdk.jfr.api.consumer.streaming.TestProcess * * @run main/othervm -Dsun.tools.attach.attachTimeout=100000 jdk.jfr.api.consumer.streaming.TestJVMExit */ public class TestJVMExit { public static void main(String... args) throws Exception { + while (true) { + try { + testExit(); + return; + } catch (RuntimeException e) { + String message = String.valueOf(e.getMessage()); + // If the test application crashes during startup, retry. + if (!message.contains("is no longer alive")) { + throw e; + } + System.out.println("Application not alive when trying to get repository. Retrying."); + } + } + } + + private static void testExit() throws Exception { try (TestProcess process = new TestProcess("exit-application")) { AtomicInteger eventCounter = new AtomicInteger(); try (EventStream es = EventStream.openRepository(process.getRepository())) { From 6f7f0f1de05fdc0f6a88ccd90b806e8a5c5074ef Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Sat, 6 Jul 2024 15:05:26 +0000 Subject: [PATCH 180/288] 8333884: MemorySegment::reinterpret removes read-only property Reviewed-by: jvernee, mcimadamore --- .../java/lang/foreign/MemorySegment.java | 21 +++++++++++++++++++ .../foreign/AbstractMemorySegmentImpl.java | 2 +- .../internal/foreign/SegmentFactories.java | 10 ++++++--- test/jdk/java/foreign/TestSegments.java | 12 +++++++---- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index aa1f1762aec65..83a8b09f9d453 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -633,6 +633,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * asSlice(offset, newSize, 1); * } *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -652,6 +655,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * alignment constraint. The returned segment's address is the address of this * segment plus the given offset; its size is specified by the given argument. *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -679,6 +685,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * asSlice(offset, layout.byteSize(), layout.byteAlignment()); * } *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -705,6 +714,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * asSlice(offset, byteSize() - offset); * } *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -721,6 +733,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * Returns a new memory segment that has the same address and scope as this segment, * but with the provided size. *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -759,6 +774,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * scope, and is accessible from any thread. The size of the segment accepted by the * cleanup action is {@link #byteSize()}. *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -807,6 +825,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * scope, and is accessible from any thread. The size of the segment accepted by the * cleanup action is {@code newSize}. *

    + * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

    * The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index f9f6ac2022a2b..325dbe1093f25 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -159,7 +159,7 @@ public MemorySegment reinterpretInternal(Class callerClass, long newSize, Sco () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) : null; return SegmentFactories.makeNativeSegmentUnchecked(address(), newSize, - (MemorySessionImpl)scope, action); + (MemorySessionImpl)scope, readOnly, action); } private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 17f141b4e8c64..133631e2aa4d8 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * 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,14 +57,18 @@ public class SegmentFactories { // associated with MemorySegment::ofAddress. @ForceInline - public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl, Runnable action) { + public static MemorySegment makeNativeSegmentUnchecked(long min, + long byteSize, + MemorySessionImpl sessionImpl, + boolean readOnly, + Runnable action) { ensureInitialized(); if (action == null) { sessionImpl.checkValidState(); } else { sessionImpl.addCloseAction(action); } - return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl); + return new NativeMemorySegmentImpl(min, byteSize, readOnly, sessionImpl); } @ForceInline diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 44ecd12ba5ebd..b361abac3dfa4 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ import java.util.function.Supplier; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.*; public class TestSegments { @@ -383,9 +382,14 @@ void testReinterpret() { assertEquals(MemorySegment.ofAddress(42).reinterpret(100, Arena.ofAuto(), null).byteSize(), 100); // check scope and cleanup assertEquals(MemorySegment.ofAddress(42).reinterpret(100, arena, s -> counter.incrementAndGet()).scope(), arena.scope()); - assertEquals(MemorySegment.ofAddress(42).reinterpret(arena, s -> counter.incrementAndGet()).scope(), arena.scope()); + assertEquals(MemorySegment.ofAddress(42).reinterpret(arena, _ -> counter.incrementAndGet()).scope(), arena.scope()); + // check read-only state + assertFalse(MemorySegment.ofAddress(42).reinterpret(100).isReadOnly()); + assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(100).isReadOnly()); + assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(100, Arena.ofAuto(), null).isReadOnly()); + assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(arena, _ -> counter.incrementAndGet()).isReadOnly()); } - assertEquals(counter.get(), 2); + assertEquals(counter.get(), 3); } @Test From 3f37c5718d676b7001e6a084aed3ba645745a144 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 8 Jul 2024 01:19:36 +0000 Subject: [PATCH 181/288] 8335806: RISC-V: Corrected typos Bizarrely Reviewed-by: aph, amitkumar --- src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 2 +- src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 7e3ceb1f02029..251ea3813ff84 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -1154,7 +1154,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("string_compare {"); - // Bizzarely, the counts are passed in bytes, regardless of whether they + // Bizarrely, the counts are passed in bytes, regardless of whether they // are L or U strings, however the result is always in characters. if (!str1_isL) asrw(cnt1, cnt1, 1); if (!str2_isL) asrw(cnt2, cnt2, 1); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 887baa4a506d1..3cb2e52c8cb93 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1322,7 +1322,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("string_compare {"); - // Bizzarely, the counts are passed in bytes, regardless of whether they + // Bizarrely, the counts are passed in bytes, regardless of whether they // are L or U strings, however the result is always in characters. if (!str1_isL) { sraiw(cnt1, cnt1, 1); From 02956ab6e161ca8556a73f328f79bcbfba997cbc Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 8 Jul 2024 06:23:03 +0000 Subject: [PATCH 182/288] 8332163: C2 SuperWord: refactor PacksetGraph and SuperWord::output into VTransformGraph Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/superword.cpp | 816 +++--------------- src/hotspot/share/opto/superword.hpp | 18 +- .../share/opto/superwordVTransformBuilder.cpp | 308 +++++++ .../share/opto/superwordVTransformBuilder.hpp | 87 ++ .../share/opto/traceAutoVectorizationTag.hpp | 1 + src/hotspot/share/opto/vectorization.cpp | 1 - src/hotspot/share/opto/vectorization.hpp | 16 +- src/hotspot/share/opto/vtransform.cpp | 450 ++++++++++ src/hotspot/share/opto/vtransform.hpp | 515 +++++++++++ 9 files changed, 1489 insertions(+), 723 deletions(-) create mode 100644 src/hotspot/share/opto/superwordVTransformBuilder.cpp create mode 100644 src/hotspot/share/opto/superwordVTransformBuilder.hpp create mode 100644 src/hotspot/share/opto/vtransform.cpp create mode 100644 src/hotspot/share/opto/vtransform.hpp diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index f78a9b63926fd..ba2dd423bf51d 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -22,22 +22,13 @@ */ #include "precompiled.hpp" -#include "libadt/vectset.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" #include "opto/addnode.hpp" -#include "opto/c2compiler.hpp" #include "opto/castnode.hpp" #include "opto/convertnode.hpp" -#include "opto/matcher.hpp" -#include "opto/memnode.hpp" -#include "opto/opcodes.hpp" -#include "opto/opaquenode.hpp" -#include "opto/rootnode.hpp" #include "opto/superword.hpp" +#include "opto/superwordVTransformBuilder.hpp" #include "opto/vectornode.hpp" #include "opto/movenode.hpp" -#include "utilities/powerOfTwo.hpp" SuperWord::SuperWord(const VLoopAnalyzer &vloop_analyzer) : _vloop_analyzer(vloop_analyzer), @@ -707,7 +698,7 @@ bool SuperWord::can_pack_into_pair(Node* s1, Node* s2) { } // Forbid anything that looks like a PopulateIndex to be packed. It does not need to be packed, - // and will still be vectorized by SuperWord::vector_opd. + // and will still be vectorized by SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index. if (isomorphic(s1, s2) && !is_populate_index(s1, s2)) { if ((independent(s1, s2) && have_similar_inputs(s1, s2)) || reduction(s1, s2)) { if (!_pairset.is_left(s1) && !_pairset.is_right(s2)) { @@ -769,8 +760,9 @@ bool SuperWord::isomorphic(Node* s1, Node* s2) { } } -// Look for pattern n1 = (iv + c) and n2 = (iv + c + 1), which may lead to PopulateIndex vector node. -// We skip the pack creation of these nodes. They will be vectorized by SuperWord::vector_opd. +// Look for pattern n1 = (iv + c) and n2 = (iv + c + 1), which may lead to +// PopulateIndex vector node. We skip the pack creation of these nodes. They +// will be vectorized by SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index. bool SuperWord::is_populate_index(const Node* n1, const Node* n2) const { return n1->is_Add() && n2->is_Add() && @@ -1858,307 +1850,74 @@ void PackSet::verify() const { } #endif -// The PacksetGraph combines the dependency graph with the packset. In the PackSet -// graph, we have two kinds of nodes: -// (1) pack-node: Represents all nodes of some pack p in a single node, which -// shall later become a vector node. -// (2) scalar-node: Represents a node that is not in any pack. -// For any edge (n1, n2) in the dependency graph, we add an edge to the PacksetGraph for -// the PacksetGraph nodes corresponding to n1 and n2. -// We work from the dependency graph, because it gives us all the data-dependencies, -// as well as more refined memory-dependencies than the C2 graph. The dependency graph -// does not have cycles. But packing nodes can introduce cyclic dependencies. Example: -// -// +--------+ -// A -> X | v -// Pack [A,B] and [X,Y] [A,B] [X,Y] -// Y -> B ^ | -// +--------+ -// -class PacksetGraph { -private: - // pid: packset graph node id. - GrowableArray _pid; // bb_idx(n) -> pid - GrowableArray _pid_to_node; // one node per pid, find rest via _packset.pack - GrowableArray> _out; // out-edges - GrowableArray _incnt; // number of (implicit) in-edges - int _max_pid = 0; - - bool _schedule_success; - - SuperWord* _slp; -public: - PacksetGraph(SuperWord* slp) - : _pid(8, 0, /* default */ 0), _slp(slp) { - } - // Get pid, if there is a packset node that n belongs to. Else return 0. - int get_pid_or_zero(const Node* n) const { - if (!_slp->in_bb(n)) { - return 0; - } - int idx = _slp->bb_idx(n); - if (idx >= _pid.length()) { - return 0; - } else { - return _pid.at(idx); - } - } - int get_pid(const Node* n) { - int poz = get_pid_or_zero(n); - assert(poz != 0, "pid should not be zero"); - return poz; - } - void set_pid(Node* n, int pid) { - assert(n != nullptr && pid > 0, "sane inputs"); - assert(_slp->in_bb(n), "must be"); - int idx = _slp->bb_idx(n); - _pid.at_put_grow(idx, pid); - _pid_to_node.at_put_grow(pid - 1, n, nullptr); - } - Node* get_node(int pid) { - assert(pid > 0 && pid <= _pid_to_node.length(), "pid must be mapped"); - Node* n = _pid_to_node.at(pid - 1); - assert(n != nullptr, "sanity"); - return n; - } - int new_pid() { - _incnt.push(0); - _out.push(GrowableArray()); - return ++_max_pid; - } - int incnt(int pid) { return _incnt.at(pid - 1); } - void incnt_set(int pid, int cnt) { return _incnt.at_put(pid - 1, cnt); } - GrowableArray& out(int pid) { return _out.at(pid - 1); } - bool schedule_success() const { return _schedule_success; } - - // Create nodes (from packs and scalar-nodes), and add edges, based on the dependency graph. - void build() { - const PackSet& packset = _slp->packset(); - const GrowableArray& body = _slp->body(); - // Map nodes in packsets - for (int i = 0; i < packset.length(); i++) { - Node_List* p = packset.at(i); - int pid = new_pid(); - for (uint k = 0; k < p->size(); k++) { - Node* n = p->at(k); - set_pid(n, pid); - assert(packset.get_pack(n) == p, "matching packset"); - } - } - - int max_pid_packset = _max_pid; - - // Map nodes not in packset - for (int i = 0; i < body.length(); i++) { - Node* n = body.at(i); - if (n->is_Phi() || n->is_CFG()) { - continue; // ignore control flow - } - int pid = get_pid_or_zero(n); - if (pid == 0) { - pid = new_pid(); - set_pid(n, pid); - assert(packset.get_pack(n) == nullptr, "no packset"); - } - } - - // Map edges for packset nodes - VectorSet set; - for (int i = 0; i < packset.length(); i++) { - Node_List* p = packset.at(i); - set.clear(); - int pid = get_pid(p->at(0)); - for (uint k = 0; k < p->size(); k++) { - Node* n = p->at(k); - assert(pid == get_pid(n), "all nodes in pack have same pid"); - for (VLoopDependencyGraph::PredsIterator preds(_slp->dependency_graph(), n); !preds.done(); preds.next()) { - Node* pred = preds.current(); - int pred_pid = get_pid_or_zero(pred); - if (pred_pid == pid && _slp->is_marked_reduction(n)) { - continue; // reduction -> self-cycle is not a cyclic dependency - } - // Only add edges once, and only for mapped nodes (in body) - if (pred_pid > 0 && !set.test_set(pred_pid)) { - incnt_set(pid, incnt(pid) + 1); // increment - out(pred_pid).push(pid); - } - } - } - } - - // Map edges for nodes not in packset - for (int i = 0; i < body.length(); i++) { - Node* n = body.at(i); - int pid = get_pid_or_zero(n); // zero for Phi or CFG - if (pid <= max_pid_packset) { - continue; // Only scalar-nodes - } - for (VLoopDependencyGraph::PredsIterator preds(_slp->dependency_graph(), n); !preds.done(); preds.next()) { - Node* pred = preds.current(); - int pred_pid = get_pid_or_zero(pred); - // Only add edges for mapped nodes (in body) - if (pred_pid > 0) { - incnt_set(pid, incnt(pid) + 1); // increment - out(pred_pid).push(pid); - } - } - } - } - - // Schedule nodes of PacksetGraph to worklist, using topsort: schedule a node - // that has zero incnt. If a PacksetGraph node corresponds to memops, then add - // those to the memops_schedule. At the end, we return the memops_schedule, and - // note if topsort was successful. - Node_List schedule() { - Node_List memops_schedule; - GrowableArray worklist; - // Directly schedule all nodes without precedence - for (int pid = 1; pid <= _max_pid; pid++) { - if (incnt(pid) == 0) { - worklist.push(pid); - } - } - // Continue scheduling via topological sort - for (int i = 0; i < worklist.length(); i++) { - int pid = worklist.at(i); - - // Add memops to memops_schedule - Node* n = get_node(pid); - Node_List* p = _slp->packset().get_pack(n); - if (n->is_Mem()) { - if (p == nullptr) { - memops_schedule.push(n); - } else { - for (uint k = 0; k < p->size(); k++) { - memops_schedule.push(p->at(k)); - assert(p->at(k)->is_Mem(), "only schedule memops"); - } - } - } +bool SuperWord::schedule_and_apply() const { + if (_packset.is_empty()) { return false; } - // Decrement incnt for all successors - for (int j = 0; j < out(pid).length(); j++){ - int pid_use = out(pid).at(j); - int incnt_use = incnt(pid_use) - 1; - incnt_set(pid_use, incnt_use); - // Did use lose its last input? - if (incnt_use == 0) { - worklist.push(pid_use); - } - } - } - - // Was every pid scheduled? If not, we found some cycles in the PacksetGraph. - _schedule_success = (worklist.length() == _max_pid); - return memops_schedule; - } - - // Print the PacksetGraph. - // print_nodes = true: print all C2 nodes beloning to PacksetGrahp node. - // print_zero_incnt = false: do not print nodes that have no in-edges (any more). - void print(bool print_nodes, bool print_zero_incnt) { - const GrowableArray &body = _slp->body(); - tty->print_cr("PacksetGraph"); - for (int pid = 1; pid <= _max_pid; pid++) { - if (incnt(pid) == 0 && !print_zero_incnt) { - continue; - } - tty->print("Node %d. incnt %d [", pid, incnt(pid)); - for (int j = 0; j < out(pid).length(); j++) { - tty->print("%d ", out(pid).at(j)); - } - tty->print_cr("]"); + // Make an empty transform. #ifndef PRODUCT - if (print_nodes) { - for (int i = 0; i < body.length(); i++) { - Node* n = body.at(i); - if (get_pid_or_zero(n) == pid) { - tty->print(" "); - n->dump(); - } - } - } + VTransformTrace trace(_vloop.vtrace(), + is_trace_superword_rejections(), + is_trace_align_vector(), + is_trace_superword_info()); #endif - } - } -}; - -// We want to replace the packed scalars from the PackSet and replace them -// with vector operations. This requires scheduling and re-ordering the memory -// graph. We take these steps: -// (1) Build the PacksetGraph. It combines the dependency graph with the -// packset. The PacksetGraph gives us the dependencies that must be -// respected after scheduling. -// (2) Schedule the PacksetGraph to the memops_schedule, which represents -// a linear order of all memops in the body. The order respects the -// dependencies of the PacksetGraph. -// (3) If the PacksetGraph has cycles, we cannot schedule. Abort. -// (4) Apply the vectorization, including re-ordering the memops and replacing -// packed scalars with vector operations. -bool SuperWord::schedule_and_apply() { - if (_packset.is_empty()) { - return false; - } - ResourceMark rm; + VTransform vtransform(_vloop_analyzer, + _mem_ref_for_main_loop_alignment, + _aw_for_main_loop_alignment + NOT_PRODUCT(COMMA trace) + ); - // (1) Build the PacksetGraph. - PacksetGraph graph(this); - graph.build(); + // Build the transform from the packset. + { + ResourceMark rm; + SuperWordVTransformBuilder builder(_packset, vtransform); + } - // (2) Schedule the PacksetGraph. - Node_List memops_schedule = graph.schedule(); + if (!vtransform.schedule()) { return false; } + vtransform.apply(); + return true; +} - // (3) Check if the PacksetGraph schedule succeeded (had no cycles). - // We now know that we only have independent packs, see verify_packs. - // This is a necessary but not a sufficient condition for an acyclic - // graph (DAG) after scheduling. Thus, we must check if the packs have - // introduced a cycle. The SuperWord paper mentions the need for this - // in "3.7 Scheduling". - if (!graph.schedule_success()) { +// Apply the vectorization, i.e. we irreversibly edit the C2 graph. At this point, all +// correctness and profitability checks have passed, and the graph was successfully scheduled. +void VTransform::apply() { #ifndef PRODUCT - if (is_trace_superword_rejections()) { - tty->print_cr("SuperWord::schedule found cycle in PacksetGraph:"); - graph.print(true, false); - tty->print_cr("removing all packs from packset."); - } -#endif - _packset.clear(); - return false; + if (_trace._info || TraceLoopOpts) { + tty->print_cr("\nVTransform::apply:"); + lpt()->dump_head(); + lpt()->head()->dump(); } + assert(cl()->is_main_loop(), "auto vectorization only for main loops"); + assert(_graph.is_scheduled(), "must already be scheduled"); +#endif - // (4) Apply the vectorization, including re-ordering the memops. - return apply(memops_schedule); -} - -bool SuperWord::apply(Node_List& memops_schedule) { Compile* C = phase()->C; - CountedLoopNode* cl = lpt()->_head->as_CountedLoop(); - C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl); + C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl()); - apply_memops_reordering_with_schedule(memops_schedule); - C->print_method(PHASE_AUTO_VECTORIZATION2_AFTER_REORDER, 4, cl); + _graph.apply_memops_reordering_with_schedule(); + C->print_method(PHASE_AUTO_VECTORIZATION2_AFTER_REORDER, 4, cl()); adjust_pre_loop_limit_to_align_main_loop_vectors(); - C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl); - - bool is_success = apply_vectorization(); - C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_APPLY, 4, cl); + C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); - return is_success; + apply_vectorization(); + C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_APPLY, 4, cl()); } -// Reorder the memory graph for all slices in parallel. We walk over the schedule once, -// and track the current memory state of each slice. -void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule) { +// We prepare the memory graph for the replacement of scalar memops with vector memops. +// We reorder all slices in parallel, ensuring that the memops inside each slice are +// ordered according to the _schedule. This means that all packed memops are consecutive +// in the memory graph after the reordering. +void VTransformGraph::apply_memops_reordering_with_schedule() const { #ifndef PRODUCT - if (is_trace_superword_info()) { - tty->print_cr("\nSuperWord::apply_memops_reordering_with_schedule:"); - memops_schedule.dump(); + assert(is_scheduled(), "must be already scheduled"); + if (_trace._info) { + print_memops_schedule(); } #endif + ResourceMark rm; int max_slices = phase()->C->num_alias_types(); - // When iterating over the memops_schedule, we keep track of the current memory state, + // When iterating over the schedule, we keep track of the current memory state, // which is the Phi or a store in the loop. GrowableArray current_state_in_slice(max_slices, max_slices, nullptr); // The memory state after the loop is the last store inside the loop. If we reorder the @@ -2179,10 +1938,9 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule old_last_store_in_slice.at_put(alias_idx, last_store); } - // (2) Walk over memops_schedule, append memops to the current state + // (2) Walk over schedule, append memops to the current state // of that slice. If it is a Store, we take it as the new state. - for (uint i = 0; i < memops_schedule.size(); i++) { - MemNode* n = memops_schedule.at(i)->as_Mem(); + for_each_memop_in_schedule([&] (MemNode* n) { assert(n->is_Load() || n->is_Store(), "only loads or stores"); int alias_idx = phase()->C->get_alias_index(n->adr_type()); Node* current_state = current_state_in_slice.at(alias_idx); @@ -2198,12 +1956,12 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule current_state_in_slice.at_put(alias_idx, n); } } - } + }); // (3) For each slice, we add the current state to the backedge // in the Phi. Further, we replace uses of the old last store // with uses of the new last store (current_state). - Node_List uses_after_loop; + GrowableArray uses_after_loop; for (int i = 0; i < mem_slice_head.length(); i++) { Node* phi = mem_slice_head.at(i); int alias_idx = phase()->C->get_alias_index(phi->adr_type()); @@ -2225,7 +1983,7 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule uses_after_loop.push(use); } } - for (uint k = 0; k < uses_after_loop.size(); k++) { + for (int k = 0; k < uses_after_loop.length(); k++) { Node* use = uses_after_loop.at(k); for (uint j = 0; j < use->req(); j++) { Node* def = use->in(j); @@ -2237,396 +1995,65 @@ void SuperWord::apply_memops_reordering_with_schedule(Node_List& memops_schedule } } -// Convert packs into vector node operations -// At this point, all correctness and profitability checks have passed. -// We start the irreversible process of editing the C2 graph. Should -// there be an unexpected situation (assert fails), then we can only -// bail out of the compilation, as the graph has already been partially -// modified. We bail out, and retry without SuperWord. -bool SuperWord::apply_vectorization() { - CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); - assert(cl->is_main_loop(), "SLP should only work on main loops"); - Compile* C = phase()->C; - assert(!_packset.is_empty(), "vectorization requires non-empty packset"); - -#ifndef PRODUCT - if (TraceLoopOpts) { - tty->print("SuperWord::apply_vectorization "); - lpt()->dump_head(); - } -#endif - - uint max_vlen_in_bytes = 0; - uint max_vlen = 0; - - for (int i = 0; i < body().length(); i++) { - Node* n = body().at(i); - Node_List* p = get_pack(n); - if (p != nullptr && n == p->at(p->size()-1)) { - // After apply_memops_reordering_with_schedule, we know that the memops have the same order in the pack - // as in the memory slice. Hence, "first" is the first memop in the slice from the pack, - // and "n" is the last node in the slice from the pack. - Node* first = p->at(0); - uint vlen = p->size(); - uint vlen_in_bytes = 0; - Node* vn = nullptr; - int opc = n->Opcode(); - if (n->is_Load()) { - Node* ctl = n->in(MemNode::Control); - Node* mem = first->in(MemNode::Memory); - // Set the memory dependency of the LoadVector as early as possible. - // Walk up the memory chain, and ignore any StoreVector that provably - // does not have any memory dependency. - while (mem->is_StoreVector()) { - VPointer p_store(mem->as_Mem(), _vloop); - if (p_store.overlap_possible_with_any_in(p)) { - break; - } else { - mem = mem->in(MemNode::Memory); - } - } - Node* adr = first->in(MemNode::Address); - const TypePtr* atyp = n->adr_type(); - vn = LoadVectorNode::make(opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n), control_dependency(p)); - vlen_in_bytes = vn->as_LoadVector()->memory_size(); - } else if (n->is_Store()) { - // Promote value to be stored to vector - Node* val = vector_opd(p, MemNode::ValueIn); - if (val == nullptr) { - assert(false, "input to vector store was not created"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } +void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const { + ResourceMark rm; + // We keep track of the resulting Nodes from every "VTransformNode::apply" call. + // Since "apply" is called on defs before uses, this allows us to find the + // generated def (input) nodes when we are generating the use nodes in "apply". + int length = _vtnodes.length(); + GrowableArray vtnode_idx_to_transformed_node(length, length, nullptr); - Node* ctl = n->in(MemNode::Control); - Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - const TypePtr* atyp = n->adr_type(); - vn = StoreVectorNode::make(opc, ctl, mem, adr, atyp, val, vlen); - vlen_in_bytes = vn->as_StoreVector()->memory_size(); - } else if (VectorNode::is_scalar_rotate(n)) { - Node* in1 = vector_opd(p, 1); - Node* in2 = first->in(2); - // If rotation count is non-constant or greater than 8bit value create a vector. - if (!in2->is_Con() || !Matcher::supports_vector_constant_rotates(in2->get_int())) { - in2 = vector_opd(p, 2); - } - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_roundopD(n)) { - Node* in1 = vector_opd(p, 1); - Node* in2 = first->in(2); - assert(in2->is_Con(), "Constant rounding mode expected."); - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_muladds2i(n)) { - assert(n->req() == 5u, "MulAddS2I should have 4 operands."); - Node* in1 = vector_opd(p, 1); - Node* in2 = vector_opd(p, 2); - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (opc == Op_SignumF || opc == Op_SignumD) { - assert(n->req() == 4, "four inputs expected"); - Node* in = vector_opd(p, 1); - Node* zero = vector_opd(p, 2); - Node* one = vector_opd(p, 3); - vn = VectorNode::make(opc, in, zero, one, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (n->is_Cmp()) { - // Bool + Cmp + CMove -> VectorMaskCmp + VectorBlend - continue; - } else if (n->is_Bool()) { - // Bool + Cmp + CMove -> VectorMaskCmp + VectorBlend - continue; - } else if (n->is_CMove()) { - // Bool + Cmp + CMove -> VectorMaskCmp + VectorBlend - - BoolNode* bol = n->in(1)->as_Bool(); - assert(bol != nullptr, "must have Bool above CMove"); - Node_List* bool_pack = get_pack(bol); - assert(bool_pack != nullptr, "CMove must have matching Bool pack"); - - CmpNode* cmp = bol->in(1)->as_Cmp(); - assert(cmp != nullptr, "must have cmp above CMove"); - Node_List* cmp_pack = get_pack(cmp); - assert(cmp_pack != nullptr, "Bool must have matching Cmp pack"); - - Node* cmp_in1 = vector_opd(cmp_pack, 1); - Node* cmp_in2 = vector_opd(cmp_pack, 2); - - Node* blend_in1 = vector_opd(p, 2); - Node* blend_in2 = vector_opd(p, 3); - - VTransformBoolTest bool_test = _packset.get_bool_test(bool_pack); - BoolTest::mask test_mask = bool_test._mask; - if (bool_test._is_negated) { - // We can cancel out the negation by swapping the blend inputs. - swap(blend_in1, blend_in2); - } + for (int i = 0; i < _schedule.length(); i++) { + VTransformNode* vtn = _schedule.at(i); + VTransformApplyResult result = vtn->apply(_vloop_analyzer, + vtnode_idx_to_transformed_node); + NOT_PRODUCT( if (_trace._verbose) { result.trace(vtn); } ) - // VectorMaskCmp - ConINode* test_mask_node = igvn().intcon((int)test_mask); - BasicType bt = velt_basic_type(cmp); - const TypeVect* vt = TypeVect::make(bt, vlen); - VectorNode* mask = new VectorMaskCmpNode(test_mask, cmp_in1, cmp_in2, test_mask_node, vt); - phase()->register_new_node_with_ctrl_of(mask, p->at(0)); - igvn()._worklist.push(mask); - - // VectorBlend - vn = new VectorBlendNode(blend_in1, blend_in2, mask); - } else if (n->req() == 3) { - // Promote operands to vector - Node* in1 = nullptr; - bool node_isa_reduction = is_marked_reduction(n); - if (node_isa_reduction) { - // the input to the first reduction operation is retained - in1 = first->in(1); - } else { - in1 = vector_opd(p, 1); - if (in1 == nullptr) { - assert(false, "input in1 to vector operand was not created"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } - } - Node* in2 = vector_opd(p, 2); - if (in2 == nullptr) { - assert(false, "input in2 to vector operand was not created"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } - if (in1->Opcode() == Op_Replicate && (node_isa_reduction == false) && (n->is_Add() || n->is_Mul())) { - // Move invariant vector input into second position to avoid register spilling. - Node* tmp = in1; - in1 = in2; - in2 = tmp; - } - if (node_isa_reduction) { - const Type *arith_type = n->bottom_type(); - vn = ReductionNode::make(opc, nullptr, in1, in2, arith_type->basic_type()); - if (in2->is_Load()) { - vlen_in_bytes = in2->as_LoadVector()->memory_size(); - } else { - vlen_in_bytes = in2->as_Vector()->length_in_bytes(); - } - } else { - if (VectorNode::can_use_RShiftI_instead_of_URShiftI(n, velt_basic_type(n))) { - opc = Op_RShiftI; - } - vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } - } else if (VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc)) { - assert(n->req() == 2, "only one input expected"); - Node* in = vector_opd(p, 1); - vn = VectorNode::make(opc, in, nullptr, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc)) { - assert(n->req() == 2, "only one input expected"); - Node* in = vector_opd(p, 1); - Node* longval = VectorNode::make(opc, in, nullptr, vlen, T_LONG); - phase()->register_new_node_with_ctrl_of(longval, first); - // Requires extra vector long -> int conversion. - vn = VectorCastNode::make(Op_VectorCastL2X, longval, T_INT, vlen); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (VectorNode::is_convert_opcode(opc)) { - assert(n->req() == 2, "only one input expected"); - BasicType bt = velt_basic_type(n); - Node* in = vector_opd(p, 1); - int vopc = VectorCastNode::opcode(opc, in->bottom_type()->is_vect()->element_basic_type()); - vn = VectorCastNode::make(vopc, in, bt, vlen); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else if (opc == Op_FmaD || opc == Op_FmaF) { - // Promote operands to vector - Node* in1 = vector_opd(p, 1); - Node* in2 = vector_opd(p, 2); - Node* in3 = vector_opd(p, 3); - vn = VectorNode::make(opc, in1, in2, in3, vlen, velt_basic_type(n)); - vlen_in_bytes = vn->as_Vector()->length_in_bytes(); - } else { - assert(false, "Unhandled scalar opcode (%s)", NodeClassNames[opc]); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } - - if (vn == nullptr) { - assert(false, "got null node instead of vector node"); - C->record_failure(C2Compiler::retry_no_superword()); - return false; // bailout - } + vtnode_idx_to_transformed_node.at_put(vtn->_idx, result.node()); + max_vector_length = MAX2(max_vector_length, result.vector_length()); + max_vector_width = MAX2(max_vector_width, result.vector_width()); + } +} -#ifdef ASSERT - // Mark Load/Store Vector for alignment verification - if (VerifyAlignVector) { - if (vn->Opcode() == Op_LoadVector) { - vn->as_LoadVector()->set_must_verify_alignment(); - } else if (vn->Opcode() == Op_StoreVector) { - vn->as_StoreVector()->set_must_verify_alignment(); - } - } +// We call "apply" on every VTransformNode, which replaces the packed scalar nodes with vector nodes. +void VTransform::apply_vectorization() const { + Compile* C = phase()->C; +#ifndef PRODUCT + if (_trace._verbose) { + tty->print_cr("\nVTransform::apply_vectorization:"); + } #endif - phase()->register_new_node_with_ctrl_of(vn, first); - for (uint j = 0; j < p->size(); j++) { - Node* pm = p->at(j); - igvn().replace_node(pm, vn); - } - igvn()._worklist.push(vn); + uint max_vector_length = 0; // number of elements + uint max_vector_width = 0; // total width in bytes + _graph.apply_vectorization_for_each_vtnode(max_vector_length, max_vector_width); - if (vlen > max_vlen) { - max_vlen = vlen; - } - if (vlen_in_bytes > max_vlen_in_bytes) { - max_vlen_in_bytes = vlen_in_bytes; - } - VectorNode::trace_new_vector(vn, "SuperWord"); - } - }//for (int i = 0; i < body().length(); i++) + assert(max_vector_length > 0 && max_vector_width > 0, "must have vectorized"); + cl()->mark_loop_vectorized(); - if (max_vlen_in_bytes > C->max_vector_size()) { - C->set_max_vector_size(max_vlen_in_bytes); - } - if (max_vlen_in_bytes > 0) { - cl->mark_loop_vectorized(); + if (max_vector_width > C->max_vector_size()) { + C->set_max_vector_size(max_vector_width); } if (SuperWordLoopUnrollAnalysis) { - if (cl->has_passed_slp()) { - uint slp_max_unroll_factor = cl->slp_max_unroll(); - if (slp_max_unroll_factor == max_vlen) { + if (cl()->has_passed_slp()) { + uint slp_max_unroll_factor = cl()->slp_max_unroll(); + if (slp_max_unroll_factor == max_vector_length) { #ifndef PRODUCT if (TraceSuperWordLoopUnrollAnalysis) { - tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte); + tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vector_length, max_vector_width * BitsPerByte); } #endif // For atomic unrolled loops which are vector mapped, instigate more unrolling - cl->set_notpassed_slp(); + cl()->set_notpassed_slp(); // if vector resources are limited, do not allow additional unrolling if (Matcher::float_pressure_limit() > 8) { C->set_major_progress(); - cl->mark_do_unroll_only(); + cl()->mark_do_unroll_only(); } } } } - - return true; -} - -//------------------------------vector_opd--------------------------- -// Create a vector operand for the nodes in pack p for operand: in(opd_idx) -Node* SuperWord::vector_opd(Node_List* p, int opd_idx) { - Node* p0 = p->at(0); - uint vlen = p->size(); - Node* opd = p0->in(opd_idx); - CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); - Node* same_input = _packset.same_inputs_at_index_or_null(p, opd_idx); - - // Insert index population operation to create a vector of increasing - // indices starting from the iv value. In some special unrolled loops - // (see JDK-8286125), we need scalar replications of the iv value if - // all inputs are the same iv, so we do a same inputs check here. - if (opd == iv() && same_input == nullptr) { - BasicType p0_bt = velt_basic_type(p0); - BasicType iv_bt = is_subword_type(p0_bt) ? p0_bt : T_INT; - assert(VectorNode::is_populate_index_supported(iv_bt), "Should support"); - const TypeVect* vt = TypeVect::make(iv_bt, vlen); - Node* vn = new PopulateIndexNode(iv(), igvn().intcon(1), vt); - VectorNode::trace_new_vector(vn, "SuperWord"); - phase()->register_new_node_with_ctrl_of(vn, opd); - return vn; - } - - if (same_input != nullptr) { - if (opd->is_Vector() || opd->is_LoadVector()) { - if (opd_idx == 2 && VectorNode::is_shift(p0)) { - assert(false, "shift's count can't be vector"); - return nullptr; - } - return opd; // input is matching vector - } - if ((opd_idx == 2) && VectorNode::is_shift(p0)) { - Node* cnt = opd; - // Vector instructions do not mask shift count, do it here. - juint mask = (p0->bottom_type() == TypeInt::INT) ? (BitsPerInt - 1) : (BitsPerLong - 1); - const TypeInt* t = opd->find_int_type(); - if (t != nullptr && t->is_con()) { - juint shift = t->get_con(); - if (shift > mask) { // Unsigned cmp - cnt = igvn().intcon(shift & mask); - phase()->set_ctrl(cnt, phase()->C->root()); - } - } else { - if (t == nullptr || t->_lo < 0 || t->_hi > (int)mask) { - cnt = igvn().intcon(mask); - cnt = new AndINode(opd, cnt); - phase()->register_new_node_with_ctrl_of(cnt, opd); - } - if (!opd->bottom_type()->isa_int()) { - assert(false, "int type only"); - return nullptr; - } - } - // Move shift count into vector register. - cnt = VectorNode::shift_count(p0->Opcode(), cnt, vlen, velt_basic_type(p0)); - phase()->register_new_node_with_ctrl_of(cnt, opd); - return cnt; - } - if (opd->is_StoreVector()) { - assert(false, "StoreVector is not expected here"); - return nullptr; - } - // Convert scalar input to vector with the same number of elements as - // p0's vector. Use p0's type because size of operand's container in - // vector should match p0's size regardless operand's size. - const Type* p0_t = nullptr; - VectorNode* vn = nullptr; - if (opd_idx == 2 && VectorNode::is_scalar_rotate(p0)) { - Node* conv = opd; - p0_t = TypeInt::INT; - if (p0->bottom_type()->isa_long()) { - p0_t = TypeLong::LONG; - conv = new ConvI2LNode(opd); - phase()->register_new_node_with_ctrl_of(conv, opd); - } - vn = VectorNode::scalar2vector(conv, vlen, p0_t); - } else { - p0_t = velt_type(p0); - vn = VectorNode::scalar2vector(opd, vlen, p0_t); - } - - phase()->register_new_node_with_ctrl_of(vn, opd); - VectorNode::trace_new_vector(vn, "SuperWord"); - return vn; - } - - // Insert pack operation - BasicType bt = velt_basic_type(p0); - PackNode* pk = PackNode::make(opd, vlen, bt); - DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); ) - - for (uint i = 1; i < vlen; i++) { - Node* pi = p->at(i); - Node* in = pi->in(opd_idx); - if (get_pack(in) != nullptr) { - assert(false, "Should already have been unpacked"); - return nullptr; - } - assert(opd_bt == in->bottom_type()->basic_type(), "all same type"); - pk->add_opd(in); - if (VectorNode::is_muladds2i(pi)) { - Node* in2 = pi->in(opd_idx + 2); - if (get_pack(in2) != nullptr) { - assert(false, "Should already have been unpacked"); - return nullptr; - } - assert(opd_bt == in2->bottom_type()->basic_type(), "all same type"); - pk->add_opd(in2); - } - } - phase()->register_new_node_with_ctrl_of(pk, opd); - VectorNode::trace_new_vector(pk, "SuperWord"); - return pk; } #ifdef ASSERT @@ -2797,18 +2224,7 @@ bool SuperWord::is_vector_use(Node* use, int u_idx) const { return _packset.is_muladds2i_pack_with_pack_inputs(u_pk); } - if (u_pk->size() != d_pk->size()) { - return false; - } - - for (uint i = 0; i < u_pk->size(); i++) { - Node* ui = u_pk->at(i); - Node* di = d_pk->at(i); - if (ui->in(u_idx) != di) { - return false; - } - } - return true; + return _packset.pack_input_at_index_or_null(u_pk, u_idx) != nullptr; } // MulAddS2I takes 4 shorts and produces an int. We can reinterpret @@ -3182,10 +2598,10 @@ bool VLoopMemorySlices::same_memory_slice(MemNode* m1, MemNode* m2) const { _vloop.phase()->C->get_alias_index(m2->adr_type()); } -LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { +LoadNode::ControlDependency VTransformLoadVectorNode::control_dependency() const { LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; - for (uint i = 0; i < p->size(); i++) { - Node* n = p->at(i); + for (int i = 0; i < nodes().length(); i++) { + Node* n = nodes().at(i); assert(n->is_Load(), "only meaningful for loads"); if (!n->depends_only_on_test()) { if (n->as_Load()->has_unknown_control_dependency() && @@ -3202,8 +2618,8 @@ LoadNode::ControlDependency SuperWord::control_dependency(Node_List* p) { } // Find the memop pack with the maximum vector width, unless they were already -// determined by SuperWord::filter_packs_for_alignment(). -void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { +// determined (e.g. by SuperWord::filter_packs_for_alignment()). +void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { if (_mem_ref_for_main_loop_alignment != nullptr) { assert(VLoop::vectors_should_be_aligned(), "mem_ref only set if filtered for alignment"); return; @@ -3211,15 +2627,18 @@ void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { MemNode const* mem_ref = nullptr; int max_aw = 0; - for (int i = 0; i < _packset.length(); i++) { - Node_List* pack = _packset.at(i); - MemNode* first = pack->at(0)->isa_Mem(); - if (first == nullptr) { continue; } - int vw = first->memory_size() * pack->size(); + const GrowableArray& vtnodes = _graph.vtnodes(); + for (int i = 0; i < vtnodes.length(); i++) { + VTransformVectorNode* vtn = vtnodes.at(i)->isa_Vector(); + if (vtn == nullptr) { continue; } + MemNode* p0 = vtn->nodes().at(0)->isa_Mem(); + if (p0 == nullptr) { continue; } + + int vw = p0->memory_size() * vtn->nodes().length(); if (vw > max_aw) { max_aw = vw; - mem_ref = first; + mem_ref = p0; } } assert(mem_ref != nullptr && max_aw > 0, "found mem_ref and aw"); @@ -3229,7 +2648,7 @@ void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { #define TRACE_ALIGN_VECTOR_NODE(node) { \ DEBUG_ONLY( \ - if (is_trace_align_vector()) { \ + if (_trace._align_vector) { \ tty->print(" " #node ": "); \ node->dump(); \ } \ @@ -3240,7 +2659,7 @@ void SuperWord::determine_mem_ref_and_aw_for_main_loop_alignment() { // the address of "_mem_ref_for_main_loop_alignment" to "_aw_for_main_loop_alignment", which is a // sufficiently large alignment width. We adjust the pre-loop iteration count by adjusting the // pre-loop limit. -void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { +void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { determine_mem_ref_and_aw_for_main_loop_alignment(); const MemNode* align_to_ref = _mem_ref_for_main_loop_alignment; const int aw = _aw_for_main_loop_alignment; @@ -3397,8 +2816,8 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { Node* invar = align_to_ref_p.invar(); #ifdef ASSERT - if (is_trace_align_vector()) { - tty->print_cr("\nadjust_pre_loop_limit_to_align_main_loop_vectors:"); + if (_trace._align_vector) { + tty->print_cr("\nVTransform::adjust_pre_loop_limit_to_align_main_loop_vectors:"); tty->print(" align_to_ref:"); align_to_ref->dump(); tty->print_cr(" aw: %d", aw); @@ -3424,7 +2843,7 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { scale == 0 || !is_power_of_2(abs(scale)) || abs(scale) >= aw) { #ifdef ASSERT - if (is_trace_align_vector()) { + if (_trace._align_vector) { tty->print_cr(" Alignment cannot be affected by changing pre-loop limit because"); tty->print_cr(" stride or scale are not power of 2, or abs(scale) >= aw."); } @@ -3440,7 +2859,7 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() { const int AW = aw / abs(scale); #ifdef ASSERT - if (is_trace_align_vector()) { + if (_trace._align_vector) { tty->print_cr(" AW = aw(%d) / abs(scale(%d)) = %d", aw, scale, AW); } #endif @@ -3595,10 +3014,10 @@ void PackSet::print_pack(Node_List* pack) { #ifndef PRODUCT void VLoopBody::print() const { - tty->print_cr("\nBlock"); + tty->print_cr("\nVLoopBody::print"); for (int i = 0; i < body().length(); i++) { Node* n = body().at(i); - tty->print("%d ", i); + tty->print("%4d ", i); if (n != nullptr) { n->dump(); } @@ -3615,3 +3034,4 @@ bool SuperWord::same_origin_idx(Node* a, Node* b) const { bool SuperWord::same_generation(Node* a, Node* b) const { return a != nullptr && b != nullptr && _clone_map.same_gen(a->_idx, b->_idx); } + diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index fb91d014faebb..65f870825251f 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -25,6 +25,7 @@ #define SHARE_OPTO_SUPERWORD_HPP #include "opto/vectorization.hpp" +#include "opto/vtransform.hpp" #include "utilities/growableArray.hpp" // @@ -367,6 +368,10 @@ class PackSet : public StackObj { Node* same_inputs_at_index_or_null(const Node_List* pack, const int index) const; VTransformBoolTest get_bool_test(const Node_List* bool_pack) const; + Node_List* pack_input_at_index_or_null(const Node_List* pack, const int index) const { + return strided_pack_input_at_index_or_null(pack, index, 1, 0); + } + private: SplitStatus split_pack(const char* split_name, Node_List* pack, SplitTask task); public: @@ -599,13 +604,6 @@ class SuperWord : public ResourceObj { DEBUG_ONLY(void verify_packs() const;) - bool schedule_and_apply(); - bool apply(Node_List& memops_schedule); - void apply_memops_reordering_with_schedule(Node_List& memops_schedule); - bool apply_vectorization(); - // Create a vector operand for the nodes in pack p for operand: in(opd_idx) - Node* vector_opd(Node_List* p, int opd_idx); - // Can code be generated for the pack, restricted to size nodes? bool implemented(const Node_List* pack, const uint size) const; // Find the maximal implemented size smaller or equal to the packs size @@ -630,11 +628,7 @@ class SuperWord : public ResourceObj { bool is_velt_basic_type_compatible_use_def(Node* use, Node* def) const; - static LoadNode::ControlDependency control_dependency(Node_List* p); - - // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. - void determine_mem_ref_and_aw_for_main_loop_alignment(); - void adjust_pre_loop_limit_to_align_main_loop_vectors(); + bool schedule_and_apply() const; }; #endif // SHARE_OPTO_SUPERWORD_HPP diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp new file mode 100644 index 0000000000000..b0a0c97cb1676 --- /dev/null +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "opto/superwordVTransformBuilder.hpp" +#include "opto/vectornode.hpp" + +void SuperWordVTransformBuilder::build() { + assert(!_packset.is_empty(), "must have non-empty packset"); + assert(!_vtransform.has_graph(), "start with empty vtransform"); + + // Create vtnodes for all nodes in the loop. + build_vector_vtnodes_for_packed_nodes(); + build_scalar_vtnodes_for_non_packed_nodes(); + + // Connect all vtnodes with their inputs. Possibly create vtnodes for input + // nodes that are outside the loop. + VectorSet vtn_dependencies; // Shared, but cleared for every vtnode. + build_inputs_for_vector_vtnodes(vtn_dependencies); + build_inputs_for_scalar_vtnodes(vtn_dependencies); +} + +void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { + for (int i = 0; i < _packset.length(); i++) { + Node_List* pack = _packset.at(i); + VTransformVectorNode* vtn = make_vector_vtnode_for_pack(pack); + for (uint k = 0; k < pack->size(); k++) { + map_node_to_vtnode(pack->at(k), vtn); + } + } +} + +void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { + for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { + Node* n = _vloop_analyzer.body().body().at(i); + if (_packset.get_pack(n) != nullptr) { continue; } + VTransformScalarNode* vtn = new (_vtransform.arena()) VTransformScalarNode(_vtransform, n); + map_node_to_vtnode(n, vtn); + } +} + +void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_dependencies) { + for (int i = 0; i < _packset.length(); i++) { + Node_List* pack = _packset.at(i); + Node* p0 = pack->at(0); + + VTransformVectorNode* vtn = get_vtnode(p0)->isa_Vector(); + assert(vtn != nullptr, "all packs must have vector vtnodes"); + vtn_dependencies.clear(); // Add every dependency only once per vtn. + + if (p0->is_Load()) { + set_req_with_scalar(p0, vtn, vtn_dependencies, MemNode::Address); + } else if (p0->is_Store()) { + set_req_with_scalar(p0, vtn, vtn_dependencies, MemNode::Address); + set_req_with_vector(pack, vtn, vtn_dependencies, MemNode::ValueIn); + } else if (vtn->isa_ReductionVector() != nullptr) { + set_req_with_scalar(p0, vtn, vtn_dependencies, 1); // scalar init + set_req_with_vector(pack, vtn, vtn_dependencies, 2); // vector + } else { + assert(vtn->isa_ElementWiseVector() != nullptr, "all other vtnodes are handled above"); + if (VectorNode::is_scalar_rotate(p0) && + p0->in(2)->is_Con() && + Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { + set_req_with_vector(pack, vtn, vtn_dependencies, 1); + set_req_with_scalar(p0, vtn, vtn_dependencies, 2); // constant rotation + } else if (VectorNode::is_roundopD(p0)) { + set_req_with_vector(pack, vtn, vtn_dependencies, 1); + set_req_with_scalar(p0, vtn, vtn_dependencies, 2); // constant rounding mode + } else if (p0->is_CMove()) { + // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. + set_all_req_with_vectors(pack, vtn, vtn_dependencies); + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in(1)->isa_BoolVector(); + if (vtn_mask_cmp->test()._is_negated) { + vtn->swap_req(2, 3); // swap if test was negated. + } + } else { + set_all_req_with_vectors(pack, vtn, vtn_dependencies); + } + } + + for (uint k = 0; k < pack->size(); k++) { + add_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_dependencies); + } + } +} + +void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_dependencies) { + for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { + Node* n = _vloop_analyzer.body().body().at(i); + VTransformScalarNode* vtn = get_vtnode(n)->isa_Scalar(); + if (vtn == nullptr) { continue; } + vtn_dependencies.clear(); // Add every dependency only once per vtn. + + if (n->is_Load()) { + set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::Address); + } else if (n->is_Store()) { + set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::Address); + set_req_with_scalar(n, vtn, vtn_dependencies, MemNode::ValueIn); + } else if (n->is_CountedLoop()) { + continue; // Is "root", has no dependency. + } else if (n->is_Phi()) { + // CountedLoop Phi's: ignore backedge (and entry value). + assert(n->in(0) == _vloop.cl(), "only Phi's from the CountedLoop allowed"); + set_req_with_scalar(n, vtn, vtn_dependencies, 0); + continue; + } else { + set_all_req_with_scalars(n, vtn, vtn_dependencies); + } + + add_dependencies_of_node_to_vtnode(n, vtn, vtn_dependencies); + } +} + +// Create a vtnode for each pack. No in/out edges set yet. +VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(const Node_List* pack) const { + uint pack_size = pack->size(); + Node* p0 = pack->at(0); + int opc = p0->Opcode(); + VTransformVectorNode* vtn = nullptr; + + if (p0->is_Load()) { + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, pack_size); + } else if (p0->is_Store()) { + vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, pack_size); + } else if (p0->is_Bool()) { + VTransformBoolTest kind = _packset.get_bool_test(pack); + vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, pack_size, kind); + } else if (_vloop_analyzer.reductions().is_marked_reduction(p0)) { + vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, pack_size); + } else if (VectorNode::is_muladds2i(p0)) { + // A special kind of binary element-wise vector op: the inputs are "ints" a and b, + // but reinterpreted as two "shorts" [a0, a1] and [b0, b1]: + // v = MulAddS2I(a, b) = a0 * b0 + a1 + b1 + assert(p0->req() == 5, "MulAddS2I should have 4 operands"); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, pack_size); + } else { + assert(p0->req() == 3 || + p0->is_CMove() || + VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc) || + VectorNode::is_convert_opcode(opc) || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc) || + opc == Op_FmaD || + opc == Op_FmaF || + opc == Op_SignumF || + opc == Op_SignumD, + "pack type must be in this list"); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), pack_size); + } + vtn->set_nodes(pack); + return vtn; +} + +void SuperWordVTransformBuilder::set_req_with_scalar(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index) { + VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); + vtn->set_req(index, req); + vtn_dependencies.set(req->_idx); +} + +// Either get the existing vtnode vector input (when input is a pack), or else make a +// new vector vtnode for the input (e.g. for Replicate or PopulateIndex). +VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index) { + Node* p0 = pack->at(0); + + Node_List* pack_in = _packset.pack_input_at_index_or_null(pack, index); + if (pack_in != nullptr) { + // Input is a matching pack -> vtnode already exists. + assert(index != 2 || !VectorNode::is_shift(p0), "shift's count cannot be vector"); + return get_vtnode(pack_in->at(0)); + } + + if (VectorNode::is_muladds2i(p0)) { + assert(_packset.is_muladds2i_pack_with_pack_inputs(pack), "inputs must all be packs"); + // All inputs are strided (stride = 2), either with offset 0 or 1. + Node_List* pack_in0 = _packset.strided_pack_input_at_index_or_null(pack, index, 2, 0); + if (pack_in0 != nullptr) { + return get_vtnode(pack_in0->at(0)); + } + Node_List* pack_in1 = _packset.strided_pack_input_at_index_or_null(pack, index, 2, 1); + if (pack_in1 != nullptr) { + return get_vtnode(pack_in1->at(0)); + } + } + + Node* same_input = _packset.same_inputs_at_index_or_null(pack, index); + if (same_input == nullptr && p0->in(index) == _vloop.iv()) { + // PopulateIndex: [iv+0, iv+1, iv+2, ...] + VTransformNode* iv_vtn = get_vtnode_or_wrap_as_input_scalar(_vloop.iv()); + BasicType p0_bt = _vloop_analyzer.types().velt_basic_type(p0); + // If we have subword type, take that type directly. If p0 is some ConvI2L/F/D, + // then the p0_bt can also be L/F/D but we need to produce ints for the input of + // the ConvI2L/F/D. + BasicType element_bt = is_subword_type(p0_bt) ? p0_bt : T_INT; + VTransformNode* populate_index = new (_vtransform.arena()) VTransformPopulateIndexNode(_vtransform, pack->size(), element_bt); + populate_index->set_req(1, iv_vtn); + return populate_index; + } + + if (same_input != nullptr) { + VTransformNode* same_input_vtn = get_vtnode_or_wrap_as_input_scalar(same_input); + if (index == 2 && VectorNode::is_shift(p0)) { + // Scalar shift count for vector shift operation: vec2 = shiftV(vec1, scalar_count) + // Scalar shift operations masks the shift count, but the vector shift does not, so + // create a special ShiftCount node. + BasicType element_bt = _vloop_analyzer.types().velt_basic_type(p0); + juint mask = (p0->bottom_type() == TypeInt::INT) ? (BitsPerInt - 1) : (BitsPerLong - 1); + VTransformNode* shift_count = new (_vtransform.arena()) VTransformShiftCountNode(_vtransform, pack->size(), element_bt, mask, p0->Opcode()); + shift_count->set_req(1, same_input_vtn); + return shift_count; + } else { + // Replicate the scalar same_input to every vector element. + const Type* element_type = _vloop_analyzer.types().velt_type(p0); + if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type->isa_long()) { + // Scalar rotate has int rotation value, but the scalar rotate expects longs. + assert(same_input->bottom_type()->isa_int(), "scalar rotate expects int rotation"); + VTransformNode* conv = new (_vtransform.arena()) VTransformConvI2LNode(_vtransform); + conv->set_req(1, same_input_vtn); + same_input_vtn = conv; + } + VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_type); + replicate->set_req(1, same_input_vtn); + return replicate; + } + } + + // The input is neither a pack not a same_input node. SuperWord::profitable does not allow + // any other case. In the future, we could insert a PackNode. +#ifdef ASSERT + tty->print_cr("\nSuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_index: index=%d", index); + pack->dump(); + assert(false, "Pack input was neither a pack nor a same_input node"); +#endif + ShouldNotReachHere(); +} + +VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(Node* n) { + VTransformNode* vtn = get_vtnode_or_null(n); + if (vtn != nullptr) { return vtn; } + + assert(!_vloop.in_bb(n), "only nodes outside the loop can be input nodes to the loop"); + vtn = new (_vtransform.arena()) VTransformInputScalarNode(_vtransform, n); + map_node_to_vtnode(n, vtn); + return vtn; +} + +void SuperWordVTransformBuilder::set_req_with_vector(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies, int j) { + VTransformNode* req = get_or_make_vtnode_vector_input_at_index(pack, j); + vtn->set_req(j, req); + vtn_dependencies.set(req->_idx); +} + +void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies) { + assert(vtn->req() == n->req(), "scalars must have same number of reqs"); + for (uint j = 0; j < n->req(); j++) { + Node* def = n->in(j); + if (def == nullptr) { continue; } + set_req_with_scalar(n, vtn, vtn_dependencies, j); + } +} + +void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies) { + Node* p0 = pack->at(0); + assert(vtn->req() <= p0->req(), "must have at at most as many reqs"); + // Vectors have no ctrl, so ignore it. + for (uint j = 1; j < vtn->req(); j++) { + Node* def = p0->in(j); + if (def == nullptr) { continue; } + set_req_with_vector(pack, vtn, vtn_dependencies, j); + } +} + +void SuperWordVTransformBuilder::add_dependencies_of_node_to_vtnode(Node*n, VTransformNode* vtn, VectorSet& vtn_dependencies) { + for (VLoopDependencyGraph::PredsIterator preds(_vloop_analyzer.dependency_graph(), n); !preds.done(); preds.next()) { + Node* pred = preds.current(); + if (!_vloop.in_bb(pred)) { continue; } + + // Only add memory dependencies to memory nodes. All others are taken care of with the req. + if (n->is_Mem() && !pred->is_Mem()) { continue; } + + VTransformNode* dependency = get_vtnode(pred); + + // Reduction self-cycle? + if (vtn == dependency && _vloop_analyzer.reductions().is_marked_reduction(n)) { continue; } + + if (vtn_dependencies.test_set(dependency->_idx)) { continue; } + vtn->add_dependency(dependency); // Add every dependency only once per vtn. + } +} + diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp new file mode 100644 index 0000000000000..847f870bef616 --- /dev/null +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "opto/vtransform.hpp" +#include "opto/superword.hpp" + +#ifndef SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP +#define SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP + +// Facility class that builds a VTransform from a SuperWord PackSet. +class SuperWordVTransformBuilder : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + const VLoop& _vloop; + const PackSet& _packset; + VTransform& _vtransform; + + ResourceHashtable _idx_to_vtnode; + +public: + SuperWordVTransformBuilder(const PackSet& packset, + VTransform& vtransform) : + _vloop_analyzer(vtransform.vloop_analyzer()), + _vloop(_vloop_analyzer.vloop()), + _packset(packset), + _vtransform(vtransform) + { + assert(!_vtransform.has_graph(), "constructor is passed an empty vtransform"); + build(); + assert(_vtransform.has_graph(), "vtransform must contain some vtnodes now"); + } + +private: + void build(); + void build_vector_vtnodes_for_packed_nodes(); + void build_scalar_vtnodes_for_non_packed_nodes(); + void build_inputs_for_vector_vtnodes(VectorSet& vtn_dependencies); + void build_inputs_for_scalar_vtnodes(VectorSet& vtn_dependencies); + + // Helper methods for building VTransform. + VTransformNode* get_vtnode_or_null(Node* n) const { + VTransformNode** ptr = _idx_to_vtnode.get(n->_idx); + return (ptr == nullptr) ? nullptr : *ptr; + } + + VTransformNode* get_vtnode(Node* n) const { + VTransformNode* vtn = get_vtnode_or_null(n); + assert(vtn != nullptr, "expect non-null vtnode"); + return vtn; + } + + void map_node_to_vtnode(Node* n, VTransformNode* vtn) { + assert(vtn != nullptr, "only set non-null vtnodes"); + _idx_to_vtnode.put_when_absent(n->_idx, vtn); + } + + VTransformVectorNode* make_vector_vtnode_for_pack(const Node_List* pack) const; + VTransformNode* get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index); + VTransformNode* get_vtnode_or_wrap_as_input_scalar(Node* n); + void set_req_with_scalar(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index); + void set_req_with_vector(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies, const int index); + void set_all_req_with_scalars(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies); + void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn, VectorSet& vtn_dependencies); + void add_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_dependencies); +}; + +#endif // SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 3aae04c9453f5..038e04fe0c50b 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -43,6 +43,7 @@ flags(SW_INFO, "Trace SuperWord info (equivalent to TraceSuperWord)") \ flags(SW_VERBOSE, "Trace SuperWord verbose (all SW tags enabled)") \ flags(ALIGN_VECTOR, "Trace AlignVector") \ + flags(VTRANSFORM, "Trace VTransform Graph") \ flags(ALL, "Trace everything (very verbose)") #define table_entry(name, description) name, diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 01b235e8b27e8..8d2d3868fe635 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -26,7 +26,6 @@ #include "opto/addnode.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" -#include "opto/matcher.hpp" #include "opto/mulnode.hpp" #include "opto/rootnode.hpp" #include "opto/vectorization.hpp" diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index c9f54594910ab..3984407c5654b 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_OPTO_VECTORIZATION_HPP #define SHARE_OPTO_VECTORIZATION_HPP -#include "opto/node.hpp" +#include "opto/matcher.hpp" #include "opto/loopnode.hpp" #include "opto/traceAutoVectorizationTag.hpp" #include "utilities/pair.hpp" @@ -763,9 +763,9 @@ class VPointer : public ArenaObj { } } - bool overlap_possible_with_any_in(const Node_List* p) const { - for (uint k = 0; k < p->size(); k++) { - MemNode* mem = p->at(k)->as_Mem(); + bool overlap_possible_with_any_in(const GrowableArray& nodes) const { + for (int i = 0; i < nodes.length(); i++) { + MemNode* mem = nodes.at(i)->as_Mem(); VPointer p_mem(mem, _vloop); // Only if we know that we have Less or Greater can we // be sure that there can never be an overlap between @@ -1323,12 +1323,4 @@ class AlignmentSolver { #endif }; -struct VTransformBoolTest { - const BoolTest::mask _mask; - const bool _is_negated; - - VTransformBoolTest(const BoolTest::mask mask, bool is_negated) : - _mask(mask), _is_negated(is_negated) {} -}; - #endif // SHARE_OPTO_VECTORIZATION_HPP diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp new file mode 100644 index 0000000000000..e40157caa362b --- /dev/null +++ b/src/hotspot/share/opto/vtransform.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "opto/vtransform.hpp" +#include "opto/vectornode.hpp" +#include "opto/convertnode.hpp" + +void VTransformGraph::add_vtnode(VTransformNode* vtnode) { + assert(vtnode->_idx == _vtnodes.length(), "position must match idx"); + _vtnodes.push(vtnode); +} + +// Compute a linearization of the graph. We do this with a reverse-post-order of a DFS. +// This only works if the graph is a directed acyclic graph (DAG). The C2 graph, and +// the VLoopDependencyGraph are both DAGs, but after introduction of vectors/packs, the +// graph has additional constraints which can introduce cycles. Example: +// +// +--------+ +// A -> X | v +// Pack [A,B] and [X,Y] [A,B] [X,Y] +// Y -> B ^ | +// +--------+ +// +// We return "true" IFF we find no cycle, i.e. if the linearization succeeds. +bool VTransformGraph::schedule() { + assert(!is_scheduled(), "not yet scheduled"); + +#ifndef PRODUCT + if (_trace._verbose) { + print_vtnodes(); + } +#endif + + ResourceMark rm; + GrowableArray stack; + VectorSet pre_visited; + VectorSet post_visited; + + collect_nodes_without_req_or_dependency(stack); + + // We create a reverse-post-visit order. This gives us a linearization, if there are + // no cycles. Then, we simply reverse the order, and we have a schedule. + int rpo_idx = _vtnodes.length() - 1; + while (!stack.is_empty()) { + VTransformNode* vtn = stack.top(); + if (!pre_visited.test_set(vtn->_idx)) { + // Forward arc in graph (pre-visit). + } else if (!post_visited.test(vtn->_idx)) { + // Forward arc in graph. Check if all uses were already visited: + // Yes -> post-visit. + // No -> we are mid-visit. + bool all_uses_already_visited = true; + + for (int i = 0; i < vtn->outs(); i++) { + VTransformNode* use = vtn->out(i); + if (post_visited.test(use->_idx)) { continue; } + if (pre_visited.test(use->_idx)) { + // Cycle detected! + // The nodes that are pre_visited but not yet post_visited form a path from + // the "root" to the current vtn. Now, we are looking at an edge (vtn, use), + // and discover that use is also pre_visited but not post_visited. Thus, use + // lies on that path from "root" to vtn, and the edge (vtn, use) closes a + // cycle. + NOT_PRODUCT(if (_trace._rejections) { trace_schedule_cycle(stack, pre_visited, post_visited); } ) + return false; + } + stack.push(use); + all_uses_already_visited = false; + } + + if (all_uses_already_visited) { + stack.pop(); + post_visited.set(vtn->_idx); // post-visit + _schedule.at_put_grow(rpo_idx--, vtn); // assign rpo_idx + } + } else { + stack.pop(); // Already post-visited. Ignore secondary edge. + } + } + +#ifndef PRODUCT + if (_trace._verbose) { + print_schedule(); + } +#endif + + assert(rpo_idx == -1, "used up all rpo_idx, rpo_idx=%d", rpo_idx); + return true; +} + +// Push all "root" nodes, i.e. those that have no inputs (req or dependency): +void VTransformGraph::collect_nodes_without_req_or_dependency(GrowableArray& stack) const { + for (int i = 0; i < _vtnodes.length(); i++) { + VTransformNode* vtn = _vtnodes.at(i); + if (!vtn->has_req_or_dependency()) { + stack.push(vtn); + } + } +} + +#ifndef PRODUCT +void VTransformGraph::trace_schedule_cycle(const GrowableArray& stack, + const VectorSet& pre_visited, + const VectorSet& post_visited) const { + tty->print_cr("\nVTransform::schedule found a cycle on path (P), vectorization attempt fails."); + for (int j = 0; j < stack.length(); j++) { + VTransformNode* n = stack.at(j); + bool on_path = pre_visited.test(n->_idx) && !post_visited.test(n->_idx); + tty->print(" %s ", on_path ? "P" : "_"); + n->print(); + } +} + +void VTransformApplyResult::trace(VTransformNode* vtnode) const { + tty->print(" apply: "); + vtnode->print(); + tty->print(" -> "); + if (_node == nullptr) { + tty->print_cr("nullptr"); + } else { + _node->dump(); + } +} +#endif + +Node* VTransformNode::find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const { + Node* n = vnode_idx_to_transformed_node.at(in(i)->_idx); + assert(n != nullptr, "must find input IR node"); + return n; +} + +VTransformApplyResult VTransformScalarNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformReplicateNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); + VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); + register_new_node_from_vectorization(vloop_analyzer, vn, val); + return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); +} + +VTransformApplyResult VTransformConvI2LNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); + Node* n = new ConvI2LNode(val); + register_new_node_from_vectorization(vloop_analyzer, n, val); + return VTransformApplyResult::make_scalar(n); +} + +VTransformApplyResult VTransformShiftCountNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + Node* shift_count_in = find_transformed_input(1, vnode_idx_to_transformed_node); + assert(shift_count_in->bottom_type()->isa_int(), "int type only for shift count"); + // The shift_count_in would be automatically truncated to the lowest _mask + // bits in a scalar shift operation. But vector shift does not truncate, so + // we must apply the mask now. + Node* shift_count_masked = new AndINode(shift_count_in, phase->igvn().intcon(_mask)); + register_new_node_from_vectorization(vloop_analyzer, shift_count_masked, shift_count_in); + // Now that masked value is "boadcast" (some platforms only set the lowest element). + VectorNode* vn = VectorNode::shift_count(_shift_opcode, shift_count_masked, _vlen, _element_bt); + register_new_node_from_vectorization(vloop_analyzer, vn, shift_count_in); + return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); +} + + +VTransformApplyResult VTransformPopulateIndexNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); + assert(val->is_Phi(), "expected to be iv"); + assert(VectorNode::is_populate_index_supported(_element_bt), "should support"); + const TypeVect* vt = TypeVect::make(_element_bt, _vlen); + VectorNode* vn = new PopulateIndexNode(val, phase->igvn().intcon(1), vt); + register_new_node_from_vectorization(vloop_analyzer, vn, val); + return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); +} + +VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* first = nodes().at(0); + uint vlen = nodes().length(); + int opc = first->Opcode(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + + if (first->is_Cmp()) { + // Cmp + Bool -> VectorMaskCmp + // Handled by Bool / VTransformBoolVectorNode, so we do not generate any nodes here. + return VTransformApplyResult::make_empty(); + } + + assert(2 <= req() && req() <= 4, "Must have 1-3 inputs"); + VectorNode* vn = nullptr; + Node* in1 = find_transformed_input(1, vnode_idx_to_transformed_node); + Node* in2 = (req() >= 3) ? find_transformed_input(2, vnode_idx_to_transformed_node) : nullptr; + Node* in3 = (req() >= 4) ? find_transformed_input(3, vnode_idx_to_transformed_node) : nullptr; + + if (first->is_CMove()) { + assert(req() == 4, "three inputs expected: mask, blend1, blend2"); + vn = new VectorBlendNode(/* blend1 */ in2, /* blend2 */ in3, /* mask */ in1); + } else if (VectorNode::is_convert_opcode(opc)) { + assert(first->req() == 2 && req() == 2, "only one input expected"); + int vopc = VectorCastNode::opcode(opc, in1->bottom_type()->is_vect()->element_basic_type()); + vn = VectorCastNode::make(vopc, in1, bt, vlen); + } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { + opc = Op_RShiftI; + vn = VectorNode::make(opc, in1, in2, vlen, bt); + } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc)) { + // The scalar operation was a long -> int operation. + // However, the vector operation is long -> long. + VectorNode* long_vn = VectorNode::make(opc, in1, nullptr, vlen, T_LONG); + register_new_node_from_vectorization(vloop_analyzer, long_vn, first); + // Cast long -> int, to mimic the scalar long -> int operation. + vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); + } else if (req() == 3 || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc)) { + assert(!VectorNode::is_roundopD(first) || in2->is_Con(), "rounding mode must be constant"); + vn = VectorNode::make(opc, in1, in2, vlen, bt); // unary and binary + } else { + assert(req() == 4, "three inputs expected"); + assert(opc == Op_FmaD || + opc == Op_FmaF || + opc == Op_SignumF || + opc == Op_SignumD, + "element wise operation must be from this list"); + vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary + } + + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->length_in_bytes()); +} + +VTransformApplyResult VTransformBoolVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + BoolNode* first = nodes().at(0)->as_Bool(); + uint vlen = nodes().length(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + + // Cmp + Bool -> VectorMaskCmp + VTransformElementWiseVectorNode* vtn_cmp = in(1)->isa_ElementWiseVector(); + assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), + "bool vtn expects cmp vtn as input"); + + Node* cmp_in1 = vtn_cmp->find_transformed_input(1, vnode_idx_to_transformed_node); + Node* cmp_in2 = vtn_cmp->find_transformed_input(2, vnode_idx_to_transformed_node); + BoolTest::mask mask = test()._mask; + + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + ConINode* mask_node = phase->igvn().intcon((int)mask); + const TypeVect* vt = TypeVect::make(bt, vlen); + VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); +} + +VTransformApplyResult VTransformReductionVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + Node* first = nodes().at(0); + uint vlen = nodes().length(); + int opc = first->Opcode(); + BasicType bt = first->bottom_type()->basic_type(); + + Node* init = find_transformed_input(1, vnode_idx_to_transformed_node); + Node* vec = find_transformed_input(2, vnode_idx_to_transformed_node); + + ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); +} + +VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + LoadNode* first = nodes().at(0)->as_Load(); + uint vlen = nodes().length(); + Node* ctrl = first->in(MemNode::Control); + Node* mem = first->in(MemNode::Memory); + Node* adr = first->in(MemNode::Address); + int opc = first->Opcode(); + const TypePtr* adr_type = first->adr_type(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + + // Set the memory dependency of the LoadVector as early as possible. + // Walk up the memory chain, and ignore any StoreVector that provably + // does not have any memory dependency. + while (mem->is_StoreVector()) { + VPointer p_store(mem->as_Mem(), vloop_analyzer.vloop()); + if (p_store.overlap_possible_with_any_in(nodes())) { + break; + } else { + mem = mem->in(MemNode::Memory); + } + } + + LoadVectorNode* vn = LoadVectorNode::make(opc, ctrl, mem, adr, adr_type, vlen, bt, + control_dependency()); + DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); +} + +VTransformApplyResult VTransformStoreVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const { + StoreNode* first = nodes().at(0)->as_Store(); + uint vlen = nodes().length(); + Node* ctrl = first->in(MemNode::Control); + Node* mem = first->in(MemNode::Memory); + Node* adr = first->in(MemNode::Address); + int opc = first->Opcode(); + const TypePtr* adr_type = first->adr_type(); + + Node* value = find_transformed_input(MemNode::ValueIn, vnode_idx_to_transformed_node); + StoreVectorNode* vn = StoreVectorNode::make(opc, ctrl, mem, adr, adr_type, value, vlen); + DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) + register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); +} + +void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(const VLoopAnalyzer& vloop_analyzer, Node* vn) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + Node* first = nodes().at(0); + + register_new_node_from_vectorization(vloop_analyzer, vn, first); + + for (int i = 0; i < _nodes.length(); i++) { + Node* n = _nodes.at(i); + phase->igvn().replace_node(n, vn); + } +} + +void VTransformNode::register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const { + PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); + phase->register_new_node_with_ctrl_of(vn, old_node); + phase->igvn()._worklist.push(vn); + VectorNode::trace_new_vector(vn, "AutoVectorization"); +} + +#ifndef PRODUCT +void VTransformGraph::print_vtnodes() const { + tty->print_cr("\nVTransformGraph::print_vtnodes:"); + for (int i = 0; i < _vtnodes.length(); i++) { + _vtnodes.at(i)->print(); + } +} + +void VTransformGraph::print_schedule() const { + tty->print_cr("\nVTransformGraph::print_schedule:"); + for (int i = 0; i < _schedule.length(); i++) { + tty->print(" %3d: ", i); + VTransformNode* vtn = _schedule.at(i); + if (vtn == nullptr) { + tty->print_cr("nullptr"); + } else { + vtn->print(); + } + } +} + +void VTransformGraph::print_memops_schedule() const { + tty->print_cr("\nVTransformGraph::print_memops_schedule:"); + int i = 0; + for_each_memop_in_schedule([&] (MemNode* mem) { + tty->print(" %3d: ", i++); + mem->dump(); + }); +} + +void VTransformNode::print() const { + tty->print("%3d %s (", _idx, name()); + for (uint i = 0; i < _req; i++) { + print_node_idx(_in.at(i)); + } + if ((uint)_in.length() > _req) { + tty->print(" |"); + for (int i = _req; i < _in.length(); i++) { + print_node_idx(_in.at(i)); + } + } + tty->print(") ["); + for (int i = 0; i < _out.length(); i++) { + print_node_idx(_out.at(i)); + } + tty->print("] "); + print_spec(); + tty->cr(); +} + +void VTransformNode::print_node_idx(const VTransformNode* vtn) { + if (vtn == nullptr) { + tty->print(" _"); + } else { + tty->print(" %d", vtn->_idx); + } +} + +void VTransformScalarNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformReplicateNode::print_spec() const { + tty->print("vlen=%d element_type=", _vlen); + _element_type->dump(); +} + +void VTransformShiftCountNode::print_spec() const { + tty->print("vlen=%d element_bt=%s mask=%d shift_opcode=%s", + _vlen, type2name(_element_bt), _mask, + NodeClassNames[_shift_opcode]); +} + +void VTransformPopulateIndexNode::print_spec() const { + tty->print("vlen=%d element_bt=%s", _vlen, type2name(_element_bt)); +} + +void VTransformVectorNode::print_spec() const { + tty->print("%d-pack[", _nodes.length()); + for (int i = 0; i < _nodes.length(); i++) { + Node* n = _nodes.at(i); + if (i > 0) { + tty->print(", "); + } + tty->print("%d %s", n->_idx, n->Name()); + } + tty->print("]"); +} +#endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp new file mode 100644 index 0000000000000..071674533a798 --- /dev/null +++ b/src/hotspot/share/opto/vtransform.hpp @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_OPTO_VTRANSFORM_HPP +#define SHARE_OPTO_VTRANSFORM_HPP + +#include "opto/node.hpp" +#include "opto/vectorization.hpp" + +// VTransform: +// - Models the transformation of the scalar loop to vectorized loop: +// It is a "C2 subgraph" -> "C2 subgraph" mapping. +// - The VTransform contains a graph (VTransformGraph), which consists of +// many vtnodes (VTransformNode). +// - Each vtnode models a part of the transformation, and is supposed +// to represent the output C2 nodes after the vectorization as closely +// as possible. +// +// This is the life-cycle of a VTransform: +// - Construction: +// - From SuperWord, with the SuperWordVTransformBuilder. +// +// - Future Plans: optimize, if-conversion, etc. +// +// - Schedule: +// - Compute linearization of the VTransformGraph, into an order that respects +// all edges in the graph (bailout if cycle detected). +// +// - Apply: +// - Changes to the C2 IR are only made once the "apply" method is called. +// - Each vtnode generates its corresponding scalar and vector C2 nodes, +// possibly replacing old scalar C2 nodes. +// +// Future Plans with VTransform: +// - Cost model: estimate if vectorization is profitable. +// - Optimizations: moving unordered reductions out of the loop, whih decreases cost. +// - Pack/Unpack/Shuffle: introduce additional nodes not present in the scalar loop. +// This is difficult to do with the SuperWord packset approach. +// - If-conversion: convert predicated nodes into CFG. + +typedef int VTransformNodeIDX; +class VTransformNode; +class VTransformScalarNode; +class VTransformInputScalarNode; +class VTransformVectorNode; +class VTransformElementWiseVectorNode; +class VTransformBoolVectorNode; +class VTransformReductionVectorNode; + +// Result from VTransformNode::apply +class VTransformApplyResult { +private: + Node* const _node; + const uint _vector_length; // number of elements + const uint _vector_width; // total width in bytes + + VTransformApplyResult(Node* n, uint vector_length, uint vector_width) : + _node(n), + _vector_length(vector_length), + _vector_width(vector_width) {} + +public: + static VTransformApplyResult make_scalar(Node* n) { + return VTransformApplyResult(n, 0, 0); + } + + static VTransformApplyResult make_vector(Node* n, uint vector_length, uint vector_width) { + assert(vector_length > 0 && vector_width > 0, "must have nonzero size"); + return VTransformApplyResult(n, vector_length, vector_width); + } + + static VTransformApplyResult make_empty() { + return VTransformApplyResult(nullptr, 0, 0); + } + + Node* node() const { return _node; } + uint vector_length() const { return _vector_length; } + uint vector_width() const { return _vector_width; } + NOT_PRODUCT( void trace(VTransformNode* vtnode) const; ) +}; + +#ifndef PRODUCT +// Convenience class for tracing flags. +class VTransformTrace { +public: + const bool _verbose; + const bool _rejections; + const bool _align_vector; + const bool _info; + + VTransformTrace(const VTrace& vtrace, + const bool is_trace_rejections, + const bool is_trace_align_vector, + const bool is_trace_info) : + _verbose (vtrace.is_trace(TraceAutoVectorizationTag::ALL)), + _rejections (_verbose | is_trace_vtransform(vtrace) | is_trace_rejections), + _align_vector(_verbose | is_trace_vtransform(vtrace) | is_trace_align_vector), + _info (_verbose | is_trace_vtransform(vtrace) | is_trace_info) {} + + static bool is_trace_vtransform(const VTrace& vtrace) { + return vtrace.is_trace(TraceAutoVectorizationTag::VTRANSFORM); + } +}; +#endif + +// VTransformGraph: component of VTransform +// See description at top of this file. +class VTransformGraph : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + const VLoop& _vloop; + + NOT_PRODUCT(const VTransformTrace _trace;) + + VTransformNodeIDX _next_idx; + GrowableArray _vtnodes; + + // Schedule (linearization) of the graph. We use this to reorder the memory graph + // before inserting vector operations. + GrowableArray _schedule; + +public: + VTransformGraph(const VLoopAnalyzer& vloop_analyzer, + Arena& arena + NOT_PRODUCT( COMMA const VTransformTrace trace)) : + _vloop_analyzer(vloop_analyzer), + _vloop(vloop_analyzer.vloop()), + NOT_PRODUCT(_trace(trace) COMMA) + _next_idx(0), + _vtnodes(&arena, _vloop.estimated_body_length(), 0, nullptr), + _schedule(&arena, _vloop.estimated_body_length(), 0, nullptr) {} + + VTransformNodeIDX new_idx() { return _next_idx++; } + void add_vtnode(VTransformNode* vtnode); + DEBUG_ONLY( bool is_empty() const { return _vtnodes.is_empty(); } ) + DEBUG_ONLY( bool is_scheduled() const { return _schedule.is_nonempty(); } ) + const GrowableArray& vtnodes() const { return _vtnodes; } + + bool schedule(); + void apply_memops_reordering_with_schedule() const; + void apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const; + +private: + // VLoop accessors + PhaseIdealLoop* phase() const { return _vloop.phase(); } + PhaseIterGVN& igvn() const { return _vloop.phase()->igvn(); } + bool in_bb(const Node* n) const { return _vloop.in_bb(n); } + + void collect_nodes_without_req_or_dependency(GrowableArray& stack) const; + + template + void for_each_memop_in_schedule(Callback callback) const; + +#ifndef PRODUCT + void print_vtnodes() const; + void print_schedule() const; + void print_memops_schedule() const; + void trace_schedule_cycle(const GrowableArray& stack, + const VectorSet& pre_visited, + const VectorSet& post_visited) const; +#endif +}; + +// VTransform: models the transformation of the scalar loop to vectorized loop. +// It is a "C2 subgraph" to "C2 subgraph" mapping. +// See description at top of this file. +class VTransform : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + const VLoop& _vloop; + + NOT_PRODUCT(const VTransformTrace _trace;) + + // Everything in the vtransform is allocated from this arena, including all vtnodes. + Arena _arena; + + VTransformGraph _graph; + + // Memory reference, and the alignment width (aw) for which we align the main-loop, + // by adjusting the pre-loop limit. + MemNode const* _mem_ref_for_main_loop_alignment; + int _aw_for_main_loop_alignment; + +public: + VTransform(const VLoopAnalyzer& vloop_analyzer, + MemNode const* mem_ref_for_main_loop_alignment, + int aw_for_main_loop_alignment + NOT_PRODUCT( COMMA const VTransformTrace trace) + ) : + _vloop_analyzer(vloop_analyzer), + _vloop(vloop_analyzer.vloop()), + NOT_PRODUCT(_trace(trace) COMMA) + _arena(mtCompiler), + _graph(_vloop_analyzer, _arena NOT_PRODUCT(COMMA _trace)), + _mem_ref_for_main_loop_alignment(mem_ref_for_main_loop_alignment), + _aw_for_main_loop_alignment(aw_for_main_loop_alignment) {} + + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + Arena* arena() { return &_arena; } + DEBUG_ONLY( bool has_graph() const { return !_graph.is_empty(); } ) + VTransformGraph& graph() { return _graph; } + + bool schedule() { return _graph.schedule(); } + void apply(); + +private: + // VLoop accessors + PhaseIdealLoop* phase() const { return _vloop.phase(); } + PhaseIterGVN& igvn() const { return _vloop.phase()->igvn(); } + IdealLoopTree* lpt() const { return _vloop.lpt(); } + CountedLoopNode* cl() const { return _vloop.cl(); } + int iv_stride() const { return cl()->stride_con(); } + + // VLoopVPointers accessors + const VPointer& vpointer(const MemNode* mem) const { + return _vloop_analyzer.vpointers().vpointer(mem); + } + + // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. + void determine_mem_ref_and_aw_for_main_loop_alignment(); + void adjust_pre_loop_limit_to_align_main_loop_vectors(); + + void apply_vectorization() const; +}; + +// The vtnodes (VTransformNode) resemble the C2 IR Nodes, and model a part of the +// VTransform. Many such vtnodes make up the VTransformGraph. The vtnodes represent +// the resulting scalar and vector nodes as closely as possible. +// See description at top of this file. +class VTransformNode : public ArenaObj { +public: + const VTransformNodeIDX _idx; + +private: + // _in is split into required inputs (_req), and additional dependencies. + const uint _req; + GrowableArray _in; + GrowableArray _out; + +public: + VTransformNode(VTransform& vtransform, const uint req) : + _idx(vtransform.graph().new_idx()), + _req(req), + _in(vtransform.arena(), req, req, nullptr), + _out(vtransform.arena(), 4, 0, nullptr) + { + vtransform.graph().add_vtnode(this); + } + + void set_req(uint i, VTransformNode* n) { + assert(i < _req, "must be a req"); + assert(_in.at(i) == nullptr && n != nullptr, "only set once"); + _in.at_put(i, n); + n->add_out(this); + } + + void swap_req(uint i, uint j) { + assert(i < _req, "must be a req"); + assert(j < _req, "must be a req"); + VTransformNode* tmp = _in.at(i); + _in.at_put(i, _in.at(j)); + _in.at_put(j, tmp); + } + + void add_dependency(VTransformNode* n) { + assert(n != nullptr, "no need to add nullptr"); + _in.push(n); + n->add_out(this); + } + + void add_out(VTransformNode* n) { + _out.push(n); + } + + uint req() const { return _req; } + VTransformNode* in(int i) const { return _in.at(i); } + int outs() const { return _out.length(); } + VTransformNode* out(int i) const { return _out.at(i); } + + bool has_req_or_dependency() const { + for (int i = 0; i < _in.length(); i++) { + if (_in.at(i) != nullptr) { return true; } + } + return false; + } + + virtual VTransformScalarNode* isa_Scalar() { return nullptr; } + virtual VTransformInputScalarNode* isa_InputScalar() { return nullptr; } + virtual VTransformVectorNode* isa_Vector() { return nullptr; } + virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } + virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } + virtual VTransformReductionVectorNode* isa_ReductionVector() { return nullptr; } + + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const = 0; + + Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; + + void register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const; + + NOT_PRODUCT(virtual const char* name() const = 0;) + NOT_PRODUCT(void print() const;) + NOT_PRODUCT(virtual void print_spec() const {};) + NOT_PRODUCT(static void print_node_idx(const VTransformNode* vtn);) +}; + +// Identity transform for scalar nodes. +class VTransformScalarNode : public VTransformNode { +private: + Node* _node; +public: + VTransformScalarNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) {} + Node* node() const { return _node; } + virtual VTransformScalarNode* isa_Scalar() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "Scalar"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Wrapper node for nodes outside the loop that are inputs to nodes in the loop. +// Since we want the loop-internal nodes to be able to reference all inputs as vtnodes, +// we must wrap the inputs that are outside the loop into special vtnodes, too. +class VTransformInputScalarNode : public VTransformScalarNode { +public: + VTransformInputScalarNode(VTransform& vtransform, Node* n) : + VTransformScalarNode(vtransform, n) {} + virtual VTransformInputScalarNode* isa_InputScalar() override { return this; } + NOT_PRODUCT(virtual const char* name() const override { return "InputScalar"; };) +}; + +// Transform produces a ReplicateNode, replicating the input to all vector lanes. +class VTransformReplicateNode : public VTransformNode { +private: + int _vlen; + const Type* _element_type; +public: + VTransformReplicateNode(VTransform& vtransform, int vlen, const Type* element_type) : + VTransformNode(vtransform, 2), _vlen(vlen), _element_type(element_type) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "Replicate"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Transform introduces a scalar ConvI2LNode that was not previously in the C2 graph. +class VTransformConvI2LNode : public VTransformNode { +public: + VTransformConvI2LNode(VTransform& vtransform) : VTransformNode(vtransform, 2) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ConvI2L"; };) +}; + +// Transform introduces a shift-count node that truncates the shift count for a vector shift. +class VTransformShiftCountNode : public VTransformNode { +private: + int _vlen; + const BasicType _element_bt; + juint _mask; + int _shift_opcode; +public: + VTransformShiftCountNode(VTransform& vtransform, int vlen, BasicType element_bt, juint mask, int shift_opcode) : + VTransformNode(vtransform, 2), _vlen(vlen), _element_bt(element_bt), _mask(mask), _shift_opcode(shift_opcode) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ShiftCount"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Transform introduces a PopulateIndex node: [phi, phi+1, phi+2, phi+3, ...]. +class VTransformPopulateIndexNode : public VTransformNode { +private: + int _vlen; + const BasicType _element_bt; +public: + VTransformPopulateIndexNode(VTransform& vtransform, int vlen, const BasicType element_bt) : + VTransformNode(vtransform, 2), _vlen(vlen), _element_bt(element_bt) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "PopulateIndex"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Base class for all vector vtnodes. +class VTransformVectorNode : public VTransformNode { +private: + GrowableArray _nodes; +public: + VTransformVectorNode(VTransform& vtransform, const uint req, const uint number_of_nodes) : + VTransformNode(vtransform, req), _nodes(vtransform.arena(), number_of_nodes, number_of_nodes, nullptr) {} + + void set_nodes(const Node_List* pack) { + for (uint k = 0; k < pack->size(); k++) { + _nodes.at_put(k, pack->at(k)); + } + } + + const GrowableArray& nodes() const { return _nodes; } + virtual VTransformVectorNode* isa_Vector() override { return this; } + void register_new_node_from_vectorization_and_replace_scalar_nodes(const VLoopAnalyzer& vloop_analyzer, Node* vn) const; + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Catch all for all element-wise vector operations. +class VTransformElementWiseVectorNode : public VTransformVectorNode { +public: + VTransformElementWiseVectorNode(VTransform& vtransform, uint req, uint number_of_nodes) : + VTransformVectorNode(vtransform, req, number_of_nodes) {} + virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) +}; + +struct VTransformBoolTest { + const BoolTest::mask _mask; + const bool _is_negated; + + VTransformBoolTest(const BoolTest::mask mask, bool is_negated) : + _mask(mask), _is_negated(is_negated) {} +}; + +class VTransformBoolVectorNode : public VTransformElementWiseVectorNode { +private: + const VTransformBoolTest _test; +public: + VTransformBoolVectorNode(VTransform& vtransform, uint number_of_nodes, VTransformBoolTest test) : + VTransformElementWiseVectorNode(vtransform, 2, number_of_nodes), _test(test) {} + VTransformBoolTest test() const { return _test; } + virtual VTransformBoolVectorNode* isa_BoolVector() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) +}; + +class VTransformReductionVectorNode : public VTransformVectorNode { +public: + // req = 3 -> [ctrl, scalar init, vector] + VTransformReductionVectorNode(VTransform& vtransform, uint number_of_nodes) : + VTransformVectorNode(vtransform, 3, number_of_nodes) {} + virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) +}; + +class VTransformLoadVectorNode : public VTransformVectorNode { +public: + // req = 3 -> [ctrl, mem, adr] + VTransformLoadVectorNode(VTransform& vtransform, uint number_of_nodes) : + VTransformVectorNode(vtransform, 3, number_of_nodes) {} + LoadNode::ControlDependency control_dependency() const; + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "LoadVector"; };) +}; + +class VTransformStoreVectorNode : public VTransformVectorNode { +public: + // req = 4 -> [ctrl, mem, adr, val] + VTransformStoreVectorNode(VTransform& vtransform, uint number_of_nodes) : + VTransformVectorNode(vtransform, 4, number_of_nodes) {} + virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, + const GrowableArray& vnode_idx_to_transformed_node) const override; + NOT_PRODUCT(virtual const char* name() const override { return "StoreVector"; };) +}; + +// Invoke callback on all memops, in the order of the schedule. +template +void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { + assert(_schedule.length() == _vtnodes.length(), "schedule was computed"); + + for (int i = 0; i < _schedule.length(); i++) { + VTransformNode* vtn = _schedule.at(i); + + // We can ignore input nodes, they are outside the loop. + if (vtn->isa_InputScalar() != nullptr) { continue; } + + VTransformScalarNode* scalar = vtn->isa_Scalar(); + if (scalar != nullptr && scalar->node()->is_Mem()) { + callback(scalar->node()->as_Mem()); + } + + VTransformVectorNode* vector = vtn->isa_Vector(); + if (vector != nullptr && vector->nodes().at(0)->is_Mem()) { + for (int j = 0; j < vector->nodes().length(); j++) { + callback(vector->nodes().at(j)->as_Mem()); + } + } + } +} + +#endif // SHARE_OPTO_VTRANSFORM_HPP From 55fd1ed228ea3c42aaf92579e5dcb818fe14351d Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Mon, 8 Jul 2024 06:42:46 +0000 Subject: [PATCH 183/288] 8333890: Fatal error in auto-vectorizer with float16 kernel. Reviewed-by: kvn --- src/hotspot/share/opto/superword.cpp | 6 ++ .../TestFloat16VectorConvChain.java | 65 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index ba2dd423bf51d..5721f7bcd5420 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2586,6 +2586,12 @@ const Type* VLoopTypes::container_type(Node* n) const { } const Type* t = _vloop.phase()->igvn().type(n); if (t->basic_type() == T_INT) { + // Float to half float conversion may be succeeded by a conversion from + // half float to float, in such a case back propagation of narrow type (SHORT) + // may not be possible. + if (n->Opcode() == Op_ConvF2HF) { + return TypeInt::SHORT; + } // A narrow type of arithmetic operations will be determined by // propagating the type of memory operations. return TypeInt::INT; diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java new file mode 100644 index 0000000000000..6b090c965bb8c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 Test Float16 vector conversion chain. +* @requires vm.compiler2.enabled +* @library /test/lib / +* @run driver compiler.vectorization.TestFloat16VectorConvChain +*/ + +package compiler.vectorization; + +import compiler.lib.ir_framework.*; +import java.util.Random; +import java.util.Arrays; + + +public class TestFloat16VectorConvChain { + + @Test + @IR(counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) + public static void test(short [] res, short [] src1, short [] src2) { + for (int i = 0; i < res.length; i++) { + res[i] = (short)Float.float16ToFloat(Float.floatToFloat16(Float.float16ToFloat(src1[i]) + Float.float16ToFloat(src2[i]))); + } + } + + @Run(test = {"test"}) + @Warmup(1000) + public static void micro() { + short [] res = new short[1024]; + short [] src1 = new short[1024]; + short [] src2 = new short[1024]; + Arrays.fill(src1, (short)Float.floatToFloat16(1.0f)); + Arrays.fill(src2, (short)Float.floatToFloat16(2.0f)); + for (int i = 0; i < 1000; i++) { + test(res, src1, src2); + } + } + + public static void main(String [] args) { + TestFramework.run(TestFloat16VectorConvChain.class); + } +} From 3cce31ad8877ec62429981871bcb0067770f9ccb Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 8 Jul 2024 08:06:56 +0000 Subject: [PATCH 184/288] 8335643: serviceability/dcmd/vm tests fail for ZGC after JDK-8322475 Reviewed-by: sgehwolf, dholmes --- test/hotspot/jtreg/ProblemList-generational-zgc.txt | 3 --- test/hotspot/jtreg/ProblemList-zgc.txt | 3 --- .../jtreg/serviceability/dcmd/vm/SystemMapTestBase.java | 4 +++- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index bdeed9947c571..db8182641ac54 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -114,7 +114,4 @@ serviceability/sa/sadebugd/PmapOnDebugdTest.java 8307393 generic- serviceability/sa/sadebugd/RunCommandOnServerTest.java 8307393 generic-all serviceability/sa/sadebugd/SADebugDTest.java 8307393 generic-all -serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all -serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all - vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 892c980b0696d..1afe56c99f8af 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -45,7 +45,4 @@ serviceability/sa/TestSysProps.java 8302055 generic- serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all -serviceability/dcmd/vm/SystemMapTest.java 8335643 generic-all -serviceability/dcmd/vm/SystemDumpMapTest.java 8335643 generic-all - vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java index 20dc8d70d7a47..000e977a590e5 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java @@ -42,6 +42,8 @@ public class SystemMapTestBase { private static final String regexBase_committed = regexBase + "com.*"; private static final String regexBase_shared_and_committed = regexBase + "shrd,com.*"; + // java heap is either committed, non-shared, or - in case of ZGC - committed and shared. + private static final String regexBase_java_heap = regexBase + "(shrd,)?com.*"; protected static final String shouldMatchUnconditionally[] = { // java launcher regexBase_committed + "/bin/java", @@ -54,7 +56,7 @@ public class SystemMapTestBase { }; protected static final String shouldMatchIfNMTIsEnabled[] = { - regexBase_committed + "JAVAHEAP.*", + regexBase_java_heap + "JAVAHEAP.*", // metaspace regexBase_committed + "META.*", // parts of metaspace should be uncommitted From 540188fdebd089d4145eca18c0f95bf338cbcefc Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Jul 2024 10:03:39 +0000 Subject: [PATCH 185/288] 8334445: Parallel: Decouple maximum compaction from SoftReference clearing Reviewed-by: zgu, lmao --- .../gc/parallel/parallelScavengeHeap.cpp | 6 +-- .../share/gc/parallel/psParallelCompact.cpp | 50 +++++++++---------- .../share/gc/parallel/psParallelCompact.hpp | 9 ++-- src/hotspot/share/gc/parallel/psScavenge.cpp | 4 +- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 665b14bb1eabf..33a499ce47134 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -441,11 +441,7 @@ HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) { } void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) { - // The do_full_collection() parameter clear_all_soft_refs - // is interpreted here as maximum_compaction which will - // cause SoftRefs to be cleared. - bool maximum_compaction = clear_all_soft_refs; - PSParallelCompact::invoke(maximum_compaction); + PSParallelCompact::invoke(clear_all_soft_refs); } // Failed allocation policy. Must be called from the VM thread, and diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index b4fe706d1e410..d4a24b710cfae 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -826,15 +826,21 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { } } -bool PSParallelCompact::reassess_maximum_compaction(bool maximum_compaction, - size_t total_live_words, - MutableSpace* const old_space, - HeapWord* full_region_prefix_end) { +bool PSParallelCompact::check_maximum_compaction(size_t total_live_words, + MutableSpace* const old_space, + HeapWord* full_region_prefix_end) { + + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + + // Check System.GC + bool is_max_on_system_gc = UseMaximumCompactionOnSystemGC + && GCCause::is_user_requested_gc(heap->gc_cause()); + // Check if all live objs are larger than old-gen. const bool is_old_gen_overflowing = (total_live_words > old_space->capacity_in_words()); // JVM flags - const uint total_invocations = ParallelScavengeHeap::heap()->total_full_collections(); + const uint total_invocations = heap->total_full_collections(); assert(total_invocations >= _maximum_compaction_gc_num, "sanity"); const size_t gcs_since_max = total_invocations - _maximum_compaction_gc_num; const bool is_interval_ended = gcs_since_max > HeapMaximumCompactionInterval; @@ -843,7 +849,7 @@ bool PSParallelCompact::reassess_maximum_compaction(bool maximum_compaction, const bool is_region_full = full_region_prefix_end >= _summary_data.region_align_down(old_space->top()); - if (maximum_compaction || is_old_gen_overflowing || is_interval_ended || is_region_full) { + if (is_max_on_system_gc || is_old_gen_overflowing || is_interval_ended || is_region_full) { _maximum_compaction_gc_num = total_invocations; return true; } @@ -851,7 +857,7 @@ bool PSParallelCompact::reassess_maximum_compaction(bool maximum_compaction, return false; } -void PSParallelCompact::summary_phase(bool maximum_compaction) +void PSParallelCompact::summary_phase() { GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); @@ -874,10 +880,9 @@ void PSParallelCompact::summary_phase(bool maximum_compaction) _space_info[i].set_dense_prefix(space->bottom()); } - maximum_compaction = reassess_maximum_compaction(maximum_compaction, - total_live_words, - old_space, - full_region_prefix_end); + bool maximum_compaction = check_maximum_compaction(total_live_words, + old_space, + full_region_prefix_end); HeapWord* dense_prefix_end = maximum_compaction ? full_region_prefix_end : compute_dense_prefix_for_old_space(old_space, @@ -958,26 +963,23 @@ void PSParallelCompact::summary_phase(bool maximum_compaction) // may be true because this method can be called without intervening // activity. For example when the heap space is tight and full measure // are being taken to free space. -bool PSParallelCompact::invoke(bool maximum_heap_compaction) { +bool PSParallelCompact::invoke(bool clear_all_soft_refs) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - assert(!heap->is_stw_gc_active(), "not reentrant"); - IsSTWGCActiveMark mark; - const bool clear_all_soft_refs = - heap->soft_ref_policy()->should_clear_all_soft_refs(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + clear_all_soft_refs = clear_all_soft_refs + || heap->soft_ref_policy()->should_clear_all_soft_refs(); - return PSParallelCompact::invoke_no_policy(clear_all_soft_refs || - maximum_heap_compaction); + return PSParallelCompact::invoke_no_policy(clear_all_soft_refs); } // This method contains no policy. You should probably // be calling invoke() instead. -bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { +bool PSParallelCompact::invoke_no_policy(bool clear_all_soft_refs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); assert(ref_processor() != nullptr, "Sanity"); @@ -998,7 +1000,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { // The scope of casr should end after code that can change // SoftRefPolicy::_should_clear_all_soft_refs. - ClearedAllSoftRefs casr(maximum_heap_compaction, + ClearedAllSoftRefs casr(clear_all_soft_refs, heap->soft_ref_policy()); // Make sure data structures are sane, make the heap parsable, and do other @@ -1033,7 +1035,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { DerivedPointerTable::clear(); #endif - ref_processor()->start_discovery(maximum_heap_compaction); + ref_processor()->start_discovery(clear_all_soft_refs); ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */, false /* unregister_nmethods_during_purge */, @@ -1041,9 +1043,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { marking_phase(&_gc_tracer); - bool max_on_system_gc = UseMaximumCompactionOnSystemGC - && GCCause::is_user_requested_gc(gc_cause); - summary_phase(maximum_heap_compaction || max_on_system_gc); + summary_phase(); #if COMPILER2_OR_JVMCI assert(DerivedPointerTable::is_active(), "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 93ea7aed78e9f..1e04beb8c66f6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -723,10 +723,9 @@ class PSParallelCompact : AllStatic { static void pre_compact(); static void post_compact(); - static bool reassess_maximum_compaction(bool maximum_compaction, - size_t total_live_words, - MutableSpace* const old_space, - HeapWord* full_region_prefix_end); + static bool check_maximum_compaction(size_t total_live_words, + MutableSpace* const old_space, + HeapWord* full_region_prefix_end); // Mark live objects static void marking_phase(ParallelOldTracer *gc_tracer); @@ -739,7 +738,7 @@ class PSParallelCompact : AllStatic { // make the heap parsable. static void fill_dense_prefix_end(SpaceId id); - static void summary_phase(bool maximum_compaction); + static void summary_phase(); static void adjust_pointers(); static void forward_to_new_addr(); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 865bbd170997d..708bb9da48af7 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -235,7 +235,6 @@ bool PSScavenge::invoke() { assert(!ParallelScavengeHeap::heap()->is_stw_gc_active(), "not reentrant"); ParallelScavengeHeap* const heap = ParallelScavengeHeap::heap(); - PSAdaptiveSizePolicy* policy = heap->size_policy(); IsSTWGCActiveMark mark; const bool scavenge_done = PSScavenge::invoke_no_policy(); @@ -250,8 +249,7 @@ bool PSScavenge::invoke() { if (need_full_gc) { GCCauseSetter gccs(heap, GCCause::_adaptive_size_policy); - SoftRefPolicy* srp = heap->soft_ref_policy(); - const bool clear_all_softrefs = srp->should_clear_all_soft_refs(); + const bool clear_all_softrefs = heap->soft_ref_policy()->should_clear_all_soft_refs(); full_gc_done = PSParallelCompact::invoke_no_policy(clear_all_softrefs); } From c5a668bb653feb3408a9efa3274ceabf9f01a2c7 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 8 Jul 2024 10:33:08 +0000 Subject: [PATCH 186/288] 8334231: Optimize MethodData layout Reviewed-by: dholmes, chagedorn, shade --- src/hotspot/share/oops/methodData.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index b6e2a1c965212..5071c29f1d774 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -1946,7 +1946,6 @@ class ciMethodData; class MethodData : public Metadata { friend class VMStructs; friend class JVMCIVMStructs; -private: friend class ProfileData; friend class TypeEntriesAtCall; friend class ciMethodData; @@ -2080,8 +2079,8 @@ class MethodData : public Metadata { #if INCLUDE_JVMCI // Support for HotSpotMethodData.setCompiledIRSize(int) - int _jvmci_ir_size; FailedSpeculation* _failed_speculations; + int _jvmci_ir_size; #endif // Size of _data array in bytes. (Excludes header and extra_data fields.) From c34a1b7013b27a8a214f63387bd528a90342a416 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 8 Jul 2024 10:53:03 +0000 Subject: [PATCH 187/288] 8335861: Problem list compiler/vectorization/TestFloat16VectorConvChain.java Reviewed-by: epeter --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d7088408ab887..76dc9f6f033fa 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -69,6 +69,8 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all +compiler/vectorization/TestFloat16VectorConvChain.java 8335860 generic-all + ############################################################################# # :hotspot_gc From 953c35eb5bff49ec5f7dbb25edd8a324b94318eb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 8 Jul 2024 11:44:04 +0000 Subject: [PATCH 188/288] 8335824: Test gc/arguments/TestMinInitialErgonomics.java is timing out Reviewed-by: ayang, kbarrett --- test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java index 6b03401a563df..6912499e53f00 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +27,7 @@ * @test TestMinInitialErgonomics * @bug 8006088 * @requires vm.gc.Parallel + * @requires vm.compMode != "Xcomp" * @summary Test Parallel GC ergonomics decisions related to minimum and initial heap size. * @library /test/lib * @library / From cec222e46065fc15db3f2eb241d3607d605ab580 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 8 Jul 2024 12:39:33 +0000 Subject: [PATCH 189/288] 8317611: Add a tool like jdeprscan to find usage of restricted methods Reviewed-by: alanb, ihse, mcimadamore, jlahoda, jwaters --- make/modules/jdk.jdeps/Launcher.gmk | 9 + .../javac/platform/JDKPlatformProvider.java | 11 +- .../share/classes/module-info.java | 8 +- .../classes/com/sun/tools/jdeprscan/Main.java | 4 +- .../tools/jnativescan/ClassFileSource.java | 124 +++++++++ .../sun/tools/jnativescan/ClassResolver.java | 163 +++++++++++ .../jnativescan/JNativeScanFatalError.java | 45 ++++ .../tools/jnativescan/JNativeScanTask.java | 195 ++++++++++++++ .../com/sun/tools/jnativescan/Main.java | 234 ++++++++++++++++ .../com/sun/tools/jnativescan/MethodRef.java | 48 ++++ .../tools/jnativescan/NativeMethodFinder.java | 141 ++++++++++ .../sun/tools/jnativescan/RestrictedUse.java | 32 +++ src/jdk.jdeps/share/classes/module-info.java | 23 +- src/jdk.jdeps/share/man/jnativescan.1 | 220 +++++++++++++++ test/jdk/tools/launcher/HelpFlagsTest.java | 1 + test/langtools/TEST.groups | 4 + .../jnativescan/JNativeScanTestBase.java | 86 ++++++ .../tools/jnativescan/TestArrayTypeRefs.java | 56 ++++ .../tools/jnativescan/TestJNativeScan.java | 252 ++++++++++++++++++ .../jnativescan/TestMissingSystemClass.java | 60 +++++ .../tools/jnativescan/TestSubclassRefs.java | 56 ++++ .../jnativescan/cases/classpath/app/App.java | 31 +++ .../cases/classpath/arrayref/App.java | 32 +++ .../jnativescan/cases/classpath/lib/Lib.java | 33 +++ .../cases/classpath/missingsystem/App.java | 32 +++ .../cases/classpath/singlejar/main/Main.java | 34 +++ .../cases/classpath/subclassref/App.java | 32 +++ .../unnamed_package/UnnamedPackage.java | 32 +++ .../cases/modules/org.lib/module-info.java | 26 ++ .../cases/modules/org.lib/org/lib/Lib.java | 34 +++ .../modules/org.lib/org/lib/Service.java | 26 ++ .../cases/modules/org.myapp/module-info.java | 28 ++ .../org.myapp/org/myapp/main/Main.java | 32 +++ .../modules/org.service/module-info.java | 27 ++ .../org.service/org/service/ServiceImpl.java | 35 +++ .../modules/org.singlejar/module-info.java | 25 ++ .../org/singlejar/main/Main.java | 34 +++ 37 files changed, 2250 insertions(+), 15 deletions(-) create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java create mode 100644 src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java create mode 100644 src/jdk.jdeps/share/man/jnativescan.1 create mode 100644 test/langtools/tools/jnativescan/JNativeScanTestBase.java create mode 100644 test/langtools/tools/jnativescan/TestArrayTypeRefs.java create mode 100644 test/langtools/tools/jnativescan/TestJNativeScan.java create mode 100644 test/langtools/tools/jnativescan/TestMissingSystemClass.java create mode 100644 test/langtools/tools/jnativescan/TestSubclassRefs.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/app/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java create mode 100644 test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java create mode 100644 test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java diff --git a/make/modules/jdk.jdeps/Launcher.gmk b/make/modules/jdk.jdeps/Launcher.gmk index ceab793124584..1aa54e16f4564 100644 --- a/make/modules/jdk.jdeps/Launcher.gmk +++ b/make/modules/jdk.jdeps/Launcher.gmk @@ -51,3 +51,12 @@ $(eval $(call SetupBuildLauncher, jdeprscan, \ MAIN_CLASS := com.sun.tools.jdeprscan.Main, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ )) + +################################################################################ +## Build jnativescan +################################################################################ + +$(eval $(call SetupBuildLauncher, jnativescan, \ + MAIN_CLASS := com.sun.tools.jnativescan.Main, \ + CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ +)) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java index 487fe969f9774..4c24f9892a673 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,14 @@ public Iterable getSupportedPlatformNames() { } @Override - public PlatformDescription getPlatform(String platformName, String options) { + public PlatformDescription getPlatform(String platformName, String options) throws PlatformNotSupported { + if (!SUPPORTED_JAVA_PLATFORM_VERSIONS.contains(platformName)) { + throw new PlatformNotSupported(); + } + return getPlatformTrusted(platformName); + } + + public PlatformDescription getPlatformTrusted(String platformName) { return new PlatformDescriptionImpl(platformName); } diff --git a/src/jdk.internal.opt/share/classes/module-info.java b/src/jdk.internal.opt/share/classes/module-info.java index 67ed1410560df..ba6987f1ea93c 100644 --- a/src/jdk.internal.opt/share/classes/module-info.java +++ b/src/jdk.internal.opt/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,13 @@ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, - jdk.jshell; + jdk.jshell, + jdk.jdeps; exports jdk.internal.opt to jdk.compiler, jdk.jartool, jdk.javadoc, jdk.jlink, - jdk.jpackage; + jdk.jpackage, + jdk.jdeps; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java index c67510de441da..f77d29a8bfa5b 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -414,7 +414,7 @@ boolean processRelease(String release, Collection classes) throws IOExce .noneMatch(n -> n.equals(release))) { return false; } - JavaFileManager fm = pp.getPlatform(release, "").getFileManager(); + JavaFileManager fm = pp.getPlatformTrusted(release).getFileManager(); List classNames = new ArrayList<>(); for (JavaFileObject fo : fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java new file mode 100644 index 0000000000000..754904c9c7f24 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassFileSource.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.JarFile; +import java.util.stream.Stream; +import java.util.zip.ZipFile; + +sealed interface ClassFileSource { + String moduleName(); + Path path(); + + Stream classFiles(Runtime.Version version) throws IOException; + + record Module(ModuleReference reference) implements ClassFileSource { + @Override + public String moduleName() { + return reference.descriptor().name(); + } + + @Override + public Path path() { + URI location = reference.location().orElseThrow(); + return Path.of(location); + } + + @Override + public Stream classFiles(Runtime.Version version) throws IOException { + ModuleReader reader = reference().open(); + return reader.list() + .filter(resourceName -> resourceName.endsWith(".class")) + .map(resourceName -> { + try (InputStream stream = reader.open(resourceName).orElseThrow()) { + return stream.readAllBytes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }).onClose(() -> { + try { + reader.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } + + record ClassPathJar(Path path) implements ClassFileSource { + @Override + public String moduleName() { + return "ALL-UNNAMED"; + } + + @Override + public Stream classFiles(Runtime.Version version) throws IOException { + JarFile jf = new JarFile(path().toFile(), false, ZipFile.OPEN_READ, version); + return jf.versionedStream() + .filter(je -> je.getName().endsWith(".class")) + .map(je -> { + try (InputStream stream = jf.getInputStream(je)){ + return stream.readAllBytes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }).onClose(() -> { + try { + jf.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } + + record ClassPathDirectory(Path path) implements ClassFileSource { + @Override + public String moduleName() { + return "ALL-UNNAMED"; + } + + @Override + public Stream classFiles(Runtime.Version version) throws IOException { + return Files.walk(path) + .filter(file -> Files.isRegularFile(file) && file.toString().endsWith(".class")) + .map(file -> { + try (InputStream stream = Files.newInputStream(file)){ + return stream.readAllBytes(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java new file mode 100644 index 0000000000000..7a267a58aa5a3 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/ClassResolver.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import com.sun.tools.javac.platform.PlatformDescription; +import com.sun.tools.javac.platform.PlatformProvider; + +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.constant.ClassDesc; +import java.lang.module.ModuleDescriptor; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +abstract class ClassResolver implements AutoCloseable { + + static ClassResolver forClassFileSources(List sources, Runtime.Version version) throws IOException { + Map classMap = new HashMap<>(); + for (ClassFileSource source : sources) { + try (Stream classFiles = source.classFiles(version)) { + classFiles.forEach(bytes -> { + ClassModel model = ClassFile.of().parse(bytes); + ClassDesc desc = model.thisClass().asSymbol(); + classMap.put(desc, new Info(source, model)); + }); + } + } + return new SimpleClassResolver(classMap); + } + + static ClassResolver forSystemModules(Runtime.Version version) { + String platformName = String.valueOf(version.feature()); + PlatformProvider platformProvider = ServiceLoader.load(PlatformProvider.class).findFirst().orElseThrow(); + PlatformDescription platform; + try { + platform = platformProvider.getPlatform(platformName, null); + } catch (PlatformProvider.PlatformNotSupported e) { + throw new JNativeScanFatalError("Release: " + platformName + " not supported", e); + } + JavaFileManager fm = platform.getFileManager(); + return new SystemModuleClassResolver(fm); + } + + record Info(ClassFileSource source, ClassModel model) {} + + public abstract void forEach(BiConsumer action); + public abstract Optional lookup(ClassDesc desc); + + @Override + public abstract void close() throws IOException; + + private static class SimpleClassResolver extends ClassResolver { + + private final Map classMap; + + public SimpleClassResolver(Map classMap) { + this.classMap = classMap; + } + + public void forEach(BiConsumer action) { + classMap.forEach(action); + } + + public Optional lookup(ClassDesc desc) { + return Optional.ofNullable(classMap.get(desc)); + } + + @Override + public void close() {} + } + + private static class SystemModuleClassResolver extends ClassResolver { + + private final JavaFileManager platformFileManager; + private final Map packageToSystemModule; + private final Map cache = new HashMap<>(); + + public SystemModuleClassResolver(JavaFileManager platformFileManager) { + this.platformFileManager = platformFileManager; + this.packageToSystemModule = packageToSystemModule(platformFileManager); + } + + private static Map packageToSystemModule(JavaFileManager platformFileManager) { + try { + Set locations = platformFileManager.listLocationsForModules( + StandardLocation.SYSTEM_MODULES).iterator().next(); + + Map result = new HashMap<>(); + for (JavaFileManager.Location loc : locations) { + JavaFileObject jfo = platformFileManager.getJavaFileForInput(loc, "module-info", JavaFileObject.Kind.CLASS); + ModuleDescriptor descriptor = ModuleDescriptor.read(jfo.openInputStream()); + for (ModuleDescriptor.Exports export : descriptor.exports()) { + if (!export.isQualified()) { + result.put(export.source(), descriptor.name()); + } + } + } + return result; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void forEach(BiConsumer action) { + throw new UnsupportedOperationException("NYI"); + } + + @Override + public Optional lookup(ClassDesc desc) { + return Optional.ofNullable(cache.computeIfAbsent(desc, _ -> { + String qualName = JNativeScanTask.qualName(desc); + String moduleName = packageToSystemModule.get(desc.packageName()); + if (moduleName != null) { + try { + JavaFileManager.Location loc = platformFileManager.getLocationForModule(StandardLocation.SYSTEM_MODULES, moduleName); + JavaFileObject jfo = platformFileManager.getJavaFileForInput(loc, qualName, JavaFileObject.Kind.CLASS); + if (jfo == null) { + throw new JNativeScanFatalError("System class can not be found: " + qualName); + } + ClassModel model = ClassFile.of().parse(jfo.openInputStream().readAllBytes()); + return new Info(null, model); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return null; + })); + } + + @Override + public void close() throws IOException { + platformFileManager.close(); + } + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java new file mode 100644 index 0000000000000..15cf86e03c333 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanFatalError.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import java.io.Serial; + +// Exception used in case of fatal error that is reasonably expected and handled. +public class JNativeScanFatalError extends RuntimeException { + @Serial + private static final long serialVersionUID = 1L; + + public JNativeScanFatalError(String message) { + super(message); + } + + public JNativeScanFatalError(String message, Throwable cause) { + super(message, cause); + } + + public JNativeScanFatalError(Throwable cause) { + super(cause); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java new file mode 100644 index 0000000000000..2ff172e9c1b71 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.constant.ClassDesc; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.module.ResolvedModule; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.zip.ZipFile; + +class JNativeScanTask { + + private final PrintWriter out; + private final List classPaths; + private final List modulePaths; + private final List cmdRootModules; + private final Runtime.Version version; + private final Action action; + + public JNativeScanTask(PrintWriter out, List classPaths, List modulePaths, + List cmdRootModules, Runtime.Version version, Action action) { + this.out = out; + this.classPaths = classPaths; + this.modulePaths = modulePaths; + this.version = version; + this.action = action; + this.cmdRootModules = cmdRootModules; + } + + public void run() throws JNativeScanFatalError { + List toScan = new ArrayList<>(findAllClassPathJars()); + + ModuleFinder moduleFinder = ModuleFinder.of(modulePaths.toArray(Path[]::new)); + List rootModules = cmdRootModules; + if (rootModules.contains("ALL-MODULE-PATH")) { + rootModules = allModuleNames(moduleFinder); + } + Configuration config = systemConfiguration().resolveAndBind(ModuleFinder.of(), moduleFinder, rootModules); + for (ResolvedModule m : config.modules()) { + toScan.add(new ClassFileSource.Module(m.reference())); + } + + SortedMap>> allRestrictedMethods; + try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version); + ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) { + NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver); + allRestrictedMethods = finder.findAll(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + switch (action) { + case PRINT -> printNativeAccess(allRestrictedMethods); + case DUMP_ALL -> dumpAll(allRestrictedMethods); + } + } + + private List findAllClassPathJars() throws JNativeScanFatalError { + List result = new ArrayList<>(); + for (Path path : classPaths) { + if (isJarFile(path)) { + Deque jarsToScan = new ArrayDeque<>(); + jarsToScan.offer(path); + + // recursively look for all class path jars, starting at the root jars + // in this.classPaths, and recursively following all Class-Path manifest + // attributes + while (!jarsToScan.isEmpty()) { + Path jar = jarsToScan.poll(); + String[] classPathAttribute = classPathAttribute(jar); + Path parentDir = jar.getParent(); + for (String classPathEntry : classPathAttribute) { + Path otherJar = parentDir != null + ? parentDir.resolve(classPathEntry) + : Path.of(classPathEntry); + if (Files.exists(otherJar)) { + // Class-Path attribute specifies that jars that + // are not found are simply ignored. Do the same here + jarsToScan.offer(otherJar); + } + } + result.add(new ClassFileSource.ClassPathJar(jar)); + } + } else if (Files.isDirectory(path)) { + result.add(new ClassFileSource.ClassPathDirectory(path)); + } else { + throw new JNativeScanFatalError( + "Path does not appear to be a jar file, or directory containing classes: " + path); + } + } + return result; + } + + private String[] classPathAttribute(Path jar) { + try (JarFile jf = new JarFile(jar.toFile(), false, ZipFile.OPEN_READ, version)) { + Manifest manifest = jf.getManifest(); + if (manifest != null) { + String attrib = manifest.getMainAttributes().getValue("Class-Path"); + if (attrib != null) { + return attrib.split("\\s+"); + } + } + return new String[0]; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Configuration systemConfiguration() { + ModuleFinder systemFinder = ModuleFinder.ofSystem(); + Configuration system = Configuration.resolve(systemFinder, List.of(Configuration.empty()), ModuleFinder.of(), + allModuleNames(systemFinder)); // resolve all of them + return system; + } + + private List allModuleNames(ModuleFinder finder) { + return finder.findAll().stream().map(mr -> mr.descriptor().name()).toList(); + } + + private void printNativeAccess(SortedMap>> allRestrictedMethods) { + String nativeAccess = allRestrictedMethods.keySet().stream() + .map(ClassFileSource::moduleName) + .distinct() + .collect(Collectors.joining(",")); + out.println(nativeAccess); + } + + private void dumpAll(SortedMap>> allRestrictedMethods) { + if (allRestrictedMethods.isEmpty()) { + out.println(" "); + } else { + allRestrictedMethods.forEach((module, perClass) -> { + out.println(module.path() + " (" + module.moduleName() + "):"); + perClass.forEach((classDesc, restrictedUses) -> { + out.println(" " + qualName(classDesc) + ":"); + restrictedUses.forEach(use -> { + switch (use) { + case RestrictedUse.NativeMethodDecl(MethodRef nmd) -> + out.println(" " + nmd + " is a native method declaration"); + case RestrictedUse.RestrictedMethodRefs(MethodRef referent, Set referees) -> { + out.println(" " + referent + " references restricted methods:"); + referees.forEach(referee -> out.println(" " + referee)); + } + } + }); + }); + }); + } + } + + private static boolean isJarFile(Path path) throws JNativeScanFatalError { + return Files.exists(path) && Files.isRegularFile(path) && path.toString().endsWith(".jar"); + } + + public enum Action { + DUMP_ALL, + PRINT + } + + public static String qualName(ClassDesc desc) { + String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + "."; + return packagePrefix + desc.displayName(); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java new file mode 100644 index 0000000000000..425a106d599f0 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import jdk.internal.joptsimple.*; +import jdk.internal.opt.CommandLine; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.spi.ToolProvider; + +public class Main { + + private static boolean DEBUG = Boolean.getBoolean("com.sun.tools.jnativescan.DEBUG"); + + private static final int SUCCESS_CODE = 0; + private static final int FATAL_ERROR_CODE = 1; + + private final PrintWriter out; + private final PrintWriter err; + + private Main(PrintWriter out, PrintWriter err) { + this.out = out; + this.err = err; + } + + private void printError(String message) { + err.println("ERROR: " + message); + } + + private void printUsage() { + out.print(""" + Use 'jnativescan --help' for help + """); + } + + private void printVersion() { + out.println(System.getProperty("java.version")); + } + + public int run(String[] args) { + if (args.length < 1) { + printUsage(); + return FATAL_ERROR_CODE; + } + + try { + String[] expandedArgs = expandArgFiles(args); + parseOptionsAndRun(expandedArgs); + } catch (JNativeScanFatalError fatalError) { + printError(fatalError.getMessage()); + for (Throwable cause = fatalError.getCause(); + cause instanceof JNativeScanFatalError jNativeScanFatalError; + cause = jNativeScanFatalError.getCause()) { + err.println("CAUSED BY: " + jNativeScanFatalError.getMessage()); + } + if (DEBUG) { + fatalError.printStackTrace(err); + } + return FATAL_ERROR_CODE; + } catch (Throwable e) { + printError("Unexpected exception encountered"); + e.printStackTrace(err); + return FATAL_ERROR_CODE; + } + + return SUCCESS_CODE; + } + + private void parseOptionsAndRun(String[] expandedArgs) throws JNativeScanFatalError { + OptionParser parser = new OptionParser(false); + OptionSpec helpOpt = parser.acceptsAll(List.of("?", "h", "help"), "help").forHelp(); + OptionSpec versionOpt = parser.accepts("version", "Print version information and exit"); + OptionSpec classPathOpt = parser.accepts( + "class-path", + "The class path as used at runtime") + .withRequiredArg() + .withValuesSeparatedBy(File.pathSeparatorChar) + .withValuesConvertedBy(PARSE_PATH); + OptionSpec modulePathOpt = parser.accepts( + "module-path", + "The module path as used at runtime") + .withRequiredArg() + .withValuesSeparatedBy(File.pathSeparatorChar) + .withValuesConvertedBy(PARSE_PATH); + OptionSpec releaseOpt = parser.accepts( + "release", + "The runtime version that will run the application") + .withRequiredArg() + .withValuesConvertedBy(PARSE_VERSION); + OptionSpec addModulesOpt = parser.accepts( + "add-modules", + "List of root modules to scan") + .requiredIf(modulePathOpt) + .withRequiredArg() + .withValuesSeparatedBy(','); + OptionSpec printNativeAccessOpt = parser.accepts( + "print-native-access", + "print a comma separated list of modules that may perform native access operations." + + " ALL-UNNAMED is used to indicate unnamed modules."); + + OptionSet optionSet; + try { + optionSet = parser.parse(expandedArgs); + } catch (OptionException oe) { + throw new JNativeScanFatalError("Parsing options failed: " + oe.getMessage(), oe); + } + + if (optionSet.nonOptionArguments().size() != 0) { + throw new JNativeScanFatalError("jnativescan does not accept positional arguments"); + } + + if (optionSet.has(helpOpt)) { + out.println(""" + The jnativescan tool can be used to find methods that may access native functionality when + run. This includes restricted method calls and 'native' method declarations. + """); + try { + parser.printHelpOn(out); + return; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + if (optionSet.has(versionOpt)) { + printVersion(); + return; + } + + List classPathJars = optionSet.valuesOf(classPathOpt); + List modulePaths = optionSet.valuesOf(modulePathOpt); + List rootModules = optionSet.valuesOf(addModulesOpt); + Runtime.Version version = Optional.ofNullable(optionSet.valueOf(releaseOpt)).orElse(Runtime.version()); + + JNativeScanTask.Action action = JNativeScanTask.Action.DUMP_ALL; + if (optionSet.has(printNativeAccessOpt)) { + action = JNativeScanTask.Action.PRINT; + } + + new JNativeScanTask(out, classPathJars, modulePaths, rootModules, version, action).run(); + } + + private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError { + try { + return CommandLine.parse(args); + } catch (IOException e) { // file not found + throw new JNativeScanFatalError(e.getMessage(), e); + } + } + + public static void main(String[] args) { + System.exit(new Main.Provider().run(System.out, System.err, args)); + } + + public static class Provider implements ToolProvider { + + @Override + public String name() { + return "jnativescan"; + } + + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + return new Main(out, err).run(args); + } + } + + // where + private static final ValueConverter PARSE_PATH = new ValueConverter<>() { + @Override + public Path convert(String value) { + return Path.of(value); + } + + @Override + public Class valueType() { + return Path.class; + } + + @Override + public String valuePattern() { + return "Path"; + } + }; + + private static final ValueConverter PARSE_VERSION = new ValueConverter<>() { + @Override + public Runtime.Version convert(String value) { + try { + return Runtime.Version.parse(value); + } catch (IllegalArgumentException e) { + throw new JNativeScanFatalError("Invalid release: " + value + ": " + e.getMessage()); + } + } + + @Override + public Class valueType() { + return Runtime.Version.class; + } + + @Override + public String valuePattern() { + return "Version"; + } + }; +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java new file mode 100644 index 0000000000000..b19e4e7ec8f2b --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/MethodRef.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import java.lang.classfile.MethodModel; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; + +record MethodRef(ClassDesc owner, String name, MethodTypeDesc type) { + public static MethodRef ofModel(MethodModel model) { + return new MethodRef(model.parent().orElseThrow().thisClass().asSymbol(), + model.methodName().stringValue(), model.methodTypeSymbol()); + } + + public static MethodRef ofInvokeInstruction(InvokeInstruction instruction) { + return new MethodRef(instruction.owner().asSymbol(), + instruction.name().stringValue(), instruction.typeSymbol()); + } + + @Override + public String toString() { + return JNativeScanTask.qualName(owner) + "::" + name + type.displayDescriptor(); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java new file mode 100644 index 0000000000000..681b954d4cdd9 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import com.sun.tools.jnativescan.RestrictedUse.NativeMethodDecl; +import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs; + +import java.io.IOException; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; +import java.util.*; + +class NativeMethodFinder { + + // ct.sym uses this fake name for the restricted annotation instead + // see make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java + private static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;"; + + private final Map cache = new HashMap<>(); + private final ClassResolver classesToScan; + private final ClassResolver systemClassResolver; + + private NativeMethodFinder(ClassResolver classesToScan, ClassResolver systemClassResolver) { + this.classesToScan = classesToScan; + this.systemClassResolver = systemClassResolver; + } + + public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException { + return new NativeMethodFinder(classesToScan, systemClassResolver); + } + + public SortedMap>> findAll() throws JNativeScanFatalError { + SortedMap>> restrictedMethods + = new TreeMap<>(Comparator.comparing(ClassFileSource::path)); + classesToScan.forEach((_, info) -> { + ClassModel classModel = info.model(); + List perClass = new ArrayList<>(); + classModel.methods().forEach(methodModel -> { + if (methodModel.flags().has(AccessFlag.NATIVE)) { + perClass.add(new NativeMethodDecl(MethodRef.ofModel(methodModel))); + } else { + SortedSet perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString)); + methodModel.code().ifPresent(code -> { + try { + code.forEach(e -> { + switch (e) { + case InvokeInstruction invoke -> { + MethodRef ref = MethodRef.ofInvokeInstruction(invoke); + if (isRestrictedMethod(ref)) { + perMethod.add(ref); + } + } + default -> { + } + } + }); + } catch (JNativeScanFatalError e) { + throw new JNativeScanFatalError("Error while processing method: " + + MethodRef.ofModel(methodModel), e); + } + }); + if (!perMethod.isEmpty()) { + perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod)); + } + } + }); + if (!perClass.isEmpty()) { + restrictedMethods.computeIfAbsent(info.source(), + _ -> new TreeMap<>(Comparator.comparing(JNativeScanTask::qualName))) + .put(classModel.thisClass().asSymbol(), perClass); + } + }); + return restrictedMethods; + } + + private boolean isRestrictedMethod(MethodRef ref) throws JNativeScanFatalError { + return cache.computeIfAbsent(ref, methodRef -> { + if (methodRef.owner().isArray()) { + // no restricted methods in arrays atm, and we can't look them up since they have no class file + return false; + } + Optional info = systemClassResolver.lookup(methodRef.owner()); + if (!info.isPresent()) { + return false; + } + ClassModel classModel = info.get().model(); + Optional methodModel = findMethod(classModel, methodRef.name(), methodRef.type()); + if (!methodModel.isPresent()) { + // If we are here, the method was referenced through a subclass of the class containing the actual + // method declaration. We could implement a method resolver (that needs to be version aware + // as well) to find the method model of the declaration, but it's not really worth it. + // None of the restricted methods (atm) are exposed through more than 1 public type, so it's not + // possible for user code to reference them through a subclass. + return false; + } + + return hasRestrictedAnnotation(methodModel.get()); + }); + } + + private static boolean hasRestrictedAnnotation(MethodModel method) { + return method.findAttribute(Attributes.runtimeVisibleAnnotations()) + .map(rva -> rva.annotations().stream().anyMatch(ann -> + ann.className().stringValue().equals(RESTRICTED_NAME))) + .orElse(false); + } + + private static Optional findMethod(ClassModel classModel, String name, MethodTypeDesc type) { + return classModel.methods().stream() + .filter(m -> m.methodName().stringValue().equals(name) + && m.methodType().stringValue().equals(type.descriptorString())) + .findFirst(); + } +} diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java new file mode 100644 index 0000000000000..58c5798d33f07 --- /dev/null +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/RestrictedUse.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.jnativescan; + +import java.util.SortedSet; + +sealed interface RestrictedUse { + record RestrictedMethodRefs(MethodRef referent, SortedSet referees) implements RestrictedUse {} + record NativeMethodDecl(MethodRef decl) implements RestrictedUse {} +} diff --git a/src/jdk.jdeps/share/classes/module-info.java b/src/jdk.jdeps/share/classes/module-info.java index e8ad319d70c55..3fdd3ca32d270 100644 --- a/src/jdk.jdeps/share/classes/module-info.java +++ b/src/jdk.jdeps/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,13 @@ /** * Defines tools for analysing dependencies in Java libraries and programs, * including the {@index jdeps jdeps tool}, - * {@index javap javap tool}, and - * {@index jdeprscan jdeprscan tool} tools. + * {@index javap javap tool}, + * {@index jdeprscan jdeprscan tool}, and + * {@index jnativescan jnativescan tool} tools. * *

    * This module provides the equivalent of command-line access to the - * javap and jdeps tools via the + * javap, jdeps, and jnativescan tools via the * {@link java.util.spi.ToolProvider ToolProvider} service provider * interface (SPI)

    * @@ -49,12 +50,14 @@ * @toolGuide javap * @toolGuide jdeprscan * @toolGuide jdeps + * @toolGuide jnativescan * * @provides java.util.spi.ToolProvider - * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")} - * or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")} + * Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")}, + * {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")}, + * or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jnativescan")} * to obtain an instance of a {@code ToolProvider} that provides the equivalent - * of command-line access to the {@code javap} or {@code jdeps} tool. + * of command-line access to the {@code javap}, {@code jdeps}, {@code jnativescan} tool. * * @moduleGraph * @since 9 @@ -63,10 +66,14 @@ module jdk.jdeps { requires java.compiler; requires jdk.compiler; + requires jdk.internal.opt; + + uses com.sun.tools.javac.platform.PlatformProvider; exports com.sun.tools.classfile to jdk.jlink; provides java.util.spi.ToolProvider with com.sun.tools.javap.Main.JavapToolProvider, - com.sun.tools.jdeps.Main.JDepsToolProvider; + com.sun.tools.jdeps.Main.JDepsToolProvider, + com.sun.tools.jnativescan.Main.Provider; } diff --git a/src/jdk.jdeps/share/man/jnativescan.1 b/src/jdk.jdeps/share/man/jnativescan.1 new file mode 100644 index 0000000000000..ff7f18277f260 --- /dev/null +++ b/src/jdk.jdeps/share/man/jnativescan.1 @@ -0,0 +1,220 @@ +.\" Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +.\" 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. +.\" +.\" Automatically generated by Pandoc 2.19.2 +.\" +.\" Define V font for inline verbatim, using C font in formats +.\" that render this, and otherwise B font. +.ie "\f[CB]x\f[R]"x" \{\ +. ftr V B +. ftr VI BI +. ftr VB B +. ftr VBI BI +.\} +.el \{\ +. ftr V CR +. ftr VI CI +. ftr VB CB +. ftr VBI CBI +.\} +.TH "JNATIVESCAN" "1" "2025" "JDK 24-ea" "JDK Commands" +.hy +.SH NAME +.PP +jnativescan - static analysis tool that scans one or more jar files for +uses of native functionalities, such as restricted method calls or +\f[V]native\f[R] method declarations. +.SH SYNOPSIS +.PP +\f[V]jnativescan\f[R] [\f[I]options\f[R]] +.TP +\f[I]options\f[R] +See \f[B]Options for the jnativescan Command\f[R] +.SH DESCRIPTION +.PP +The \f[V]jnative\f[R] tool is a static analysis tool provided by the JDK +that scans a JAR file for uses of native functionalities, such as +restricted method calls or \f[V]native\f[R] method declarations. +.PP +\f[V]jnativescan\f[R] accepts a runtime class path and module path +configuration, as well as a set of root modules, and a target release. +It scans the jars on the class and module paths, and reports uses of +native functionalities either in a tree like structure, which also +identifies that calling classes and methods, or as a list of module +names when the \f[V]--print-native-access\f[R] flag is specified. +.SH OPTIONS FOR THE JNATIVESCAN COMMAND +.PP +The following options are available: +.TP +\f[V]--class-path\f[R] \f[I]path\f[R] +Used to specify a list of paths pointing to jar files to be scanned. +.PP +All jar files specified through this list will be scanned. +If a jar file contains a \f[V]Class-Path\f[R] attribute in its manifest, +jar files listed there will be scanned as well. +Jar files listed in the \f[V]Class-Path\f[R] manifest attribute that can +not be found are ignored. +All the jar files found are treated as if they belonged to the unnamed +module. +.TP +\f[V]--module-path\f[R] \f[I]path\f[R] +Used to specify a list of paths pointing to jar files or directories +containing jar files, that the tool can use to find modules that need to +be scanned. +The list of jar files that will be scanned depends on the +\f[V]--add-modules\f[R] option. +.RS +.PP +For both the \f[V]--class-path\f[R] and \f[V]--module-path\f[R] options, +\f[I]path\f[R] should be a search path that consists of one or more jar +files, separated by the system-specific path separator. +For example: +.IP \[bu] 2 +\f[B]Linux and macOS:\f[R] +.RS 2 +.RS +.PP +\f[V]--class-path /some/foo.jar:/another/different/bar.jar\f[R] +.RE +.RE +.PP +\f[B]Note:\f[R] +.PP +On Windows, use a semicolon (\f[V];\f[R]) as the separator instead of a +colon (\f[V]:\f[R]). +.IP \[bu] 2 +\f[B]Windows:\f[R] +.RS 2 +.RS +.PP +\f[V]--class-path C:\[rs]some\[rs]foo.jar;C:\[rs]another\[rs]different\[rs]bar.jar\f[R] +.RE +.RE +.RE +.TP +\f[V]--add-modules\f[R] \f[I]module[,module...]\f[R] +Used to specify a comma-separated list of module names that indicate the +root modules to scan. +All the root modules will be scanned, as well as any modules that they +depend on. +This includes dependencies on service implementations specified through +the \f[V]uses\f[R] directive in a module\[aq]s \f[V]module-info\f[R] +file. +All modules found on the module path that provide an implementation of +such a service will be scanned as well. +.TP +\f[V]--release\f[R] \f[I]version\f[R] +Used to specify the Java SE release that specifies the set of restricted +methods to scan for. +For multi-release jar files, this option also indicates the version of +class file that should be loaded from the jar. +This option should be set to the version of the runtime under which the +application is eventually intended to be run. +If this flag is omitted, the version of \f[V]jnativescan\f[R] is used as +release version, which is the same as the version of the JDK that the +tool belongs to. +.TP +\f[V]--print-native-access\f[R] +Print a comma-separated list of module names that use native +functionalities, instead of the default tree structure. +.TP +\f[V]--help\f[R] or \f[V]-h\f[R] +Prints out a full help message. +.TP +\f[V]--version\f[R] +Prints out the abbreviated version string of the tool. +.SH EXAMPLE OF \f[V]jnativescan\f[R] USE +.PP +\f[V]jnativescan\f[R] accepts a runtime configuration in the form of a +class path, module path, set of root modules, and a target release +version. +For the class path, the tool will scan all jar files, including those +found recursively through the \f[V]Class-Path\f[R] manifest attribute. +For the module path, the tool scans all root modules specified through +\f[V]--add-modules\f[R], and any (transitive) dependence of the root +modules, including any modules that contain service implementations that +are used by a scanned module. +.PP +By default, the tool prints out which jars, classes, and methods use +native functionalities, in a tree-like structure. +The following is an example output: +.IP +.nf +\f[CB] +$ jnativescan --class-path app.jar +app.jar (ALL-UNNAMED): + foo.Main: + foo.Main::main(String[])void references restricted methods: + java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment + foo.Main::nativeMethod()void is a native method declaration +\f[R] +.fi +.PP +\f[V]app.jar (ALL-UNNAMED)\f[R] is the path to the jar file, with the +module name in parentheses behind it. +Since in this case the jar file appears on the class path, +\f[V]ALL-UNNAMED\f[R] is printed to indicate the unnamed module. +The second line of the output, \f[V]foo.Main\f[R], indicates that +methods using native functionalities were found in the +\f[V]foo.Main\f[R] class. +The next line: +.IP +.nf +\f[CB] + foo.Main::main(String[])void references restricted methods: +\f[R] +.fi +.PP +Indicates that the \f[V]main(String[])\f[R] method in the +\f[V]foo.Main\f[R] class references a restricted method, which is listed +on the following line as: +.IP +.nf +\f[CB] + java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment +\f[R] +.fi +.PP +Lastly, the text: +.IP +.nf +\f[CB] + foo.Main::nativeMethod()void is a native method declaration +\f[R] +.fi +.PP +Indicates that the \f[V]foo.Main\f[R] class contains a declaration of a +\f[V]native\f[R] method named \f[V]nativeMethod\f[R]. +.PP +If we add \f[V]--print-native-access\f[R] to the example command line, +we instead get a list of the names of modules that contain accesses to +native functionalities: +.IP +.nf +\f[CB] +$ jnativescan --class-path app.jar --print-native-access +ALL-UNNAMED +\f[R] +.fi +.PP +In this case the output consists of just \f[V]ALL-UNNAMED\f[R], which +indicates a jar file on the class path, that is, in the unnamed module, +contains an access to native functionalities. diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index dda649b9f41ba..15c6c101dd0c1 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.java @@ -141,6 +141,7 @@ private static class ToolHelpSpec { new ToolHelpSpec("jlink", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help new ToolHelpSpec("jmap", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. new ToolHelpSpec("jmod", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented. + new ToolHelpSpec("jnativescan", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. new ToolHelpSpec("jps", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jrunscript", 1, 1, 1, 0, 1, 1, 7), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jshell", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. diff --git a/test/langtools/TEST.groups b/test/langtools/TEST.groups index 74503501da9b9..e290a1431a3c5 100644 --- a/test/langtools/TEST.groups +++ b/test/langtools/TEST.groups @@ -63,6 +63,10 @@ langtools_jdeps = \ tools/all \ tools/jdeps +langtools_jnativescan = \ + tools/all \ + tools/jnativescan + langtools_slow = \ jdk/internal/shellsupport/doc/FullJavadocHelperTest.java diff --git a/test/langtools/tools/jnativescan/JNativeScanTestBase.java b/test/langtools/tools/jnativescan/JNativeScanTestBase.java new file mode 100644 index 0000000000000..97c0b21a738a2 --- /dev/null +++ b/test/langtools/tools/jnativescan/JNativeScanTestBase.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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.io.PrintWriter; +import java.nio.file.Path; +import java.util.Arrays; + +import java.io.StringWriter; +import java.util.spi.ToolProvider; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; + +public class JNativeScanTestBase { + + public static final String MODULE_PATH = "mods"; + + private static final ToolProvider JNATIVESCAN_TOOL = ToolProvider.findFirst("jnativescan") + .orElseThrow(() -> new RuntimeException("jnativescan tool not found")); + + public static OutputAnalyzer jnativescan(String... args) { + return run(JNATIVESCAN_TOOL, args); + } + + private static OutputAnalyzer run(ToolProvider tp, String[] commands) { + int rc; + StringWriter sw = new StringWriter(); + StringWriter esw = new StringWriter(); + + try (PrintWriter pw = new PrintWriter(sw); + PrintWriter epw = new PrintWriter(esw)) { + System.out.println("Running " + tp.name() + ", Command: " + Arrays.toString(commands)); + rc = tp.run(pw, epw, commands); + } + OutputAnalyzer output = new OutputAnalyzer(sw.toString(), esw.toString(), rc); + output.outputTo(System.out); + output.errorTo(System.err); + return output; + } + + public static Path makeModularJar(String moduleName) throws IOException { + Path jarPath = Path.of(MODULE_PATH, moduleName + ".jar"); + Path moduleRoot = moduleRoot(moduleName); + JarUtils.createJarFile(jarPath, moduleRoot); + return jarPath; + } + + public static Path moduleRoot(String name) { + return Path.of(System.getProperty("test.module.path")).resolve(name); + } + + public static OutputAnalyzer assertSuccess(OutputAnalyzer output) { + if (output.getExitValue() != 0) { + throw new IllegalStateException("tool run failed"); + } + return output; + } + + public static OutputAnalyzer assertFailure(OutputAnalyzer output) { + if (output.getExitValue() == 0) { + throw new IllegalStateException("tool run succeeded"); + } + return output; + } +} diff --git a/test/langtools/tools/jnativescan/TestArrayTypeRefs.java b/test/langtools/tools/jnativescan/TestArrayTypeRefs.java new file mode 100644 index 0000000000000..a439fdfdef967 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestArrayTypeRefs.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * cases.classpath.arrayref.App + * @run junit TestArrayTypeRefs + */ + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestArrayTypeRefs extends JNativeScanTestBase { + + static Path ARRAY_REF; + + @BeforeAll + public static void before() throws IOException { + ARRAY_REF = Path.of("arrayref.jar"); + Path testClasses = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(ARRAY_REF, testClasses, Path.of("arrayref", "App.class")); + } + + @Test + public void testSingleJarClassPath() { + assertSuccess(jnativescan("--class-path", ARRAY_REF.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain(""); + } +} diff --git a/test/langtools/tools/jnativescan/TestJNativeScan.java b/test/langtools/tools/jnativescan/TestJNativeScan.java new file mode 100644 index 0000000000000..94db492441263 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestJNativeScan.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * org.singlejar/* org.lib/* org.myapp/* org.service/* + * cases.classpath.singlejar.main.Main + * cases.classpath.lib.Lib + * cases.classpath.app.App + * cases.classpath.unnamed_package.UnnamedPackage + * @run junit TestJNativeScan + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class TestJNativeScan extends JNativeScanTestBase { + + static Path TEST_CLASSES; + + static Path CLASS_PATH_APP; + static Path SINGLE_JAR_CLASS_PATH; + static Path SINGLE_JAR_MODULAR; + static Path ORG_MYAPP; + static Path ORG_LIB; + static Path UNNAMED_PACKAGE_JAR; + static Path LIB_JAR; + + @BeforeAll + public static void before() throws IOException { + SINGLE_JAR_CLASS_PATH = Path.of("singleJar.jar"); + TEST_CLASSES = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(SINGLE_JAR_CLASS_PATH, TEST_CLASSES, Path.of("main", "Main.class")); + + LIB_JAR = Path.of("lib.jar"); + JarUtils.createJarFile(LIB_JAR, TEST_CLASSES, Path.of("lib", "Lib.class")); + Manifest manifest = new Manifest(); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); // need version or other attributes will be ignored + mainAttrs.putValue("Class-Path", "lib.jar non-existent.jar"); + CLASS_PATH_APP = Path.of("app.jar"); + JarUtils.createJarFile(CLASS_PATH_APP, manifest, TEST_CLASSES, Path.of("app", "App.class")); + + SINGLE_JAR_MODULAR = makeModularJar("org.singlejar"); + ORG_MYAPP = makeModularJar("org.myapp"); + ORG_LIB = makeModularJar("org.lib"); + makeModularJar("org.service"); + + UNNAMED_PACKAGE_JAR = Path.of("unnamed_package.jar"); + JarUtils.createJarFile(UNNAMED_PACKAGE_JAR, TEST_CLASSES, Path.of("UnnamedPackage.class")); + } + + @Test + public void testSingleJarClassPath() { + assertSuccess(jnativescan("--class-path", SINGLE_JAR_CLASS_PATH.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("main.Main") + .stdoutShouldContain("main.Main::m()void is a native method declaration") + .stdoutShouldContain("main.Main::main(String[])void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testSingleJarModulePath() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "org.singlejar")) + .stderrShouldBeEmpty() + .stdoutShouldContain("org.singlejar") + .stdoutShouldContain("org.singlejar.main.Main") + .stdoutShouldContain("org.singlejar.main.Main::m()void is a native method declaration") + .stdoutShouldContain("org.singlejar.main.Main::main(String[])void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testWithDepModule() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "org.myapp")) + .stderrShouldBeEmpty() + .stdoutShouldContain("org.lib") + .stdoutShouldContain("org.lib.Lib") + .stdoutShouldContain("org.lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("org.lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment") + .stdoutShouldContain("org.service") + .stdoutShouldContain("org.service.ServiceImpl") + .stdoutShouldContain("org.service.ServiceImpl::m()void is a native method declaration") + .stdoutShouldContain("org.service.ServiceImpl::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testAllModulePath() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH")) + .stderrShouldBeEmpty() + .stdoutShouldContain("org.singlejar") + .stdoutShouldContain("org.lib") + .stdoutShouldContain("org.service"); + } + + @Test + public void testClassPathAttribute() { + assertSuccess(jnativescan("--class-path", CLASS_PATH_APP.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain("lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testInvalidRelease() { + assertFailure(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH", "--release", "asdf")) + .stderrShouldContain("Invalid release"); + } + + @Test + public void testReleaseNotSupported() { + assertFailure(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH", "--release", "9999999")) + .stderrShouldContain("Release: 9999999 not supported"); + } + + @Test + public void testFileDoesNotExist() { + assertFailure(jnativescan("--class-path", "non-existent.jar")) + .stderrShouldContain("Path does not appear to be a jar file, or directory containing classes"); + } + + @Test + public void testModuleNotAJarFile() { + String modulePath = moduleRoot("org.myapp").toString() + File.pathSeparator + ORG_LIB.toString(); + assertSuccess(jnativescan("--module-path", modulePath, + "--add-modules", "ALL-MODULE-PATH")) + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain("lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testPrintNativeAccess() { + assertSuccess(jnativescan("--module-path", MODULE_PATH, + "-add-modules", "org.singlejar,org.myapp", + "--print-native-access")) + .stdoutShouldMatch("org.lib,org.service,org.singlejar"); + } + + @Test + public void testNoDuplicateNames() { + String classPath = SINGLE_JAR_CLASS_PATH + File.pathSeparator + CLASS_PATH_APP; + OutputAnalyzer output = assertSuccess(jnativescan("--class-path", classPath, "--print-native-access")); + String[] moduleNames = output.getStdout().split(","); + Set names = new HashSet<>(); + for (String name : moduleNames) { + assertTrue(names.add(name.strip())); + } + } + + @Test + public void testUnnamedPackage() { + assertSuccess(jnativescan("--class-path", UNNAMED_PACKAGE_JAR.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldNotContain(".UnnamedPackage") + .stdoutShouldContain("UnnamedPackage") + .stdoutShouldContain("UnnamedPackage::m()void is a native method declaration") + .stdoutShouldContain("UnnamedPackage::main(String[])void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testPositionalArguments() { + assertFailure(jnativescan("foo")) + .stdoutShouldBeEmpty() + .stderrShouldContain("jnativescan does not accept positional arguments"); + } + + @Test + public void testMissingRootModules() { + assertFailure(jnativescan("--module-path", MODULE_PATH)) + .stdoutShouldBeEmpty() + .stderrShouldContain("Missing required option(s) [add-modules]"); + } + + @Test + public void testClassPathDirectory() { + assertSuccess(jnativescan("--class-path", TEST_CLASSES.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("UnnamedPackage") + .stdoutShouldContain("UnnamedPackage::m()void is a native method declaration") + .stdoutShouldContain("UnnamedPackage::main(String[])void references restricted methods") + .stdoutShouldContain("main.Main") + .stdoutShouldContain("main.Main::m()void is a native method declaration") + .stdoutShouldContain("main.Main::main(String[])void references restricted methods") + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain("lib.Lib::m()void is a native method declaration") + .stdoutShouldContain("lib.Lib::doIt()void references restricted methods") + .stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment"); + } + + @Test + public void testMultipleClassPathJars() { + // make sure all of these are reported, even when they are all in the ALL-UNNAMED module + String classPath = UNNAMED_PACKAGE_JAR + + File.pathSeparator + SINGLE_JAR_CLASS_PATH + + File.pathSeparator + LIB_JAR; + assertSuccess(jnativescan("--class-path", classPath)) + .stderrShouldBeEmpty() + .stdoutShouldContain("ALL-UNNAMED") + .stdoutShouldContain("UnnamedPackage") + .stdoutShouldContain(UNNAMED_PACKAGE_JAR.toString()) + .stdoutShouldContain("lib.Lib") + .stdoutShouldContain(LIB_JAR.toString()) + .stdoutShouldContain("main.Main") + .stdoutShouldContain(SINGLE_JAR_CLASS_PATH.toString()); + } +} diff --git a/test/langtools/tools/jnativescan/TestMissingSystemClass.java b/test/langtools/tools/jnativescan/TestMissingSystemClass.java new file mode 100644 index 0000000000000..5806590d0e081 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestMissingSystemClass.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * @compile --release 20 cases/classpath/missingsystem/App.java + * @run junit TestMissingSystemClass + */ + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestMissingSystemClass extends JNativeScanTestBase { + + static Path MISSING_SYSTEM; + + @BeforeAll + public static void before() throws IOException { + MISSING_SYSTEM = Path.of("missingsystem.jar"); + Path testClasses = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(MISSING_SYSTEM, testClasses, Path.of("missingsystem", "App.class")); + } + + @Test + public void testSingleJarClassPath() { + assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21")) + .stdoutShouldBeEmpty() + .stderrShouldContain("Error while processing method") + .stderrShouldContain("missingsystem.App::main(String[])void") + .stderrShouldContain("CAUSED BY:") + .stderrShouldContain("System class can not be found") + .stderrShouldContain("java.lang.Compiler"); + } +} diff --git a/test/langtools/tools/jnativescan/TestSubclassRefs.java b/test/langtools/tools/jnativescan/TestSubclassRefs.java new file mode 100644 index 0000000000000..c8eed0439ee75 --- /dev/null +++ b/test/langtools/tools/jnativescan/TestSubclassRefs.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib .. ./cases/modules + * @build JNativeScanTestBase + * cases.classpath.subclassref.App + * @run junit TestSubclassRefs + */ + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestSubclassRefs extends JNativeScanTestBase { + + static Path SUBCLASS_REF; + + @BeforeAll + public static void before() throws IOException { + SUBCLASS_REF = Path.of("subclassref.jar"); + Path testClasses = Path.of(System.getProperty("test.classes", "")); + JarUtils.createJarFile(SUBCLASS_REF, testClasses, Path.of("subclassref", "App.class")); + } + + @Test + public void testSingleJarClassPath() { + assertSuccess(jnativescan("--class-path", SUBCLASS_REF.toString())) + .stderrShouldBeEmpty() + .stdoutShouldContain(""); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/app/App.java b/test/langtools/tools/jnativescan/cases/classpath/app/App.java new file mode 100644 index 0000000000000..f96ab11e5764a --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/app/App.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package app; + +import lib.Lib; + +public class App { + public static void main(String[] args) { + Lib.doIt(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java b/test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java new file mode 100644 index 0000000000000..aa480f392fbf2 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/arrayref/App.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package arrayref; + +public class App { + public static void main(String[] args) { + // reference an array method to see that + // RestrictedMethodFinder correctly handles + // references to array methods + args.clone(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java b/test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java new file mode 100644 index 0000000000000..ec92696364c9d --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/lib/Lib.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package lib; + +import java.lang.foreign.MemorySegment; + +public class Lib { + public static void doIt() { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java new file mode 100644 index 0000000000000..0e20fe81eecd0 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package missingsystem; + +public class App { + public static void main(String[] args) { + // this class was present in Java 20, but removed in 21 + // if we compile with --release 20, but run jnativescan + // with --release 21, we should get an error + java.lang.Compiler.enable(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java b/test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java new file mode 100644 index 0000000000000..280e8646f9ff4 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/singlejar/main/Main.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package main; + +import java.lang.foreign.*; + +public class Main { + public static void main(String[] args) { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java b/test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java new file mode 100644 index 0000000000000..abe9e41265e4c --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/subclassref/App.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package subclassref; + +import java.util.List; + +public class App { + public static void main(String[] args) { + List l = List.of(args); + l.stream(); // List does not declare stream() + } +} diff --git a/test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java b/test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java new file mode 100644 index 0000000000000..4e8dfe69b5a19 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/classpath/unnamed_package/UnnamedPackage.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.foreign.*; + +public class UnnamedPackage { + public static void main(String[] args) { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java new file mode 100644 index 0000000000000..8572ed80e431d --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.lib/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module org.lib { + exports org.lib; +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java new file mode 100644 index 0000000000000..3f9ea0e1ada26 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Lib.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.lib; + +import java.lang.foreign.*; + +public class Lib { + public static void doIt() { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java new file mode 100644 index 0000000000000..2e406d926a662 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.lib/org/lib/Service.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.lib; + +public interface Service { +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java new file mode 100644 index 0000000000000..8155fb5d8f260 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.myapp/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module org.myapp { + requires org.lib; + + uses org.lib.Service; +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java b/test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java new file mode 100644 index 0000000000000..c2329b2ceeb2f --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.myapp/org/myapp/main/Main.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.myapp.main; + +import org.lib.Lib; + +public class Main { + public static void main(String[] args) { + Lib.doIt(); + } +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java new file mode 100644 index 0000000000000..431dd64172dd4 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.service/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +module org.service { + requires org.lib; + + provides org.lib.Service with org.service.ServiceImpl; +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java b/test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java new file mode 100644 index 0000000000000..6e643f1c649f1 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.service/org/service/ServiceImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.service; + +import org.lib.Service; + +import java.lang.foreign.MemorySegment; + +public class ServiceImpl implements Service { + public void doIt() { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private native void m(); +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java new file mode 100644 index 0000000000000..c9f96e4f77147 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +module org.singlejar { + +} diff --git a/test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java new file mode 100644 index 0000000000000..c6925eaf64996 --- /dev/null +++ b/test/langtools/tools/jnativescan/cases/modules/org.singlejar/org/singlejar/main/Main.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.singlejar.main; + +import java.lang.foreign.*; + +public class Main { + public static void main(String[] args) { + MemorySegment.ofAddress(1234).reinterpret(10); + } + + private static native void m(); +} From be3676f6bbc2d8041e43cf7bcfaee7fb9d864378 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 8 Jul 2024 14:04:32 +0000 Subject: [PATCH 190/288] 8304484: CDS dynamic dumping incorrectly leads to "Error occurred during initialization of VM" Reviewed-by: ccheung, iklam --- src/hotspot/share/classfile/classLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 910cbe48c5c19..e410824e3001c 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -470,7 +470,7 @@ bool ClassPathImageEntry::is_modules_image() const { void ClassLoader::exit_with_path_failure(const char* error, const char* message) { assert(CDSConfig::is_dumping_archive(), "sanity"); tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure"); - vm_exit_during_initialization(error, message); + vm_exit_during_cds_dumping(error, message); } #endif From d8c1c6ab0543c986280dcfa1c6c79e010a7b35fb Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Jul 2024 15:45:26 +0000 Subject: [PATCH 191/288] 8335604: Serial: Inline Generation::contiguous_available Reviewed-by: tschatzl --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 5 ----- src/hotspot/share/gc/serial/defNewGeneration.hpp | 2 -- src/hotspot/share/gc/serial/generation.hpp | 4 ---- src/hotspot/share/gc/serial/tenuredGeneration.cpp | 6 +----- src/hotspot/share/gc/serial/tenuredGeneration.hpp | 2 -- 5 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index acf7e23910367..715b82fd38d32 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -533,11 +533,6 @@ size_t DefNewGeneration::capacity_before_gc() const { return eden()->capacity(); } -size_t DefNewGeneration::contiguous_available() const { - return eden()->free(); -} - - void DefNewGeneration::object_iterate(ObjectClosure* blk) { eden()->object_iterate(blk); from()->object_iterate(blk); diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index a7ee555902a25..011b79fdabd6b 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -172,8 +172,6 @@ class DefNewGeneration: public Generation { // heuristic resizing decisions. size_t unsafe_max_alloc_nogc() const; - size_t contiguous_available() const; - size_t max_eden_size() const { return _max_eden_size; } size_t max_survivor_size() const { return _max_survivor_size; } diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index 5e5aad5d0c1b2..a757c97c5cb15 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -96,10 +96,6 @@ class Generation: public CHeapObj { // for the allocation of objects. virtual size_t max_capacity() const; - // The largest number of contiguous free bytes in the generation, - // including expansion (Assumes called at a safepoint.) - virtual size_t contiguous_available() const = 0; - MemRegion reserved() const { return _reserved; } /* Returns "TRUE" iff "p" points into the reserved area of the generation. */ diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index f1389b48557f8..b1b7507094771 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -377,7 +377,7 @@ void TenuredGeneration::update_counters() { } bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const { - size_t available = contiguous_available(); + size_t available = _the_space->free() + _virtual_space.uncommitted_size(); size_t av_promo = (size_t)_avg_promoted->padded_average(); bool res = (available >= av_promo) || (available >= max_promotion_in_bytes); @@ -413,10 +413,6 @@ TenuredGeneration::expand_and_allocate(size_t word_size, bool is_tlab) { return allocate(word_size, is_tlab); } -size_t TenuredGeneration::contiguous_available() const { - return _the_space->free() + _virtual_space.uncommitted_size(); -} - void TenuredGeneration::assert_correct_size_change_locking() { assert_locked_or_safepoint(Heap_lock); } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index bcb2d668213e8..dcec912d4887f 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -124,8 +124,6 @@ class TenuredGeneration: public Generation { const char* name() const { return "tenured generation"; } const char* short_name() const { return "Tenured"; } - size_t contiguous_available() const; - // Iteration void object_iterate(ObjectClosure* blk); From a9b7f42f29120a3cca0d341350ff03cae485e68b Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 8 Jul 2024 16:20:01 +0000 Subject: [PATCH 192/288] 8333826: Update --release 23 symbol information for JDK 23 build 29 Reviewed-by: iris, jlahoda --- src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt index fdc899578cf82..577ff91c7caad 100644 --- a/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.desktop-N.sym.txt @@ -119,6 +119,10 @@ class name javax/swing/JScrollBar method name setMinimumSize descriptor (Ljava/awt/Dimension;)V flags 1 method name setMaximumSize descriptor (Ljava/awt/Dimension;)V flags 1 +class name javax/swing/plaf/basic/BasicSliderUI +-method name descriptor ()V +method name descriptor ()V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="23") + class name javax/swing/plaf/synth/SynthTreeUI method name getCollapsedIcon descriptor ()Ljavax/swing/Icon; flags 1 From 284671a1e4fb5bfe15b20b7f41fc24415b1235ed Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 8 Jul 2024 16:44:22 +0000 Subject: [PATCH 193/288] 8335449: runtime/cds/DeterministicDump.java fails with File content different at byte ... Reviewed-by: matsaave, iklam --- test/hotspot/jtreg/runtime/cds/DeterministicDump.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 8f9bb4a582985..cc8d8c2b1dde9 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -25,7 +25,7 @@ * @test * @bug 8241071 * @summary The same JDK build should always generate the same archive file (no randomness). - * @requires vm.cds + * @requires vm.cds & vm.flagless * @library /test/lib * @run driver DeterministicDump */ From 3a87eb5c4606ce39970962895315567e8606eba7 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Mon, 8 Jul 2024 18:03:19 +0000 Subject: [PATCH 194/288] 8335126: Shenandoah: Improve OOM handling Reviewed-by: shade, ysr, wkemper, rkennke --- .../gc/shenandoah/shenandoahControlThread.cpp | 3 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 1 - .../share/gc/shenandoah/shenandoahHeap.cpp | 48 ++++++++++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index e538ca024678f..95a70de5790e9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -318,7 +318,8 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau ShenandoahConcurrentGC gc; if (gc.collect(cause)) { - // Cycle is complete + // Cycle is complete. There were no failed allocation requests and no degeneration, so count this as good progress. + heap->notify_gc_progress(); heap->heuristics()->record_success_concurrent(); heap->shenandoah_policy()->record_success_concurrent(gc.abbreviated()); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index fb5283bb1d88d..6b597d9b2d7b3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -228,7 +228,6 @@ void ShenandoahDegenGC::op_degenerated() { // Check for futility and fail. There is no reason to do several back-to-back Degenerated cycles, // because that probably means the heap is overloaded and/or fragmented. if (!metrics.is_good_progress()) { - heap->notify_gc_no_progress(); heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc); op_degenerated_futile(); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index ee3f4e7d8eb8c..5c5b6f7ebe58d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -945,24 +945,36 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { return nullptr; } - // Block until control thread reacted, then retry allocation. - // - // It might happen that one of the threads requesting allocation would unblock - // way later after GC happened, only to fail the second allocation, because - // other threads have already depleted the free storage. In this case, a better - // strategy is to try again, as long as GC makes progress (or until at least - // one full GC has completed). - size_t original_count = shenandoah_policy()->full_gc_count(); - while (result == nullptr - && (get_gc_no_progress_count() == 0 || original_count == shenandoah_policy()->full_gc_count())) { - control_thread()->handle_alloc_failure(req, true); - result = allocate_memory_under_lock(req, in_new_region); - } - - if (log_is_enabled(Debug, gc, alloc)) { - ResourceMark rm; - log_debug(gc, alloc)("Thread: %s, Result: " PTR_FORMAT ", Request: %s, Size: " SIZE_FORMAT ", Original: " SIZE_FORMAT ", Latest: " SIZE_FORMAT, - Thread::current()->name(), p2i(result), req.type_string(), req.size(), original_count, get_gc_no_progress_count()); + if (result == nullptr) { + // Block until control thread reacted, then retry allocation. + // + // It might happen that one of the threads requesting allocation would unblock + // way later after GC happened, only to fail the second allocation, because + // other threads have already depleted the free storage. In this case, a better + // strategy is to try again, until at least one full GC has completed. + // + // Stop retrying and return nullptr to cause OOMError exception if our allocation failed even after: + // a) We experienced a GC that had good progress, or + // b) We experienced at least one Full GC (whether or not it had good progress) + // + // TODO: Consider GLOBAL GC rather than Full GC to remediate OOM condition: https://bugs.openjdk.org/browse/JDK-8335910 + + size_t original_count = shenandoah_policy()->full_gc_count(); + while ((result == nullptr) && (original_count == shenandoah_policy()->full_gc_count())) { + control_thread()->handle_alloc_failure(req, true); + result = allocate_memory_under_lock(req, in_new_region); + } + if (result != nullptr) { + // If our allocation request has been satisifed after it initially failed, we count this as good gc progress + notify_gc_progress(); + } + if (log_is_enabled(Debug, gc, alloc)) { + ResourceMark rm; + log_debug(gc, alloc)("Thread: %s, Result: " PTR_FORMAT ", Request: %s, Size: " SIZE_FORMAT + ", Original: " SIZE_FORMAT ", Latest: " SIZE_FORMAT, + Thread::current()->name(), p2i(result), req.type_string(), req.size(), + original_count, get_gc_no_progress_count()); + } } } else { assert(req.is_gc_alloc(), "Can only accept GC allocs here"); From 3733fe3a207078b585421cd2a098e808fafaa817 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Mon, 8 Jul 2024 19:14:33 +0000 Subject: [PATCH 195/288] 8335789: [TESTBUG] XparColor.java test fails with Error. Parse Exception: Invalid or unrecognized bugid: @ Reviewed-by: aivanov --- test/jdk/java/awt/print/PrinterJob/XparColor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/XparColor.java b/test/jdk/java/awt/print/PrinterJob/XparColor.java index 9a85a78af558a..30713b1424e53 100644 --- a/test/jdk/java/awt/print/PrinterJob/XparColor.java +++ b/test/jdk/java/awt/print/PrinterJob/XparColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @bug 4179262 - @ @key printer + * @key printer * @summary Confirm that transparent colors are printed correctly. The * printout should show transparent rings with increasing darkness toward * the center. From babf6df7d97e4beedb25e689634d999412c1e950 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 8 Jul 2024 20:09:07 +0000 Subject: [PATCH 196/288] 8334757: AssertionError: Missing type variable in where clause Reviewed-by: jlahoda, vromero --- .../javac/util/RichDiagnosticFormatter.java | 3 +++ .../CantAnnotateClassWithTypeVariable.java | 19 +++++++++++++++++++ .../CantAnnotateClassWithTypeVariable.out | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java index e1faa02bd38af..3bc5c671bfda2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java @@ -184,6 +184,9 @@ protected void preprocessArgument(Object arg) { if (arg instanceof Type type) { preprocessType(type); } + else if (arg instanceof JCDiagnostic.AnnotatedType type) { + preprocessType(type.type()); + } else if (arg instanceof Symbol symbol) { preprocessSymbol(symbol); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java new file mode 100644 index 0000000000000..8d575caec57c2 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.java @@ -0,0 +1,19 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8334757 + * @compile/fail/ref=CantAnnotateClassWithTypeVariable.out -XDrawDiagnostics CantAnnotateClassWithTypeVariable.java + */ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +public class CantAnnotateClassWithTypeVariable { + @Target(ElementType.TYPE_USE) + @interface TA {} + + static class A { + static class B {} + } + + @TA A.B f() {} +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out new file mode 100644 index 0000000000000..80fa9f2cdd9c9 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateClassWithTypeVariable.out @@ -0,0 +1,2 @@ +CantAnnotateClassWithTypeVariable.java:18:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @CantAnnotateClassWithTypeVariable.TA), CantAnnotateClassWithTypeVariable.A, @CantAnnotateClassWithTypeVariable.TA CantAnnotateClassWithTypeVariable.A.B +1 error From bb1f8a1698553d5962569ac8912edd0d7ef010dd Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 8 Jul 2024 20:10:27 +0000 Subject: [PATCH 197/288] 8335904: Fix invalid comment in ShenandoahLock Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahLock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp index 6fc74c53e6390..63c6c9ea88624 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp @@ -44,7 +44,7 @@ void ShenandoahLock::contended_lock(bool allow_block_for_safepoint) { template void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) { assert(!ALLOW_BLOCK || java_thread != nullptr, "Must have a Java thread when allowing block."); - // Spin this much on multi-processor, do not spin on multi-processor. + // Spin this much, but only on multi-processor systems. int ctr = os::is_MP() ? 0xFF : 0; // Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread. while (Atomic::load(&_state) == locked || From 9c7a6eabb93c570fdb74076edc931576ed6be3e0 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 8 Jul 2024 20:14:26 +0000 Subject: [PATCH 198/288] 8312125: Refactor CDS enum class handling Reviewed-by: matsaave, ccheung --- src/hotspot/share/cds/cdsEnumKlass.cpp | 136 +++++++++++++++++++++++ src/hotspot/share/cds/cdsEnumKlass.hpp | 50 +++++++++ src/hotspot/share/cds/heapShared.cpp | 94 +--------------- src/hotspot/share/cds/heapShared.hpp | 4 - src/hotspot/share/oops/instanceKlass.cpp | 3 +- 5 files changed, 192 insertions(+), 95 deletions(-) create mode 100644 src/hotspot/share/cds/cdsEnumKlass.cpp create mode 100644 src/hotspot/share/cds/cdsEnumKlass.hpp diff --git a/src/hotspot/share/cds/cdsEnumKlass.cpp b/src/hotspot/share/cds/cdsEnumKlass.cpp new file mode 100644 index 0000000000000..b77f2fd9d16ad --- /dev/null +++ b/src/hotspot/share/cds/cdsEnumKlass.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "cds/archiveHeapLoader.hpp" +#include "cds/cdsEnumKlass.hpp" +#include "cds/heapShared.hpp" +#include "classfile/vmClasses.hpp" +#include "classfile/systemDictionaryShared.hpp" +#include "memory/resourceArea.hpp" +#include "oops/fieldStreams.inline.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/fieldDescriptor.inline.hpp" + +#if INCLUDE_CDS_JAVA_HEAP + +bool CDSEnumKlass::is_enum_obj(oop orig_obj) { + Klass* k = orig_obj->klass(); + Klass* buffered_k = ArchiveBuilder::get_buffered_klass(k); + return k->is_instance_klass() && + InstanceKlass::cast(k)->java_super() == vmClasses::Enum_klass(); +} + +// -- Handling of Enum objects +// Java Enum classes have synthetic methods that look like this +// enum MyEnum {FOO, BAR} +// MyEnum:: { +// /*static final MyEnum*/ MyEnum::FOO = new MyEnum("FOO"); +// /*static final MyEnum*/ MyEnum::BAR = new MyEnum("BAR"); +// } +// +// If MyEnum::FOO object is referenced by any of the archived subgraphs, we must +// ensure the archived value equals (in object address) to the runtime value of +// MyEnum::FOO. +// +// However, since MyEnum:: is synthetically generated by javac, there's +// no way of programmatically handling this inside the Java code (as you would handle +// ModuleLayer::EMPTY_LAYER, for example). +// +// Instead, we archive all static field of such Enum classes. At runtime, +// HeapShared::initialize_enum_klass() skips the method and instead pulls +// the static fields out of the archived heap. +void CDSEnumKlass::handle_enum_obj(int level, + KlassSubGraphInfo* subgraph_info, + oop orig_obj) { + assert(level > 1, "must never be called at the first (outermost) level"); + assert(is_enum_obj(orig_obj), "must be"); + + InstanceKlass* ik = InstanceKlass::cast(orig_obj->klass()); + if (ik->has_archived_enum_objs()) { + return; + } + + ik->set_has_archived_enum_objs(); + ArchiveBuilder::get_buffered_klass(ik)->set_has_archived_enum_objs(); + + oop mirror = ik->java_mirror(); + for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + archive_static_field(level, subgraph_info, ik, mirror, fs); + } + } +} + +void CDSEnumKlass::archive_static_field(int level, KlassSubGraphInfo* subgraph_info, + InstanceKlass* ik, oop mirror, JavaFieldStream& fs) { + ResourceMark rm; + fieldDescriptor& fd = fs.field_descriptor(); + if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { + guarantee(false, "static field %s::%s must be T_OBJECT or T_ARRAY", + ik->external_name(), fd.name()->as_C_string()); + } + oop oop_field = mirror->obj_field(fd.offset()); + if (oop_field == nullptr) { + guarantee(false, "static field %s::%s must not be null", + ik->external_name(), fd.name()->as_C_string()); + } else if (oop_field->klass() != ik && oop_field->klass() != ik->array_klass_or_null()) { + guarantee(false, "static field %s::%s is of the wrong type", + ik->external_name(), fd.name()->as_C_string()); + } + bool success = HeapShared::archive_reachable_objects_from(level, subgraph_info, oop_field); + assert(success, "VM should have exited with unarchivable objects for _level > 1"); + int root_index = HeapShared::append_root(oop_field); + log_info(cds, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT ")", + root_index, ik->external_name(), fd.name()->as_C_string(), + p2i((oopDesc*)oop_field)); + SystemDictionaryShared::add_enum_klass_static_field(ik, root_index); +} + +bool CDSEnumKlass::initialize_enum_klass(InstanceKlass* k, TRAPS) { + if (!ArchiveHeapLoader::is_in_use()) { + return false; + } + + RunTimeClassInfo* info = RunTimeClassInfo::get_for(k); + assert(info != nullptr, "sanity"); + + if (log_is_enabled(Info, cds, heap)) { + ResourceMark rm; + log_info(cds, heap)("Initializing Enum class: %s", k->external_name()); + } + + oop mirror = k->java_mirror(); + int i = 0; + for (JavaFieldStream fs(k); !fs.done(); fs.next()) { + if (fs.access_flags().is_static()) { + int root_index = info->enum_klass_static_field_root_index_at(i++); + fieldDescriptor& fd = fs.field_descriptor(); + assert(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY, "must be"); + mirror->obj_field_put(fd.offset(), HeapShared::get_root(root_index, /*clear=*/true)); + } + } + return true; +} +#endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/cdsEnumKlass.hpp b/src/hotspot/share/cds/cdsEnumKlass.hpp new file mode 100644 index 0000000000000..c898bfec60d45 --- /dev/null +++ b/src/hotspot/share/cds/cdsEnumKlass.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_CDS_CDSENUMKLASS_HPP +#define SHARE_CDS_CDSENUMKLASS_HPP + +#include "memory/allStatic.hpp" +#include "oops/oop.hpp" +#include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" + +class InstanceKlass; +class JavaFieldStream; +class KlassSubGraphInfo; + +class CDSEnumKlass: AllStatic { +public: + static bool is_enum_obj(oop orig_obj); + static void handle_enum_obj(int level, + KlassSubGraphInfo* subgraph_info, + oop orig_obj); + static bool initialize_enum_klass(InstanceKlass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(false); + +private: + static void archive_static_field(int level, KlassSubGraphInfo* subgraph_info, + InstanceKlass* ik, oop mirror, JavaFieldStream& fs); +}; + +#endif // SHARE_CDS_CDSENUMKLASS_HPP diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 7b519a57d57cd..ff84ddc13fc6c 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -28,6 +28,7 @@ #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" +#include "cds/cdsEnumKlass.hpp" #include "cds/cdsHeapVerifier.hpp" #include "cds/heapShared.hpp" #include "cds/metaspaceShared.hpp" @@ -451,95 +452,6 @@ void HeapShared::set_has_native_pointers(oop src_obj) { info->set_has_native_pointers(); } -// -- Handling of Enum objects -// Java Enum classes have synthetic methods that look like this -// enum MyEnum {FOO, BAR} -// MyEnum:: { -// /*static final MyEnum*/ MyEnum::FOO = new MyEnum("FOO"); -// /*static final MyEnum*/ MyEnum::BAR = new MyEnum("BAR"); -// } -// -// If MyEnum::FOO object is referenced by any of the archived subgraphs, we must -// ensure the archived value equals (in object address) to the runtime value of -// MyEnum::FOO. -// -// However, since MyEnum:: is synthetically generated by javac, there's -// no way of programmatically handling this inside the Java code (as you would handle -// ModuleLayer::EMPTY_LAYER, for example). -// -// Instead, we archive all static field of such Enum classes. At runtime, -// HeapShared::initialize_enum_klass() will skip the method and pull -// the static fields out of the archived heap. -void HeapShared::check_enum_obj(int level, - KlassSubGraphInfo* subgraph_info, - oop orig_obj) { - assert(level > 1, "must never be called at the first (outermost) level"); - Klass* k = orig_obj->klass(); - Klass* buffered_k = ArchiveBuilder::get_buffered_klass(k); - if (!k->is_instance_klass()) { - return; - } - InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->java_super() == vmClasses::Enum_klass() && !ik->has_archived_enum_objs()) { - ResourceMark rm; - ik->set_has_archived_enum_objs(); - buffered_k->set_has_archived_enum_objs(); - oop mirror = ik->java_mirror(); - - for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - fieldDescriptor& fd = fs.field_descriptor(); - if (fd.field_type() != T_OBJECT && fd.field_type() != T_ARRAY) { - guarantee(false, "static field %s::%s must be T_OBJECT or T_ARRAY", - ik->external_name(), fd.name()->as_C_string()); - } - oop oop_field = mirror->obj_field(fd.offset()); - if (oop_field == nullptr) { - guarantee(false, "static field %s::%s must not be null", - ik->external_name(), fd.name()->as_C_string()); - } else if (oop_field->klass() != ik && oop_field->klass() != ik->array_klass_or_null()) { - guarantee(false, "static field %s::%s is of the wrong type", - ik->external_name(), fd.name()->as_C_string()); - } - bool success = archive_reachable_objects_from(level, subgraph_info, oop_field); - assert(success, "VM should have exited with unarchivable objects for _level > 1"); - int root_index = append_root(oop_field); - log_info(cds, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT ")", - root_index, ik->external_name(), fd.name()->as_C_string(), - p2i((oopDesc*)oop_field)); - SystemDictionaryShared::add_enum_klass_static_field(ik, root_index); - } - } - } -} - -// See comments in HeapShared::check_enum_obj() -bool HeapShared::initialize_enum_klass(InstanceKlass* k, TRAPS) { - if (!ArchiveHeapLoader::is_in_use()) { - return false; - } - - RunTimeClassInfo* info = RunTimeClassInfo::get_for(k); - assert(info != nullptr, "sanity"); - - if (log_is_enabled(Info, cds, heap)) { - ResourceMark rm; - log_info(cds, heap)("Initializing Enum class: %s", k->external_name()); - } - - oop mirror = k->java_mirror(); - int i = 0; - for (JavaFieldStream fs(k); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - int root_index = info->enum_klass_static_field_root_index_at(i++); - fieldDescriptor& fd = fs.field_descriptor(); - assert(fd.field_type() == T_OBJECT || fd.field_type() == T_ARRAY, "must be"); - mirror->obj_field_put(fd.offset(), get_root(root_index, /*clear=*/true)); - } - } - return true; -} - void HeapShared::archive_objects(ArchiveHeapInfo *heap_info) { { NoSafepointVerifier nsv; @@ -1241,7 +1153,9 @@ bool HeapShared::archive_reachable_objects_from(int level, WalkOopAndArchiveClosure walker(level, record_klasses_only, subgraph_info, orig_obj); orig_obj->oop_iterate(&walker); - check_enum_obj(level + 1, subgraph_info, orig_obj); + if (CDSEnumKlass::is_enum_obj(orig_obj)) { + CDSEnumKlass::handle_enum_obj(level + 1, subgraph_info, orig_obj); + } return true; } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index aa8c1dd3bc4f9..fa34289a38eda 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -212,9 +212,6 @@ class HeapShared: AllStatic { }; private: - static void check_enum_obj(int level, KlassSubGraphInfo* subgraph_info, - oop orig_obj); - static const int INITIAL_TABLE_SIZE = 15889; // prime number static const int MAX_TABLE_SIZE = 1000000; typedef ResizeableResourceHashtable Date: Tue, 9 Jul 2024 08:10:55 +0000 Subject: [PATCH 199/288] 8335955: JDK-8335742 wrongly used a "JDK-" prefix in the problemlist bug number Reviewed-by: iwalulya --- test/hotspot/jtreg/ProblemList-Virtual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index ac35f60e66153..06110ddcbc1a8 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -89,7 +89,7 @@ vmTestbase/nsk/jdi/VMOutOfMemoryException/VMOutOfMemoryException001/VMOutOfMemor ### # Fails on Windows because of additional memory allocation. -gc/g1/TestMixedGCLiveThreshold.java#25percent JDK-8334759 windows-x64 +gc/g1/TestMixedGCLiveThreshold.java#25percent 8334759 windows-x64 ########## ## Tests incompatible with with virtual test thread factory. From 2a2964759c73b3b9ab6afaad109383c89952977b Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 9 Jul 2024 08:25:00 +0000 Subject: [PATCH 200/288] 8334777: Test javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java failed with NullPointerException Reviewed-by: cjplummer, dholmes --- .../remote/mandatory/notif/NotifReconnectDeadlockTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java b/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java index 72ae57663079c..8f8ef54eade22 100644 --- a/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java +++ b/test/jdk/javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,9 @@ * @bug 6199899 * @summary Tests reconnection done by a fetching notif thread. * @author Shanliang JIANG + * @requires vm.compMode != "Xcomp" + * @comment Running with -Xcomp is likely to cause a timeout from ServerCommunicatorAdmin + * before addNotificationListener can complete. * * @run clean NotifReconnectDeadlockTest * @run build NotifReconnectDeadlockTest From 8f62f31dff564289a2422d58e8ecd5062d443b81 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 9 Jul 2024 08:26:25 +0000 Subject: [PATCH 201/288] 8335906: [s390x] Test Failure: GTestWrapper.java Reviewed-by: stuefe --- src/hotspot/share/runtime/os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 7b766707b0d0e..490a04aa6f132 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -959,7 +959,7 @@ static void print_ascii_form(stringStream& ascii_form, uint64_t value, int units uint8_t c[sizeof(v)]; } u = { value }; for (int i = 0; i < unitsize; i++) { - const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - 1 - i); + const int idx = LITTLE_ENDIAN_ONLY(i) BIG_ENDIAN_ONLY(sizeof(u.v) - unitsize + i); const uint8_t c = u.c[idx]; ascii_form.put(isprint(c) && isascii(c) ? c : '.'); } From f3ff4f7427c3c3f5cb2a115a61462bb9d28de1cd Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 9 Jul 2024 10:21:47 +0000 Subject: [PATCH 202/288] 8335882: platform/cgroup/TestSystemSettings.java fails on Alpine Linux Reviewed-by: stuefe, mbaesken --- test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java index 8d9279e1603c1..0e668b1f969d4 100644 --- a/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java +++ b/test/jdk/jdk/internal/platform/cgroup/TestSystemSettings.java @@ -24,7 +24,7 @@ /* * @test * @key cgroups - * @requires os.family == "linux" + * @requires (os.family == "linux" & !vm.musl) * @requires vm.flagless * @library /test/lib * @build TestSystemSettings From 0e0dfca21f64ecfcb3e5ed7cdc2a173834faa509 Mon Sep 17 00:00:00 2001 From: Aleksei Voitylov Date: Tue, 9 Jul 2024 10:27:44 +0000 Subject: [PATCH 203/288] 8330806: test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java fails on ARM32 Reviewed-by: snazarki, dsamersoff --- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index 688790f07e548..999f8fe590472 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -152,8 +152,14 @@ void LIR_Assembler::osr_entry() { int monitor_offset = (method()->max_locals() + 2 * (number_of_locks - 1)) * BytesPerWord; for (int i = 0; i < number_of_locks; i++) { int slot_offset = monitor_offset - (i * 2 * BytesPerWord); - __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord)); - __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord)); + if (slot_offset >= 4096 - BytesPerWord) { + __ add_slow(R2, OSR_buf, slot_offset); + __ ldr(R1, Address(R2, 0*BytesPerWord)); + __ ldr(R2, Address(R2, 1*BytesPerWord)); + } else { + __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord)); + __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord)); + } __ str(R1, frame_map()->address_for_monitor_lock(i)); __ str(R2, frame_map()->address_for_monitor_object(i)); } From 531a6d85b00b88688668ab1ced0db6ce0214a5f1 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Tue, 9 Jul 2024 13:11:07 +0000 Subject: [PATCH 204/288] 8335911: Document ccls indexer in doc/ide.md Reviewed-by: erikj --- doc/ide.html | 11 ++++++----- doc/ide.md | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/ide.html b/doc/ide.html index 0dd16b7b9e6e7..ef6f434013ed1 100644 --- a/doc/ide.html +++ b/doc/ide.html @@ -63,11 +63,12 @@
    Alternative indexers

    The main vscode-project target configures the default C++ support in Visual Studio Code. There are also other source indexers that can be installed, that may provide additional features. It's -currently possible to generate configuration for two such indexers, clangd and rtags. These can be -configured by appending the name of the indexer to the make target, such -as:

    +currently possible to generate configuration for three such indexers, clangd, ccls +and rtags. These can +be configured by appending the name of the indexer to the make target, +such as:

    make vscode-project-clangd

    Additional instructions for configuring the given indexer will be displayed after the workspace has been generated.

    diff --git a/doc/ide.md b/doc/ide.md index 40e3430a43875..d6ebb7b742a61 100644 --- a/doc/ide.md +++ b/doc/ide.md @@ -32,7 +32,8 @@ choose `File -> Open Workspace...` in Visual Studio Code. The main `vscode-project` target configures the default C++ support in Visual Studio Code. There are also other source indexers that can be installed, that may provide additional features. It's currently possible to generate -configuration for two such indexers, [clangd](https://clang.llvm.org/extra/clangd/) +configuration for three such indexers, [clangd](https://clang.llvm.org/extra/clangd/), +[ccls](https://github.com/MaskRay/ccls/wiki/Visual-Studio-Code) and [rtags](https://github.com/Andersbakken/rtags). These can be configured by appending the name of the indexer to the make target, such as: From 7e11fb702696df733ca89d325200f2e9414402d9 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Jul 2024 13:11:20 +0000 Subject: [PATCH 205/288] 8335688: Fix -Wzero-as-null-pointer-constant warnings from fflush calls in jvmti tests Reviewed-by: jwaters, coleenp --- .../libAddModuleUsesAndProvidesTest.c | 6 +- .../GenerateEvents/libGenerateEvents1.cpp | 2 +- .../GenerateEvents/libGenerateEvents2.cpp | 4 +- .../FilteredFields/libFilteredFieldsTest.cpp | 4 +- .../libMissedStackMapFrames.cpp | 2 +- .../libRedefineRetransform.cpp | 2 +- .../FramePop/framepop02/libframepop02.cpp | 4 +- .../thread/GetStackTrace/get_stack_trace.hpp | 2 +- .../SuspendResume1/libSuspendResume1.cpp | 6 +- .../getclfld007/getclfld007.cpp | 6 +- .../followref001/followref001.cpp | 58 ++++++++-------- .../followref002/followref002.cpp | 62 ++++++++--------- .../followref003/followref003.cpp | 68 +++++++++---------- .../followref004/followref004.cpp | 12 ++-- .../followref005/followref005.cpp | 2 +- .../followref006/followref006.cpp | 2 +- .../earlyretbase/earlyretbase.cpp | 12 ++-- .../earlyretfp/earlyretfp.cpp | 18 ++--- .../earlyretint/earlyretint.cpp | 14 ++-- .../earlyretlong/earlyretlong.cpp | 14 ++-- .../earlyretobj/earlyretobj.cpp | 14 ++-- .../earlyretstr/earlyretstr.cpp | 12 ++-- .../earlyretvoid/earlyretvoid.cpp | 12 ++-- .../getallstktr001/getallstktr001.cpp | 6 +- .../getcpool001/getcpool001.cpp | 6 +- 25 files changed, 175 insertions(+), 175 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c b/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c index 86f9993c70334..a979d1f913e0a 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c +++ b/test/hotspot/jtreg/serviceability/jvmti/AddModuleUsesAndProvides/libAddModuleUsesAndProvidesTest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,7 +200,7 @@ Java_MyPackage_AddModuleUsesAndProvidesTest_checkUses(JNIEnv *env, throw_exc(env, "Check #UC3: service can not be used unexpectedly"); return FAILED; } - fflush(0); + fflush(NULL); return PASSED; } @@ -275,7 +275,7 @@ Java_MyPackage_AddModuleUsesAndProvidesTest_checkProvides(JNIEnv *env, throw_exc(env, "Check #PC2: error in add provides to baseModule with correct service and serviceImpl"); return FAILED; } - fflush(0); + fflush(NULL); return PASSED; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp index fa60c07f8db41..0f040175bf953 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents1.cpp @@ -71,7 +71,7 @@ CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName"); printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign); - fflush(0); + fflush(nullptr); } JNIEXPORT jint JNICALL diff --git a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp index 7af061196a157..d582a9648920e 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/GenerateEvents/libGenerateEvents2.cpp @@ -71,7 +71,7 @@ CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName"); printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign); - fflush(0); + fflush(nullptr); } JNIEXPORT jint JNICALL @@ -132,7 +132,7 @@ Java_MyPackage_GenerateEventsTest_agent2FailStatus(JNIEnv *env, jclass cls) { printf("check2: Unexpected non-zero event count in agent2: %d\n", agent2_event_count); } printf("\n"); - fflush(0); + fflush(nullptr); return fail_status; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp index 28bfaaa03bd6f..fbefb1219e602 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp @@ -35,7 +35,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jint res = jvm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti == nullptr) { printf("Wrong result of a valid call to GetEnv!\n"); - fflush(0); + fflush(nullptr); return JNI_ERR; } return JNI_OK; @@ -72,7 +72,7 @@ Java_FilteredFieldsTest_getJVMTIFieldCount(JNIEnv *env, jclass cls, jclass clazz printf(" [%d]: %s\n", i, name); jvmti->Deallocate((unsigned char *)name); } - fflush(0); + fflush(nullptr); return fcount; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp index 5cebf608c3484..066794d1d6077 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/MissedStackMapFrames/libMissedStackMapFrames.cpp @@ -31,7 +31,7 @@ static void _log(const char* format, ...) { va_start(args, format); vprintf(format, args); va_end(args); - fflush(0); + fflush(nullptr); } static jvmtiEnv* jvmti = nullptr; diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp index 518e147c94278..450b0f35918b6 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineRetransform/libRedefineRetransform.cpp @@ -36,7 +36,7 @@ static void _log(const char* format, ...) { va_start(args, format); vprintf(format, args); va_end(args); - fflush(0); + fflush(nullptr); } static bool isTestClass(const char* name) { diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp index 61c9a91184bab..93df7f98277bf 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/events/FramePop/framepop02/libframepop02.cpp @@ -194,7 +194,7 @@ void JNICALL MethodEntry(jvmtiEnv *jvmti, JNIEnv *jni, { if (printdump == JNI_TRUE) { print_current_time(); - fflush(0); + fflush(nullptr); LOG(">>> %sMethod entry\n>>>", (isNative == JNI_TRUE) ? "Native " : ""); printInfo(jni, jvmti, thr, method, frameCount); } @@ -231,7 +231,7 @@ void JNICALL FramePop(jvmtiEnv *jvmti, JNIEnv *jni, { if (printdump == JNI_TRUE) { print_current_time(); - fflush(0); + fflush(nullptr); LOG(" >>> Frame Pop\n>>>"); printInfo(jni, jvmti, thr, method, frameCount); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp b/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp index d7c85704275f2..b8828b0e80f29 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp +++ b/test/hotspot/jtreg/serviceability/jvmti/thread/GetStackTrace/get_stack_trace.hpp @@ -70,7 +70,7 @@ int compare_stack_trace(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, int exp_idx = expected_frames_length - 1 - i; printf("expected idx %d\n", exp_idx); - fflush(0); + fflush(nullptr); if (i < expected_frames_length) { // for generated classes don't compare lambda indicies diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp index f05e619e0bd7d..93ad399b121ac 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume1/libSuspendResume1.cpp @@ -138,7 +138,7 @@ check_suspended_state(JNIEnv* jni, jthread thread, int thr_idx, char* tname, con LOG("## Agent: %s: virtual thread of carrier thread has state: %s (%d)\n", func_name, TranslateState(state), (int)state); - fflush(0); + fflush(nullptr); } set_agent_fail_status(); fatal(jni, "check_resumed_state: expected SUSPENDED flag in thread state"); @@ -169,7 +169,7 @@ check_resumed_state(JNIEnv* jni, jthread thread, int thr_idx, char* tname, const LOG("## Agent: %s: virtual thread of carrier thread has state: %s (%d)\n", func_name, TranslateState(state), (int)state); - fflush(0); + fflush(nullptr); } set_agent_fail_status(); fatal(jni, "check_resumed_state: NOT expected SUSPENDED flag in thread state"); @@ -210,7 +210,7 @@ test_thread_resume(JNIEnv* jni, jthread thread, int thr_idx, char* tname) { LOG("## Agent: test_thread_resume: virtual thread of carrier thread has state: %s (%d)\n", TranslateState(state), (int)state); - fflush(0); + fflush(nullptr); } check_jvmti_status(jni, err, "test_thread_resume: error in JVMTI ResumeThread"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp index 3cd333843308c..89a62346ca9f0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp @@ -86,7 +86,7 @@ Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass if (jvmti == nullptr) { printf("JVMTI client was not properly loaded!\n"); - fflush(0); + fflush(nullptr); result = STATUS_FAILED; return; } @@ -98,7 +98,7 @@ Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass if (err != JVMTI_ERROR_NONE) { printf("GetClassFields unexpected error: %s (%d)\n", TranslateError(err), err); - fflush(0); + fflush(nullptr); result = STATUS_FAILED; return; } @@ -132,7 +132,7 @@ Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass jvmti->Deallocate((unsigned char *)name); jvmti->Deallocate((unsigned char *)sig); } - fflush(0); + fflush(nullptr); } JNIEXPORT int JNICALL diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp index ff431aa2203e9..b33128b491626 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref001/followref001.cpp @@ -137,14 +137,14 @@ static bool initObjectDescList(jvmtiEnv* jvmti, *objectsCount = 1 + 2 * chainLength; printf("Allocate memory for objects list: %d objects\n", *objectsCount); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**) objectDescList))) { nsk_jvmti_setFailStatus(); return false; } printf(" ... allocated array: 0x%p\n", (void*)objectDescList); - fflush(0); + fflush(nullptr); { int k; @@ -179,7 +179,7 @@ static bool getAndTagClasses(jvmtiEnv* jvmti, } printf("\nFound debugee class: 0x%p\n %s\n", (void*) *debugeeClass, DEBUGEE_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != nullptr)) { @@ -194,7 +194,7 @@ static bool getAndTagClasses(jvmtiEnv* jvmti, printf("\nFound root object class: 0x%p, tag=%ld\n %s\n", (void*) *rootObjectClass,(long) ROOT_CLASS_TAG, ROOT_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*chainObjectClass = @@ -209,7 +209,7 @@ static bool getAndTagClasses(jvmtiEnv* jvmti, printf("\nFound chain object class: 0x%p, tag=%ld\n %s\n", (void*) *chainObjectClass, (long) CHAIN_CLASS_TAG, CHAIN_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); return true; } /* getAndTagClasses */ @@ -234,7 +234,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, } printf("\nFound fieldID: 0x%p - \'%s\' static field in debugee class\n", (void*) rootObjectField, OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*reachableChainField = jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { @@ -243,7 +243,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, } printf("\nFound fieldID: 0x%p - \'%s\' field in root object class\n", (void*) reachableChainField, REACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*unreachableChainField = jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { @@ -253,7 +253,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, printf("\nFound fieldID: 0x%p - \'%s\' field in root object class\n", (void*) unreachableChainField, UNREACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*nextField = jni->GetFieldID(chainObjectClass, NEXT_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { @@ -262,7 +262,7 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, } printf("\nFound fieldID: 0x%p - \'%s\' field in chain object class\n", (void*) nextField, NEXT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObjectPtr = jni->GetStaticObjectField(debugeeClass, rootObjectField)) != nullptr)) { @@ -270,14 +270,14 @@ static bool getFieldsAndObjects(jvmtiEnv* jvmti, return false; } printf("\nFound root object: 0x%p\n", (void*) *rootObjectPtr); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObjectPtr = jni->NewGlobalRef(*rootObjectPtr)) != nullptr)) { nsk_jvmti_setFailStatus(); return false; } printf("Created root object global ref: 0x%p\n", (void*)*rootObjectPtr); - fflush(0); + fflush(nullptr); return true; } /* getFieldsAndObjects */ @@ -318,7 +318,7 @@ static bool getAndTagChainObjects( nsk_jvmti_setFailStatus(); } printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)nextObj); - fflush(0); + fflush(nullptr); /* To continue traversing objects in the chain */ if (!getAndTagChainObjects(jvmti, @@ -394,7 +394,7 @@ static int getAndTagTestedObjects( (long) ROOT_OBJECT_TAG, (void*) *rootObjectPtr); printf(" reachable objects chain: %d objects\n", chainLength); - fflush(0); + fflush(nullptr); if (!getAndTagChainObjects(jvmti, jni, @@ -453,7 +453,7 @@ static bool checkTestedObjects(jvmtiEnv* jvmti, } printf("\nReachable objects:\n"); - fflush(0); + fflush(nullptr); for (i = 0; i < chainLength; i++) { idx = i + 1; printf("Reachable object:\n" @@ -488,7 +488,7 @@ static bool checkTestedObjects(jvmtiEnv* jvmti, NSK_COMPLAIN0("Unreachable object was iterated\n"); nsk_jvmti_setFailStatus(); } - fflush(0); + fflush(nullptr); } return true; @@ -514,7 +514,7 @@ static void releaseTestedObjects(jvmtiEnv* jvmti, } } - fflush(0); + fflush(nullptr); } /* releaseTestedObjects */ @@ -542,7 +542,7 @@ jint JNICALL heapReferenceCallback( /* ss45998: class_tag=>referrence_class_tag */ printf(" size: %" LL "d, tag_ptr: 0x%p, referrer_tag_ptr: 0x%p, length: %-d\n", size, tag_ptr, referrer_tag_ptr, length); - fflush(0); + fflush(nullptr); if (((uintptr_t) tag_ptr & FULL_32_BIT_MASK) == FULL_32_BIT_MASK) { NSK_COMPLAIN1("wrong tag_ptr passed to " @@ -567,7 +567,7 @@ jint JNICALL heapReferenceCallback( printf(" class_tag=%" LL "d, tag=%" LL "d, size=%" LL "d," " ref_tag=%" LL "d, referrer_index=%d\n\n", class_tag, tag, size, ref_tag, referrer_index); - fflush(0); + fflush(nullptr); if (length != -1) { NSK_COMPLAIN1("wrong length passed to heapReferenceCallback: " @@ -647,7 +647,7 @@ jint JNICALL heapReferenceCallback( case JVMTI_HEAP_REFERENCE_OTHER: { NSK_COMPLAIN1("This reference kind was not expected: %s\n", ref_kind_str[reference_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); return 0; } @@ -674,7 +674,7 @@ jint JNICALL primitiveFieldCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); return 0; } /* primitiveFieldCallback */ @@ -694,7 +694,7 @@ jint JNICALL arrayPrimitiveValueCallback( (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); return 0; } /* arrayPrimitiveValueCallback */ @@ -711,7 +711,7 @@ jint JNICALL stringPrimitiveValueCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); return 0; } /* stringPrimitiveValueCallback */ @@ -725,14 +725,14 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { jobject rootObject = nullptr; printf("Wait for tested objects created\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { return; } printf(">>> Obtain and tag tested objects from debugee class\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(getAndTagTestedObjects(jvmti, jni, @@ -745,7 +745,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to clean links to unreachable objects\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; @@ -755,7 +755,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Start iteration from root tested object: 0x%p\n\n", rootObject); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences((jint) 0, /* heap_filter */ (jclass) nullptr, /* class */ @@ -767,19 +767,19 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were iterated:\n"); - fflush(0); + fflush(nullptr); if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); } printf(">>> Clean used data\n"); - fflush(0); + fflush(nullptr); releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject); printf(">>> Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp index 6366b430776c9..9ea3a5d0d01c0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref002/followref002.cpp @@ -131,7 +131,7 @@ static int getAndTagChainObjects( nsk_jvmti_setFailStatus(); } printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj); - fflush(0); + fflush(nullptr); if (!getAndTagChainObjects(jvmti, jni, obj, nextField, nextFieldName, @@ -170,14 +170,14 @@ static int getAndTagTestedObjects( *objectsCount = 1 + 2 * chainLength; printf("Allocate memory for objects list: %d objects\n", *objectsCount); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**)objectDescList))) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... allocated array: 0x%p\n", (void*)objectDescList); - fflush(0); + fflush(nullptr); { int k; @@ -191,7 +191,7 @@ static int getAndTagTestedObjects( (*objectDescList)[0].exp_class_tag = rootClassTag; printf("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -199,7 +199,7 @@ static int getAndTagTestedObjects( printf(" ... found class: 0x%p\n", (void*)debugeeClass); printf("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -212,7 +212,7 @@ static int getAndTagTestedObjects( printf(" tag=%-5ld rootClass=0x%p\n", (long)rootClassTag, (void*)rootObjectClass); printf("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (chainObjectClass = jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -226,7 +226,7 @@ static int getAndTagTestedObjects( printf(" tag=%-5ld chainClass=0x%p\n", (long)chainClassTag, (void*)chainObjectClass); printf("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (objectField = jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -235,7 +235,7 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)objectField); printf("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (reachableChainField = jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -244,7 +244,7 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)reachableChainField); printf("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (unreachableChainField = jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -253,7 +253,7 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)unreachableChainField); printf("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (tailField = jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -262,14 +262,14 @@ static int getAndTagTestedObjects( printf(" ... got fieldID: 0x%p\n", (void*)tailField); printf("Get root object from static field: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->GetStaticObjectField(debugeeClass, objectField)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... got object: 0x%p\n", (void*)*rootObject); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->NewGlobalRef(*rootObject)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -280,7 +280,7 @@ static int getAndTagTestedObjects( printf("Obtain and tag chain objects:\n"); printf(" root tested object:\n"); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObject, rootObjectTag))) { nsk_jvmti_setFailStatus(); } @@ -295,7 +295,7 @@ static int getAndTagTestedObjects( (*objectDescList)[chainLength].exp_found = 1; printf(" reachable objects chain: %d objects\n", chainLength); - fflush(0); + fflush(nullptr); if (!getAndTagChainObjects(jvmti, jni, *rootObject, reachableChainField, REACHABLE_CHAIN_FIELD_NAME, @@ -348,7 +348,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, } printf("\nReachable objects:\n"); - fflush(0); + fflush(nullptr); for (i = 0; i < chainLength; i++) { idx = i + 1; printf("Reachable object:\n" @@ -383,7 +383,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, NSK_COMPLAIN0("Unreachable object was iterated\n"); nsk_jvmti_setFailStatus(); } - fflush(0); + fflush(nullptr); } return NSK_TRUE; @@ -404,7 +404,7 @@ static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, } } - fflush(0); + fflush(nullptr); return NSK_TRUE; } /* releaseTestedObjects */ @@ -456,7 +456,7 @@ jint JNICALL heapReferenceCallback( (long) size, (long) ref_tag, (int) referrer_index); - fflush(0); + fflush(nullptr); if (tag_ptr == nullptr) { NSK_COMPLAIN1("null tag_ptr is passed to heapReferenceCallback:" @@ -531,7 +531,7 @@ jint JNICALL heapReferenceCallback( case JVMTI_HEAP_REFERENCE_OTHER: { NSK_COMPLAIN1("This reference kind was not expected: %s\n", ref_kind_str[reference_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); return 0; } @@ -556,7 +556,7 @@ jint JNICALL primitiveFieldCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); return 0; } @@ -574,7 +574,7 @@ jint JNICALL arrayPrimitiveValueCallback( (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); return 0; } @@ -590,7 +590,7 @@ jint JNICALL stringPrimitiveValueCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); return 0; } @@ -602,13 +602,13 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { jobject rootObject = nullptr; printf("Wait for tested objects created\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { return; } printf(">>> Obtain and tag tested objects from debugee class\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(getAndTagTestedObjects(jvmti, jni, chainLength, &objectsCount, @@ -618,7 +618,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to clean links to unreachable objects\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; @@ -629,7 +629,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 1-st iteration for root tested object: 0x%p\n", rootObject); - fflush(0); + fflush(nullptr); { jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED | JVMTI_HEAP_FILTER_CLASS_UNTAGGED; if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences(heap_filter, @@ -643,7 +643,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were iterated\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -660,7 +660,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 2-nd iteration for root tested object: 0x%p\n", rootObject); - fflush(0); + fflush(nullptr); { /* This time everythig is filtered out */ jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED | JVMTI_HEAP_FILTER_CLASS_UNTAGGED | @@ -676,7 +676,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were not reported this time\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -684,7 +684,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Clean used data\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject))) { return; @@ -692,7 +692,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp index cb0385ee6535b..80cbf856f4504 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref003/followref003.cpp @@ -146,7 +146,7 @@ static int getChainObjects(jvmtiEnv* jvmti, JNIEnv* jni, jobject firstObject, nsk_jvmti_setFailStatus(); } printf(" tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj); - fflush(0); + fflush(nullptr); if (!getChainObjects(jvmti, jni, obj, nextField, nextFieldName, nextField, nextFieldName, count, objectDescList, tag, reachable)) { @@ -173,14 +173,14 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, *objectsCount = 1 + 2 * chainLength; printf("Allocate memory for objects list: %d objects\n", *objectsCount); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**)objectDescList))) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... allocated array: 0x%p\n", (void*)objectDescList); - fflush(0); + fflush(nullptr); { int k; @@ -194,7 +194,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (*objectDescList)[0].exp_class_tag = rootClassTag; printf("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -202,7 +202,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... found class: 0x%p\n", (void*)debugeeClass); printf("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; @@ -216,7 +216,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (long)rootClassTag, (void*)rootObjectClass); printf("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (chainObjectClass = jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -232,7 +232,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (long)chainClassTag, (void*)chainObjectClass); printf("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (objectField = jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -241,7 +241,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)objectField); printf("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (reachableChainField = jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -250,7 +250,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)reachableChainField); printf("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (unreachableChainField = jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -259,7 +259,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)unreachableChainField); printf("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (tailField = jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -268,14 +268,14 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf(" ... got fieldID: 0x%p\n", (void*)tailField); printf("Get root object from static field: %s\n", OBJECT_FIELD_NAME); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->GetStaticObjectField(debugeeClass, objectField)) != nullptr)) { nsk_jvmti_setFailStatus(); return NSK_FALSE; } printf(" ... got object: 0x%p\n", (void*)*rootObject); - fflush(0); + fflush(nullptr); if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->NewGlobalRef(*rootObject)) != nullptr)) { nsk_jvmti_setFailStatus(); @@ -286,7 +286,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, printf("Obtain and tag chain objects:\n"); printf(" root tested object\n"); - fflush(0); + fflush(nullptr); if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObject, rootObjectTag))) { nsk_jvmti_setFailStatus(); } @@ -298,7 +298,7 @@ static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, (*objectDescList)[0].tag = rootObjectTag; printf(" reachable objects chain: %d objects\n", chainLength); - fflush(0); + fflush(nullptr); if (!getChainObjects(jvmti, jni, *rootObject, reachableChainField, REACHABLE_CHAIN_FIELD_NAME, tailField, TAIL_FIELD_NAME, @@ -347,7 +347,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, } printf("\nReachable objects:\n"); - fflush(0); + fflush(nullptr); for (i = 0; i < chainLength; i++) { idx = i + 1; printf("Reachable object:\n" @@ -382,7 +382,7 @@ static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, NSK_COMPLAIN0("Unreachable object was iterated\n"); nsk_jvmti_setFailStatus(); } - fflush(0); + fflush(nullptr); } return NSK_TRUE; @@ -403,7 +403,7 @@ static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength, } } - fflush(0); + fflush(nullptr); return NSK_TRUE; } @@ -646,7 +646,7 @@ jint JNICALL heapReferenceCallback( (long) size); } - fflush(0); + fflush(nullptr); return 0; } @@ -665,7 +665,7 @@ jint JNICALL heapReferenceCallback( method, (long) location, (int) index); - fflush(0); + fflush(nullptr); if (tag_ptr == nullptr) { NSK_COMPLAIN1("null tag_ptr is passed to heapReferenceCallback:" @@ -748,7 +748,7 @@ jint JNICALL heapReferenceCallback( if (tag != rootObjectTag || class_tag != rootClassTag) { NSK_COMPLAIN1("This reference kind was not expected: %s\n", ref_kind_str[ref_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); } break; @@ -818,7 +818,7 @@ jint JNICALL heapReferenceCallback( default: { NSK_COMPLAIN1("This reference kind was not expected: %s\n\n", ref_kind_str[ref_kind]); - fflush(0); + fflush(nullptr); nsk_jvmti_setFailStatus(); break; } @@ -840,7 +840,7 @@ jint JNICALL primitiveFieldCallback (long) class_tag, (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); return 0; } @@ -853,7 +853,7 @@ jint JNICALL arrayPrimitiveValueCallback (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); return 0; } @@ -865,7 +865,7 @@ jint JNICALL stringPrimitiveValueCallback (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); return 0; } @@ -902,13 +902,13 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { jobject rootObject = nullptr; printf("Wait for tested objects created\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) { return; } printf(">>> Obtain and tag tested objects from debugee class\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(getTestedObjects(jvmti, jni, chainLength, &objectsCount, &objectDescList, &rootObject))) { @@ -917,7 +917,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to clean links to unreachable objects\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; @@ -933,7 +933,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 1-st iteration starting from the heap root\n"); - fflush(0); + fflush(nullptr); { if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences((jint) 0, /* heap_filter */ (jclass) nullptr, /* class */ @@ -946,7 +946,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Check if reachable objects were iterated\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -968,7 +968,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("\n\n>>> Start 2-nd iteration starting from the heap root\n"); - fflush(0); + fflush(nullptr); first_followref = 0; { jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED @@ -985,7 +985,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { printf(">>> Check that both reachable and unreachable " "objects were not iterated\n"); - fflush(0); + fflush(nullptr); { if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) { nsk_jvmti_setFailStatus(); @@ -994,7 +994,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { printf(">>> Clean used data\n"); - fflush(0); + fflush(nullptr); { if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject))) { @@ -1003,7 +1003,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf("Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) return; } @@ -1047,7 +1047,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { info = INFO_HEAPOBJ; else { printf("Unknown option value: info=%s\n", infoOpt); - fflush(0); + fflush(nullptr); return JNI_ERR; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp index e73534de8b6b4..2446b5f7caf93 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref004/followref004.cpp @@ -86,7 +86,7 @@ jint JNICALL primitiveFieldCallback( (long) DEREF(tag_ptr), (int) value_type); - fflush(0); + fflush(nullptr); markTagVisited(DEREF(tag_ptr)); @@ -111,7 +111,7 @@ jint JNICALL arrayPrimitiveValueCallback( (long) DEREF(tag_ptr), (int) element_count, (int) element_type); - fflush(0); + fflush(nullptr); markTagVisited(DEREF(tag_ptr)); @@ -132,7 +132,7 @@ jint JNICALL stringPrimitiveValueCallback( (long) class_tag, (long) DEREF(tag_ptr), (int) value_length); - fflush(0); + fflush(nullptr); markTagVisited(DEREF(tag_ptr)); @@ -168,14 +168,14 @@ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) jvmtiError retCode; printf(">>> Sync with Java code\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) { return; } printf(">>> Create JNI global references\n"); - fflush(0); + fflush(nullptr); createGlobalRefs(jni); @@ -192,7 +192,7 @@ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) checkThatAllTagsVisited(); printf(">>> Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_resumeSync())) { return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp index 333ddcccf831a..d0194feab0288 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref005/followref005.cpp @@ -88,7 +88,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } printf(">>> Let debugee to finish\n"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) { return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp index 54485fb809ae2..5c5e37803211d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/FollowReferences/followref006/followref006.cpp @@ -181,7 +181,7 @@ static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) checkNoObjIterated(jni, jvmti, JAVA_UTIL_CALENDAR_CLASS_NAME); NSK_DISPLAY0("Let debugee to finish"); - fflush(0); + fflush(nullptr); if (!NSK_VERIFY(nsk_jvmti_waitForSync(g_timeout))) { return; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp index 47b9618d19c88..6c57004fc5f59 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp @@ -33,7 +33,7 @@ extern "C" { #define STATUS_FAILED 2 #define PASSED 0 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return errCode +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return errCode static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -59,7 +59,7 @@ MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr, if (method == midActiveMethod) { printf("#### MethodExit event occurred ####\n"); - fflush(0); + fflush(nullptr); meth_exit_gen_events++; } } @@ -70,7 +70,7 @@ FramePop(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, if (method == midActiveMethod) { printf("#### FramePop event occurred ####\n"); - fflush(0); + fflush(nullptr); pop_frame_gen_events++; } } @@ -120,7 +120,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_resThread(JNIEnv *env, return JNI_ERR; } printf("<<<<<<<< ResumeThread() is successfully done\n"); - fflush(0); + fflush(nullptr); return PASSED; } @@ -176,7 +176,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_doForceEarlyReturn(JNIEnv *env RETURN_FAILED; } printf("Check #1 PASSED: ForceEarlyReturn() is successfully done\n"); - fflush(0); + fflush(nullptr); return(errCode); } @@ -268,7 +268,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_check(JNIEnv *env, jclass cls) "events generated correctly\n"); errCode = PASSED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp index 9a0ce3d85508b..5e7506a871e3c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretfp/earlyretfp.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return #define METHCNT 2 static jvmtiEnv *jvmti = nullptr; @@ -175,7 +175,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -220,7 +220,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -256,7 +256,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -289,7 +289,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, printf("Method was_popped_by_exception unexpectedly\n"); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -361,7 +361,7 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { printf("Warning: Breakpoint or SingleStep event are not implemented\n"); } - fflush(0); + fflush(nullptr); return JNI_OK; } @@ -431,7 +431,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretfp_printFloat( JNIEnv *env, jclass cls, jfloat val) { printf("\n>>> Returned value is %8.4f, hex: %#a\n", val, val); - fflush(0); + fflush(nullptr); return; } @@ -440,7 +440,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretfp_printDouble( JNIEnv *env, jclass cls, jdouble val) { printf("\n>>> Returned value is %8.4f, hex: %#a\n", val, val); - fflush(0); + fflush(nullptr); return; } @@ -451,7 +451,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretfp_check(JNIEnv *env, jclass cls) { framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp index feb51d5fc407d..16cd4c3856712 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretint/earlyretint.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -184,7 +184,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -229,7 +229,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -270,7 +270,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -295,7 +295,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, printf("Method was_popped_by_exception unexpectedly\n"); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -452,7 +452,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretint_printInt( JNIEnv *env, jclass cls, jint val) { printf("\n>>> Returned value: dec %d, hex: %#x\n", val, val); - fflush(0); + fflush(nullptr); return; } @@ -463,7 +463,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretint_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp index 170d6839bef09..2cb1a318d4492 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretlong/earlyretlong.cpp @@ -34,7 +34,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -168,7 +168,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -213,7 +213,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -251,7 +251,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -276,7 +276,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, errCode = STATUS_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -412,7 +412,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretlong_printLong( printf("\n>>> Returned value: dec: %" LL "d, hex: %#x %#x\n", val, iptr[0], iptr[1]); - fflush(0); + fflush(nullptr); return; } @@ -423,7 +423,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretlong_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp index 6faf82f9ed90e..ee3b79632d5c2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretobj/earlyretobj.cpp @@ -34,7 +34,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -168,7 +168,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -213,7 +213,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -251,7 +251,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -274,7 +274,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, errCode = STATUS_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -410,7 +410,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretobj_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } @@ -419,7 +419,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretobj_printObject( JNIEnv *env, jclass cls, jobject obj) { printf("\nReturned jobject: %#" PRIxPTR "\n", (uintptr_t)obj); - fflush(0); + fflush(nullptr); return; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp index 6ebb50026a34a..8465d05f9561a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretstr/earlyretstr.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -167,7 +167,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, printf(" expected: %d\n", framesCount + 1); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -212,7 +212,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -249,7 +249,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, @@ -273,7 +273,7 @@ void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, errCode = STATUS_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -409,7 +409,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretstr_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp index 4919d27e9e7c7..e66b9fc97acd6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretvoid/earlyretvoid.cpp @@ -33,7 +33,7 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jvmtiEnv *jvmti = nullptr; static jvmtiCapabilities caps; @@ -155,7 +155,7 @@ void check(jvmtiEnv *jvmti_env, jthread thr, jmethodID mid, } jvmti_env->Deallocate((unsigned char*)table); } - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -192,7 +192,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -223,7 +223,7 @@ void JNICALL SingleStep(jvmtiEnv *jvmti_env, JNIEnv *env, RETURN_FAILED; } } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD @@ -339,7 +339,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretvoid_getReady( } else { framesExpected = depth; } - fflush(0); + fflush(nullptr); } JNIEXPORT jint JNICALL @@ -349,7 +349,7 @@ Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretvoid_check(JNIEnv *env, jclass cls) framesCount, framesExpected); errCode = STATUS_FAILED; } - fflush(0); + fflush(nullptr); return errCode; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp index c1f0443186f20..8916186531d58 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetAllStackTraces/getallstktr001/getallstktr001.cpp @@ -179,7 +179,7 @@ void compare_all_frames(int ti, int frames_count, printf("thr #%d: compare frame #%d: fields are the same: " " method: 0x%p, location: %#" LL "x\n", ti, fi, fr1->method, fr1->location); - fflush(0); + fflush(nullptr); } } @@ -225,7 +225,7 @@ void compare_one_stack_trace(int ti, " jthread: 0x%p, state: %d, frame_count: %d\n", ti, stk1->thread, stk1->state, stk1->frame_count); - fflush(0); + fflush(nullptr); compare_all_frames(ti, stk1->frame_count, stk1->frame_buffer, @@ -291,7 +291,7 @@ Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_GetThreadsInfo( iGlobalStatus = STATUS_FAILED; } printf("GetThreadInfo %d: thread: %s\n", ti, thread_info[ti].name); - fflush(0); + fflush(nullptr); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp index 997e6c667e60a..d3905ad65ebcf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetConstantPool/getcpool001/getcpool001.cpp @@ -36,7 +36,7 @@ extern "C" { static jvmtiCapabilities caps; static jvmtiEventCallbacks callbacks; -#define RETURN_FAILED errCode = STATUS_FAILED; fflush(0); return +#define RETURN_FAILED errCode = STATUS_FAILED; fflush(nullptr); return static jint errCode = PASSED; static jvmtiEnv *jvmti = nullptr; @@ -63,7 +63,7 @@ Java_nsk_jvmti_unit_GetConstantPool_getcpool001_getCP( /* Print Constant Pool attrs*/ printf("getCP: id = %d, cnt = %03d, bytes_cnt = %04d\n", id, cp_cnt, cp_bytes_cnt); - fflush(0); + fflush(nullptr); } void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, @@ -83,7 +83,7 @@ void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, TranslateError(err), err); RETURN_FAILED; } - fflush(0); + fflush(nullptr); } #ifdef STATIC_BUILD From 1472124489c841642996ae984e21c533ffec8091 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 9 Jul 2024 20:38:09 +0000 Subject: [PATCH 206/288] 8333364: Minor cleanup could be done in com.sun.crypto.provider Reviewed-by: mullan, valeriep --- .../sun/crypto/provider/AESKeyGenerator.java | 12 +- .../com/sun/crypto/provider/AESKeyWrap.java | 30 ++--- .../sun/crypto/provider/AESKeyWrapPadded.java | 34 ++--- .../sun/crypto/provider/ARCFOURCipher.java | 8 +- .../sun/crypto/provider/ChaCha20Cipher.java | 35 +++-- .../provider/ChaCha20Poly1305Parameters.java | 7 +- .../crypto/provider/CipherBlockChaining.java | 4 +- .../com/sun/crypto/provider/CipherCore.java | 21 ++- .../crypto/provider/CipherTextStealing.java | 5 +- .../sun/crypto/provider/ConstructKeys.java | 6 +- .../com/sun/crypto/provider/DESCrypt.java | 126 +++++++++--------- .../sun/crypto/provider/DESKeyFactory.java | 4 +- .../sun/crypto/provider/DESedeKeyFactory.java | 4 +- .../crypto/provider/DESedeKeyGenerator.java | 4 +- .../sun/crypto/provider/DESedeWrapCipher.java | 15 +-- .../com/sun/crypto/provider/DHKEM.java | 20 +-- .../sun/crypto/provider/DHKeyAgreement.java | 30 ++--- .../crypto/provider/DHKeyPairGenerator.java | 5 +- .../crypto/provider/ElectronicCodeBook.java | 6 +- .../sun/crypto/provider/FeedbackCipher.java | 6 +- .../classes/com/sun/crypto/provider/GCTR.java | 5 +- .../com/sun/crypto/provider/GHASH.java | 7 +- .../crypto/provider/GaloisCounterMode.java | 34 ++--- .../com/sun/crypto/provider/HmacCore.java | 27 ++-- .../com/sun/crypto/provider/HmacMD5.java | 9 +- .../crypto/provider/HmacMD5KeyGenerator.java | 5 +- .../com/sun/crypto/provider/HmacSHA1.java | 9 +- .../crypto/provider/HmacSHA1KeyGenerator.java | 5 +- .../sun/crypto/provider/ISO10126Padding.java | 5 +- .../com/sun/crypto/provider/JceKeyStore.java | 14 +- .../com/sun/crypto/provider/KWUtil.java | 10 +- .../com/sun/crypto/provider/KeyProtector.java | 6 +- .../sun/crypto/provider/KeyWrapCipher.java | 20 +-- .../sun/crypto/provider/OAEPParameters.java | 12 +- .../sun/crypto/provider/OutputFeedback.java | 4 +- .../sun/crypto/provider/PBEKeyFactory.java | 4 +- .../com/sun/crypto/provider/PBES1Core.java | 6 +- .../sun/crypto/provider/PBES2Parameters.java | 20 ++- .../sun/crypto/provider/PBKDF2KeyImpl.java | 21 +-- .../com/sun/crypto/provider/PBMAC1Core.java | 4 +- .../com/sun/crypto/provider/PKCS5Padding.java | 5 +- .../com/sun/crypto/provider/Poly1305.java | 12 +- .../com/sun/crypto/provider/RC2Crypt.java | 4 +- .../com/sun/crypto/provider/RSACipher.java | 7 +- .../com/sun/crypto/provider/SslMacCore.java | 23 ++-- .../provider/TlsKeyMaterialGenerator.java | 12 +- .../sun/crypto/provider/TlsPrfGenerator.java | 8 +- 47 files changed, 313 insertions(+), 367 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java index 2672807aaddae..51671fdf25d0a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,19 +25,19 @@ package com.sun.crypto.provider; -import java.security.SecureRandom; -import java.security.InvalidParameterException; import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; + import sun.security.util.SecurityProviderConstants; /** - * This class generates a AES key. + * This class generates an AES key. * * @author Valerie Peng * @@ -105,7 +105,7 @@ protected void engineInit(int keysize, SecureRandom random) { * @return the new AES key */ protected SecretKey engineGenerateKey() { - SecretKeySpec aesKey = null; + SecretKeySpec aesKey; if (this.random == null) { this.random = SunJCE.getRandom(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java index 9cb338996406e..7fad0b84d0715 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ package com.sun.crypto.provider; -import java.util.Arrays; -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import javax.crypto.IllegalBlockSizeException; + import static com.sun.crypto.provider.KWUtil.*; /** @@ -66,7 +66,7 @@ String getFeedback() { @Override void save() { throw new UnsupportedOperationException("save not supported"); - }; + } /** * Restores the content of this cipher to the previous saved one. @@ -74,7 +74,7 @@ void save() { @Override void restore() { throw new UnsupportedOperationException("restore not supported"); - }; + } /** * Initializes the cipher in the specified mode with the given key @@ -112,20 +112,20 @@ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) @Override void reset() { throw new UnsupportedOperationException("reset not supported"); - }; + } - // no support for multi-part encryption + // no support for multipart encryption @Override int encrypt(byte[] pt, int ptOfs, int ptLen, byte[] ct, int ctOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } - // no support for multi-part decryption + // no support for multipart decryption @Override int decrypt(byte[] ct, int ctOfs, int ctLen, byte[] pt, int ptOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } /** * Performs single-part encryption operation. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java index 4ae96acbca853..1e4e7236c8cae 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,12 @@ package com.sun.crypto.provider; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.util.Arrays; import java.util.HexFormat; -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; -import javax.crypto.spec.*; +import javax.crypto.IllegalBlockSizeException; + import static com.sun.crypto.provider.KWUtil.*; /** @@ -49,7 +49,7 @@ class AESKeyWrapPadded extends FeedbackCipher { private static final byte[] PAD_BLK = new byte[SEMI_BLKSIZE - 1]; - // set the first semiblock of dest with iv and inLen + // set the first semi-block of dest with iv and inLen private static void setIvAndLen(byte[] dest, byte[] iv, int inLen) { assert(dest.length >= SEMI_BLKSIZE) : "buffer needs at least 8 bytes"; @@ -60,7 +60,7 @@ private static void setIvAndLen(byte[] dest, byte[] iv, int inLen) { dest[7] = (byte) (inLen & 0xFF); } - // validate the recovered internal ivAndLen semiblock against iv and + // validate the recovered internal ivAndLen semi-block against iv and // return the recovered input length private static int validateIV(byte[] ivAndLen, byte[] iv) throws IllegalBlockSizeException { @@ -103,7 +103,7 @@ String getFeedback() { @Override void save() { throw new UnsupportedOperationException("save not supported"); - }; + } /** * Restores the content of this cipher to the previous saved one. @@ -111,7 +111,7 @@ void save() { @Override void restore() { throw new UnsupportedOperationException("restore not supported"); - }; + } /** * Initializes the cipher in the specified mode with the given key @@ -151,19 +151,19 @@ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) @Override void reset() { throw new UnsupportedOperationException("reset not supported"); - }; + } - // no support for multi-part encryption + // no support for multipart encryption @Override int encrypt(byte[] pt, int ptOfs, int ptLen, byte[] ct, int ctOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } - // no support for multi-part decryption + // no support for multipart decryption @Override int decrypt(byte[] ct, int ctOfs, int ctLen, byte[] pt, int ptOfs) { - throw new UnsupportedOperationException("multi-part not supported"); - }; + throw new UnsupportedOperationException("multipart not supported"); + } /** * Performs single-part encryption operation. @@ -199,7 +199,7 @@ int encryptFinal(byte[] pt, int dummy1, int ptLen, byte[] dummy2, } if (ptLen <= BLKSIZE) { - // overwrite the first semiblock with iv and input length + // overwrite the first semi-block with iv and input length setIvAndLen(pt, iv, actualLen); embeddedCipher.encryptBlock(pt, 0, pt, 0); } else { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java index 09d5a8cddebfb..d7c0f3dd35dae 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ARCFOURCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,7 @@ private void crypt(byte[] in, int inOfs, int inLen, byte[] out, // Modes do not make sense with stream ciphers, but allow ECB // see JCE spec. protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (mode.equalsIgnoreCase("ECB") == false) { + if (!mode.equalsIgnoreCase("ECB")) { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } } @@ -123,7 +123,7 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { // see JCE spec. protected void engineSetPadding(String padding) throws NoSuchPaddingException { - if (padding.equalsIgnoreCase("NoPadding") == false) { + if (!padding.equalsIgnoreCase("NoPadding")) { throw new NoSuchPaddingException("Padding must be NoPadding"); } } @@ -201,7 +201,7 @@ private static byte[] getEncodedKey(Key key) throws InvalidKeyException { if (!keyAlg.equals("RC4") && !keyAlg.equals("ARCFOUR")) { throw new InvalidKeyException("Not an ARCFOUR key: " + keyAlg); } - if ("RAW".equals(key.getFormat()) == false) { + if (!"RAW".equals(key.getFormat())) { throw new InvalidKeyException("Key encoding format must be RAW"); } byte[] encodedKey = key.getEncoded(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java index ed2fda5bf0086..fc39b4ed63480 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,7 +156,7 @@ protected ChaCha20Cipher() { } */ @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (mode.equalsIgnoreCase("None") == false) { + if (!mode.equalsIgnoreCase("None")) { throw new NoSuchAlgorithmException("Mode must be None"); } } @@ -174,7 +174,7 @@ protected void engineSetMode(String mode) throws NoSuchAlgorithmException { @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - if (padding.equalsIgnoreCase("NoPadding") == false) { + if (!padding.equalsIgnoreCase("NoPadding")) { throw new NoSuchPaddingException("Padding must be NoPadding"); } } @@ -326,7 +326,7 @@ protected void engineInit(int opmode, Key key, // We will ignore the secure random implementation and use the nonce // from the AlgorithmParameterSpec instead. - byte[] newNonce = null; + byte[] newNonce; switch (mode) { case MODE_NONE: if (!(params instanceof ChaCha20ParameterSpec)) { @@ -360,7 +360,7 @@ protected void engineInit(int opmode, Key key, /** * Initialize the engine using the {@code AlgorithmParameter} initialization - * format. This cipher does supports initialization with + * format. This cipher supports initialization with * {@code AlgorithmParameter} objects for ChaCha20-Poly1305 but not for * ChaCha20 as a simple stream cipher. In the latter case, it will throw * an {@code InvalidAlgorithmParameterException} if the value is non-null. @@ -618,7 +618,7 @@ private void checkKeyAndNonce(byte[] newKeyBytes, byte[] newNonce) * or if the key encoding format is not {@code RAW}. */ private static byte[] getEncodedKey(Key key) throws InvalidKeyException { - if ("RAW".equals(key.getFormat()) == false) { + if (!"RAW".equals(key.getFormat())) { throw new InvalidKeyException("Key encoding format must be RAW"); } byte[] encodedKey = key.getEncoded(); @@ -675,7 +675,7 @@ protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { @Override protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) throws ShortBufferException { - int bytesUpdated = 0; + int bytesUpdated; try { bytesUpdated = engine.doUpdate(in, inOfs, inLen, out, outOfs); } catch (KeyException ke) { @@ -691,10 +691,10 @@ protected int engineUpdate(byte[] in, int inOfs, int inLen, * @param output ByteBuffer that will hold the resulting data. This * must be large enough to hold the resulting data. * - * @return the length in bytes of the data written into the {@code out} + * @return the length in bytes of the data written into the {@code output} * buffer. * - * @throws ShortBufferException if the buffer {@code out} does not have + * @throws ShortBufferException if the buffer {@code output} does not have * enough space to hold the resulting data. */ @Override @@ -763,7 +763,7 @@ protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) throws ShortBufferException, AEADBadTagException { - int bytesUpdated = 0; + int bytesUpdated; try { bytesUpdated = engine.doFinal(in, inOfs, inLen, out, outOfs); } catch (KeyException ke) { @@ -785,6 +785,9 @@ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, * * @return the resulting plaintext or ciphertext bytes. * + * @throws ShortBufferException if the buffer {@code output} does not have + * enough space to hold the resulting data. + * * @throws AEADBadTagException if, during decryption, the provided tag * does not match the calculated tag. */ @@ -947,12 +950,8 @@ protected int engineGetKeySize(Key key) throws InvalidKeyException { * key and nonce into their proper locations. The counter field is not * set here. * - * @throws IllegalArgumentException if the key or nonce are not in - * their proper lengths (32 bytes for the key, 12 bytes for the - * nonce). - * @throws InvalidKeyException if the key does not support an encoded form. */ - private void setInitialState() throws InvalidKeyException { + private void setInitialState() { // Apply constants to first 4 words startState[0] = STATE_CONST_0; startState[1] = STATE_CONST_1; @@ -1257,11 +1256,11 @@ private int authUpdate(byte[] data, int offset, int length) { * @param out the array to write the resulting tag into * @param outOff the offset to begin writing the data. * - * @throws ShortBufferException if there is insufficient room to + * @throws ProviderException if there is insufficient room to * write the tag. */ private void authFinalizeData(byte[] data, int dataOff, int length, - byte[] out, int outOff) throws ShortBufferException { + byte[] out, int outOff) { // Update with the final chunk of ciphertext, then pad to a // multiple of 16. if (data != null) { @@ -1300,7 +1299,7 @@ private void authPad16(long dataLen) { * @param dLen the length of the application data. * @param buf the buffer to write the two lengths into. * - * @note it is the caller's responsibility to provide an array large + * @implNote it is the caller's responsibility to provide an array large * enough to hold the two longs. */ private void authWriteLengths(long aLen, long dLen, byte[] buf) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java index 762827d0152ff..ab9d4a23e6098 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Poly1305Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,8 +206,7 @@ protected byte[] engineGetEncoded(String encodingMethod) protected String engineToString() { String LINE_SEP = System.lineSeparator(); HexDumpEncoder encoder = new HexDumpEncoder(); - StringBuilder sb = new StringBuilder(LINE_SEP + "nonce:" + - LINE_SEP + "[" + encoder.encodeBuffer(nonce) + "]"); - return sb.toString(); + return LINE_SEP + "nonce:" + + LINE_SEP + "[" + encoder.encodeBuffer(nonce) + "]"; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java index 5d756e2684746..4bd7faea72257 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherBlockChaining.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,7 +180,7 @@ private int implEncrypt(byte[] plain, int plainOffset, int plainLen, * *

    It is also the application's responsibility to make sure that * init has been called before this method is called. - * (This check is omitted here, to avoid double checking.) + * (This check is omitted here, to avoid double-checking.) * * @param cipher the buffer with the input data to be decrypted * @param cipherOffset the offset in cipherOffset diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java index 2555448e3c011..c808756fa1d7a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ final class CipherCore { /* * unit size (number of input bytes that can be processed at a time) */ - private int unitBytes = 0; + private int unitBytes; /* * index of the content size left in the buffer @@ -91,17 +91,17 @@ final class CipherCore { * input bytes that are processed at a time is different from the block * size) */ - private int diffBlocksize = 0; + private int diffBlocksize; /* * padding class */ - private Padding padding = null; + private Padding padding; /* * internal cipher engine */ - private FeedbackCipher cipher = null; + private FeedbackCipher cipher; /* * the cipher mode @@ -136,7 +136,7 @@ final class CipherCore { /* * The buffer should be usable for all cipher mode and padding * schemes. Thus, it has to be at least (blockSize+1) for CTS. - * In decryption mode, it also hold the possible padding block. + * In decryption mode, it also holds the possible padding block. */ buffer = new byte[blockSize*2]; @@ -334,7 +334,7 @@ AlgorithmParameters getParameters(String algName) { if (cipherMode == ECB_MODE) { return null; } - AlgorithmParameters params = null; + AlgorithmParameters params; AlgorithmParameterSpec spec; byte[] iv = getIV(); if (iv == null) { @@ -545,7 +545,7 @@ static byte[] getKeyBytes(Key key) throws InvalidKeyException { */ byte[] update(byte[] input, int inputOffset, int inputLen) { - byte[] output = null; + byte[] output; try { output = new byte[getOutputSizeByOperation(inputLen, false)]; int len = update(input, inputOffset, inputLen, output, @@ -930,8 +930,7 @@ private byte[] prepareInputBuffer(byte[] input, int inputOffset, private int fillOutputBuffer(byte[] finalBuf, int finalOffset, byte[] output, int outOfs, int finalBufLen, byte[] input) - throws ShortBufferException, BadPaddingException, - IllegalBlockSizeException { + throws BadPaddingException, IllegalBlockSizeException { int len; try { @@ -967,7 +966,7 @@ private int checkOutputCapacity(byte[] output, int outputOffset, private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs, int len) - throws IllegalBlockSizeException, ShortBufferException { + throws IllegalBlockSizeException { if (in == null || len == 0) { return 0; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java b/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java index 630f8707fdeb7..da46f220825a5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/CipherTextStealing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ package com.sun.crypto.provider; import javax.crypto.IllegalBlockSizeException; -import javax.crypto.ShortBufferException; /** * This class represents ciphers in cipher text stealing (CTS) mode. @@ -153,7 +152,7 @@ int encryptFinal(byte[] plain, int plainOffset, int plainLen, * *

    It is also the application's responsibility to make sure that * init has been called before this method is called. - * (This check is omitted here, to avoid double checking.) + * (This check is omitted here, to avoid double-checking.) * * @param cipher the buffer with the input data to be decrypted * @param cipherOffset the offset in cipherOffset diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java b/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java index e8375d1eb8182..2019104941efd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ final class ConstructKeys { private static final PublicKey constructPublicKey(byte[] encodedKey, int ofs, int len, String encodedKeyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException { - PublicKey key = null; + PublicKey key; byte[] keyBytes = (ofs == 0 && encodedKey.length == len) ? encodedKey : Arrays.copyOfRange(encodedKey, ofs, ofs + len); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); @@ -88,7 +88,7 @@ private static final PublicKey constructPublicKey(byte[] encodedKey, private static final PrivateKey constructPrivateKey(byte[] encodedKey, int ofs, int len, String encodedKeyAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException { - PrivateKey key = null; + PrivateKey key; byte[] keyBytes = (ofs == 0 && encodedKey.length == len) ? encodedKey : Arrays.copyOfRange(encodedKey, ofs, ofs + len); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java b/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java index acbde75cd8426..29a5ba2540860 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESCrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ */ class DESCrypt extends SymmetricCipher implements DESConstants { - private static final int s0p[] = { + private static final int[] s0p = { 0x00410100, 0x00010000, 0x40400000, 0x40410100, 0x00400000, 0x40010100, 0x40010000, 0x40400000, 0x40010100, 0x00410100, 0x00410000, 0x40000100, 0x40400100, 0x00400000, 0x00000000, @@ -56,7 +56,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x40000000, 0x40410000, 0x00000100, 0x40010100, }; - private static final int s1p[] = { + private static final int[] s1p = { 0x08021002, 0x00000000, 0x00021000, 0x08020000, 0x08000002, 0x00001002, 0x08001000, 0x00021000, 0x00001000, 0x08020002, 0x00000002, 0x08001000, 0x00020002, 0x08021000, 0x08020000, @@ -72,7 +72,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x08001002, 0x00000002, 0x08020000, 0x00021000, }; - private static final int s2p[] = { + private static final int[] s2p = { 0x20800000, 0x00808020, 0x00000020, 0x20800020, 0x20008000, 0x00800000, 0x20800020, 0x00008020, 0x00800020, 0x00008000, 0x00808000, 0x20000000, 0x20808020, 0x20000020, 0x20000000, @@ -88,7 +88,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x20800000, 0x20008020, 0x00000020, 0x00808000, }; - private static final int s3p[] = { + private static final int[] s3p = { 0x00080201, 0x02000200, 0x00000001, 0x02080201, 0x00000000, 0x02080000, 0x02000201, 0x00080001, 0x02080200, 0x02000001, 0x02000000, 0x00000201, 0x02000001, 0x00080201, 0x00080000, @@ -104,7 +104,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x00000201, 0x02000000, 0x02000001, 0x02080200, }; - private static final int s4p[] = { + private static final int[] s4p = { 0x01000000, 0x00002000, 0x00000080, 0x01002084, 0x01002004, 0x01000080, 0x00002084, 0x01002000, 0x00002000, 0x00000004, 0x01000004, 0x00002080, 0x01000084, 0x01002004, 0x01002080, @@ -120,7 +120,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x00000004, 0x00002084, 0x01002000, 0x01000004, }; - private static final int s5p[] = { + private static final int[] s5p = { 0x10000008, 0x00040008, 0x00000000, 0x10040400, 0x00040008, 0x00000400, 0x10000408, 0x00040000, 0x00000408, 0x10040408, 0x00040400, 0x10000000, 0x10000400, 0x10000008, 0x10040000, @@ -136,7 +136,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x10040000, 0x00000408, 0x00000008, 0x10040008, }; - private static final int s6p[] = { + private static final int[] s6p = { 0x00000800, 0x00000040, 0x00200040, 0x80200000, 0x80200840, 0x80000800, 0x00000840, 0x00000000, 0x00200000, 0x80200040, 0x80000040, 0x00200800, 0x80000000, 0x00200840, 0x00200800, @@ -152,7 +152,7 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x80200000, 0x00200840, 0x00200800, 0x80000800, }; - private static final int s7p[] = { + private static final int[] s7p = { 0x04100010, 0x04104000, 0x00004010, 0x00000000, 0x04004000, 0x00100010, 0x04100000, 0x04104010, 0x00000010, 0x04000000, 0x00104000, 0x00004010, 0x00104010, 0x04004010, 0x04000010, @@ -168,112 +168,112 @@ class DESCrypt extends SymmetricCipher implements DESConstants { 0x04000000, 0x04100010, 0x00004000, 0x00104010, }; - private static final int permRight0[] = { + private static final int[] permRight0 = { 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, }; - private static final int permLeft1[] = { + private static final int[] permLeft1 = { 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, }; - private static final int permRight2[] = { + private static final int[] permRight2 = { 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, }; - private static final int permLeft3[] = { + private static final int[] permLeft3 = { 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, }; - private static final int permRight4[] = { + private static final int[] permRight4 = { 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, }; - private static final int permLeft5[] = { + private static final int[] permLeft5 = { 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, }; - private static final int permRight6[] = { + private static final int[] permRight6 = { 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, }; - private static final int permLeft7[] = { + private static final int[] permLeft7 = { 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, }; - private static final int permRight8[] = { + private static final int[] permRight8 = { 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, }; - private static final int permLeft9[] = { + private static final int[] permLeft9 = { 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, }; - private static final int permRightA[] = { + private static final int[] permRightA = { 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, }; - private static final int permLeftB[] = { + private static final int[] permLeftB = { 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, }; - private static final int permRightC[] = { + private static final int[] permRightC = { 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, }; - private static final int permLeftD[] = { + private static final int[] permLeftD = { 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, }; - private static final int permRightE[] = { + private static final int[] permRightE = { 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, }; - private static final int permLeftF[] = { + private static final int[] permLeftF = { 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, @@ -283,224 +283,224 @@ class DESCrypt extends SymmetricCipher implements DESConstants { /* * Initial Permutation */ - private static final int initPermLeft0[] = { + private static final int[] initPermLeft0 = { 0x00000000, 0x00008000, 0x00000000, 0x00008000, 0x00000080, 0x00008080, 0x00000080, 0x00008080, 0x00000000, 0x00008000, 0x00000000, 0x00008000, 0x00000080, 0x00008080, 0x00000080, 0x00008080, }; - private static final int initPermRight0[] = { + private static final int[] initPermRight0 = { 0x00000000, 0x00000000, 0x00008000, 0x00008000, 0x00000000, 0x00000000, 0x00008000, 0x00008000, 0x00000080, 0x00000080, 0x00008080, 0x00008080, 0x00000080, 0x00000080, 0x00008080, 0x00008080, }; - private static final int initPermLeft1[] = { + private static final int[] initPermLeft1 = { 0x00000000, 0x80000000, 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00800000, 0x80800000, 0x00000000, 0x80000000, 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00800000, 0x80800000, }; - private static final int initPermRight1[] = { + private static final int[] initPermRight1 = { 0x00000000, 0x00000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, 0x80000000, 0x80000000, 0x00800000, 0x00800000, 0x80800000, 0x80800000, 0x00800000, 0x00800000, 0x80800000, 0x80800000, }; - private static final int initPermLeft2[] = { + private static final int[] initPermLeft2 = { 0x00000000, 0x00004000, 0x00000000, 0x00004000, 0x00000040, 0x00004040, 0x00000040, 0x00004040, 0x00000000, 0x00004000, 0x00000000, 0x00004000, 0x00000040, 0x00004040, 0x00000040, 0x00004040, }; - private static final int initPermRight2[] = { + private static final int[] initPermRight2 = { 0x00000000, 0x00000000, 0x00004000, 0x00004000, 0x00000000, 0x00000000, 0x00004000, 0x00004000, 0x00000040, 0x00000040, 0x00004040, 0x00004040, 0x00000040, 0x00000040, 0x00004040, 0x00004040, }; - private static final int initPermLeft3[] = { + private static final int[] initPermLeft3 = { 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00400000, 0x40400000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00400000, 0x40400000, }; - private static final int initPermRight3[] = { + private static final int[] initPermRight3 = { 0x00000000, 0x00000000, 0x40000000, 0x40000000, 0x00000000, 0x00000000, 0x40000000, 0x40000000, 0x00400000, 0x00400000, 0x40400000, 0x40400000, 0x00400000, 0x00400000, 0x40400000, 0x40400000, }; - private static final int initPermLeft4[] = { + private static final int[] initPermLeft4 = { 0x00000000, 0x00002000, 0x00000000, 0x00002000, 0x00000020, 0x00002020, 0x00000020, 0x00002020, 0x00000000, 0x00002000, 0x00000000, 0x00002000, 0x00000020, 0x00002020, 0x00000020, 0x00002020, }; - private static final int initPermRight4[] = { + private static final int[] initPermRight4 = { 0x00000000, 0x00000000, 0x00002000, 0x00002000, 0x00000000, 0x00000000, 0x00002000, 0x00002000, 0x00000020, 0x00000020, 0x00002020, 0x00002020, 0x00000020, 0x00000020, 0x00002020, 0x00002020, }; - private static final int initPermLeft5[] = { + private static final int[] initPermLeft5 = { 0x00000000, 0x20000000, 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00200000, 0x20200000, 0x00000000, 0x20000000, 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00200000, 0x20200000, }; - private static final int initPermRight5[] = { + private static final int[] initPermRight5 = { 0x00000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x20000000, 0x20000000, 0x00200000, 0x00200000, 0x20200000, 0x20200000, 0x00200000, 0x00200000, 0x20200000, 0x20200000, }; - private static final int initPermLeft6[] = { + private static final int[] initPermLeft6 = { 0x00000000, 0x00001000, 0x00000000, 0x00001000, 0x00000010, 0x00001010, 0x00000010, 0x00001010, 0x00000000, 0x00001000, 0x00000000, 0x00001000, 0x00000010, 0x00001010, 0x00000010, 0x00001010, }; - private static final int initPermRight6[] = { + private static final int[] initPermRight6 = { 0x00000000, 0x00000000, 0x00001000, 0x00001000, 0x00000000, 0x00000000, 0x00001000, 0x00001000, 0x00000010, 0x00000010, 0x00001010, 0x00001010, 0x00000010, 0x00000010, 0x00001010, 0x00001010, }; - private static final int initPermLeft7[] = { + private static final int[] initPermLeft7 = { 0x00000000, 0x10000000, 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00100000, 0x10100000, 0x00000000, 0x10000000, 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00100000, 0x10100000, }; - private static final int initPermRight7[] = { + private static final int[] initPermRight7 = { 0x00000000, 0x00000000, 0x10000000, 0x10000000, 0x00000000, 0x00000000, 0x10000000, 0x10000000, 0x00100000, 0x00100000, 0x10100000, 0x10100000, 0x00100000, 0x00100000, 0x10100000, 0x10100000, }; - private static final int initPermLeft8[] = { + private static final int[] initPermLeft8 = { 0x00000000, 0x00000800, 0x00000000, 0x00000800, 0x00000008, 0x00000808, 0x00000008, 0x00000808, 0x00000000, 0x00000800, 0x00000000, 0x00000800, 0x00000008, 0x00000808, 0x00000008, 0x00000808, }; - private static final int initPermRight8[] = { + private static final int[] initPermRight8 = { 0x00000000, 0x00000000, 0x00000800, 0x00000800, 0x00000000, 0x00000000, 0x00000800, 0x00000800, 0x00000008, 0x00000008, 0x00000808, 0x00000808, 0x00000008, 0x00000008, 0x00000808, 0x00000808, }; - private static final int initPermLeft9[] = { + private static final int[] initPermLeft9 = { 0x00000000, 0x08000000, 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00080000, 0x08080000, 0x00000000, 0x08000000, 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00080000, 0x08080000, }; - private static final int initPermRight9[] = { + private static final int[] initPermRight9 = { 0x00000000, 0x00000000, 0x08000000, 0x08000000, 0x00000000, 0x00000000, 0x08000000, 0x08000000, 0x00080000, 0x00080000, 0x08080000, 0x08080000, 0x00080000, 0x00080000, 0x08080000, 0x08080000, }; - private static final int initPermLeftA[] = { + private static final int[] initPermLeftA = { 0x00000000, 0x00000400, 0x00000000, 0x00000400, 0x00000004, 0x00000404, 0x00000004, 0x00000404, 0x00000000, 0x00000400, 0x00000000, 0x00000400, 0x00000004, 0x00000404, 0x00000004, 0x00000404, }; - private static final int initPermRightA[] = { + private static final int[] initPermRightA = { 0x00000000, 0x00000000, 0x00000400, 0x00000400, 0x00000000, 0x00000000, 0x00000400, 0x00000400, 0x00000004, 0x00000004, 0x00000404, 0x00000404, 0x00000004, 0x00000004, 0x00000404, 0x00000404, }; - private static final int initPermLeftB[] = { + private static final int[] initPermLeftB = { 0x00000000, 0x04000000, 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00040000, 0x04040000, 0x00000000, 0x04000000, 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00040000, 0x04040000, }; - private static final int initPermRightB[] = { + private static final int[] initPermRightB = { 0x00000000, 0x00000000, 0x04000000, 0x04000000, 0x00000000, 0x00000000, 0x04000000, 0x04000000, 0x00040000, 0x00040000, 0x04040000, 0x04040000, 0x00040000, 0x00040000, 0x04040000, 0x04040000, }; - private static final int initPermLeftC[] = { + private static final int[] initPermLeftC = { 0x00000000, 0x00000200, 0x00000000, 0x00000200, 0x00000002, 0x00000202, 0x00000002, 0x00000202, 0x00000000, 0x00000200, 0x00000000, 0x00000200, 0x00000002, 0x00000202, 0x00000002, 0x00000202, }; - private static final int initPermRightC[] = { + private static final int[] initPermRightC = { 0x00000000, 0x00000000, 0x00000200, 0x00000200, 0x00000000, 0x00000000, 0x00000200, 0x00000200, 0x00000002, 0x00000002, 0x00000202, 0x00000202, 0x00000002, 0x00000002, 0x00000202, 0x00000202, }; - private static final int initPermLeftD[] = { + private static final int[] initPermLeftD = { 0x00000000, 0x02000000, 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00020000, 0x02020000, 0x00000000, 0x02000000, 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00020000, 0x02020000, }; - private static final int initPermRightD[] = { + private static final int[] initPermRightD = { 0x00000000, 0x00000000, 0x02000000, 0x02000000, 0x00000000, 0x00000000, 0x02000000, 0x02000000, 0x00020000, 0x00020000, 0x02020000, 0x02020000, 0x00020000, 0x00020000, 0x02020000, 0x02020000, }; - private static final int initPermLeftE[] = { + private static final int[] initPermLeftE = { 0x00000000, 0x00000100, 0x00000000, 0x00000100, 0x00000001, 0x00000101, 0x00000001, 0x00000101, 0x00000000, 0x00000100, 0x00000000, 0x00000100, 0x00000001, 0x00000101, 0x00000001, 0x00000101, }; - private static final int initPermRightE[] = { + private static final int[] initPermRightE = { 0x00000000, 0x00000000, 0x00000100, 0x00000100, 0x00000000, 0x00000000, 0x00000100, 0x00000100, 0x00000001, 0x00000001, 0x00000101, 0x00000101, 0x00000001, 0x00000001, 0x00000101, 0x00000101, }; - private static final int initPermLeftF[] = { + private static final int[] initPermLeftF = { 0x00000000, 0x01000000, 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00010000, 0x01010000, 0x00000000, 0x01000000, 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00010000, 0x01010000, }; - private static final int initPermRightF[] = { + private static final int[] initPermRightF = { 0x00000000, 0x00000000, 0x01000000, 0x01000000, 0x00000000, 0x00000000, 0x01000000, 0x01000000, 0x00010000, 0x00010000, 0x01010000, 0x01010000, 0x00010000, 0x00010000, 0x01010000, @@ -586,7 +586,7 @@ void decryptBlock(byte[] cipher, int cipherOffset, void cipherBlock(byte[] in, int inOffset, byte[] out, int outOffset) { - byte key[]; + byte[] key; int temp; int i, j; int offset; @@ -638,7 +638,7 @@ void cipherBlock(byte[] in, int inOffset, byte[] out, int outOffset) { } private static void perm(int left, int right, - byte out[], int offset) { + byte[] out, int offset) { int low, high, temp; temp = left; @@ -687,7 +687,7 @@ private static void perm(int left, int right, } - private static int initialPermutationLeft(byte block[], int offset) { + private static int initialPermutationLeft(byte[] block, int offset) { int l; l = initPermLeft1[block[offset] & 0xf]; @@ -709,7 +709,7 @@ private static int initialPermutationLeft(byte block[], int offset) { return l; } - private static int initialPermutationRight(byte block[], int offset) { + private static int initialPermutationRight(byte[] block, int offset) { int l; l = initPermRight1[block[offset] & 0xf]; @@ -731,9 +731,9 @@ private static int initialPermutationRight(byte block[], int offset) { return l; } - void expandKey(byte key[]) { + void expandKey(byte[] key) { int octet; - byte ek[] = new byte[128]; + byte[] ek = new byte[128]; octet = key[0]; if ((octet & 0x80) != 0) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java index fa06797abc293..fd3320b070d54 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ protected KeySpec engineGetKeySpec(SecretKey key, Class keySpec) try { - if ((key instanceof SecretKey) + if ((key != null) && (key.getAlgorithm().equalsIgnoreCase("DES")) && (key.getFormat().equalsIgnoreCase("RAW"))) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java index fd20415bb2d4a..b769aab417b22 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ protected KeySpec engineGetKeySpec(SecretKey key, Class keySpec) throws InvalidKeySpecException { try { - if ((key instanceof SecretKey) + if ((key != null) && (key.getAlgorithm().equalsIgnoreCase("DESede")) && (key.getFormat().equalsIgnoreCase("RAW"))) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java index 28684b0f9e7af..325c0588777d1 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ protected SecretKey engineGenerateKey() { java.util.Arrays.fill(tmpkey, (byte)0x00); } - DESedeKey desEdeKey = null; + DESedeKey desEdeKey; try { desEdeKey = new DESedeKey(rawkey); } catch (InvalidKeyException ike) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java index 92d25b57a7e50..f9281ae929536 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,13 +137,13 @@ protected int engineGetBlockSize() { */ protected int engineGetOutputSize(int inputLen) { // can only return an upper-limit if not initialized yet. - int result = 0; + int result; if (decrypting) { result = inputLen - 16; // CHECKSUM_LEN + IV_LEN; } else { result = Math.addExact(inputLen, 16); } - return (result < 0? 0:result); + return (Math.max(result, 0)); } /** @@ -210,7 +210,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - byte[] currIv = null; + byte[] currIv; if (opmode == Cipher.WRAP_MODE) { decrypting = false; if (params == null) { @@ -380,7 +380,7 @@ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, /** * Returns the parameters used with this cipher. * Note that null maybe returned if this cipher does not use any - * parameters or when it has not be set, e.g. initialized with + * parameters or when it has not been set, e.g. initialized with * UNWRAP_MODE but wrapped key data has not been given. * * @return the parameters used with this cipher; can be null. @@ -556,9 +556,8 @@ protected Key engineUnwrap(byte[] wrappedKey, buffer2, 0); int keyValLen = buffer2.length - CHECKSUM_LEN; byte[] cks = getChecksum(buffer2, 0, keyValLen); - int offset = keyValLen; for (int i = 0; i < CHECKSUM_LEN; i++) { - if (buffer2[offset + i] != cks[i]) { + if (buffer2[keyValLen + i] != cks[i]) { throw new InvalidKeyException("Checksum comparison failed"); } } @@ -588,7 +587,7 @@ private static final byte[] getChecksum(byte[] in) { return getChecksum(in, 0, in.length); } private static final byte[] getChecksum(byte[] in, int offset, int len) { - MessageDigest md = null; + MessageDigest md; try { md = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException nsae) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java index bd1c3f7c38053..3fa6b14762ac2 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,21 +24,23 @@ */ package com.sun.crypto.provider; -import sun.security.jca.JCAUtil; -import sun.security.ssl.HKDF; -import sun.security.util.*; - -import javax.crypto.*; -import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; -import java.nio.charset.StandardCharsets; import java.security.*; -import java.security.interfaces.*; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.XECKey; +import java.security.interfaces.XECPublicKey; import java.security.spec.*; import java.util.Arrays; import java.util.Objects; +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; + +import sun.security.jca.JCAUtil; +import sun.security.ssl.HKDF; +import sun.security.util.*; // Implementing DHKEM defined inside https://www.rfc-editor.org/rfc/rfc9180.html, // without the AuthEncap and AuthDecap functions diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java index 01f978fff615f..5eebf98acc3d8 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyAgreement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,15 @@ package com.sun.crypto.provider; -import java.util.*; -import java.lang.*; import java.math.BigInteger; -import java.security.AccessController; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.PrivilegedAction; -import java.security.ProviderException; +import java.security.*; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; import javax.crypto.KeyAgreementSpi; -import javax.crypto.ShortBufferException; import javax.crypto.SecretKey; -import javax.crypto.spec.*; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; import sun.security.util.KeyUtil; @@ -180,7 +172,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params, * @param key the key for this phase. For example, in the case of * Diffie-Hellman between 2 parties, this would be the other party's * Diffie-Hellman public key. - * @param lastPhase flag which indicates whether or not this is the last + * @param lastPhase flag which indicates if this is the last * phase of this key agreement. * * @return the (intermediate) key resulting from this phase, or null if @@ -227,7 +219,7 @@ protected Key engineDoPhase(Key key, boolean lastPhase) // intermediate secret, in which case we wrap it into a // Diffie-Hellman public key object and return it. generateSecret = true; - if (lastPhase == false) { + if (!lastPhase) { byte[] intermediate = engineGenerateSecret(); return new DHPublicKey(new BigInteger(1, intermediate), init_p, init_g); @@ -293,7 +285,7 @@ protected byte[] engineGenerateSecret() protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { - if (generateSecret == false) { + if (!generateSecret) { throw new IllegalStateException ("Key agreement has not been completed yet"); } @@ -413,9 +405,7 @@ protected SecretKey engineGenerateSecret(String algorithm) int keysize = secret.length; if (keysize >= BlowfishConstants.BLOWFISH_MAX_KEYSIZE) keysize = BlowfishConstants.BLOWFISH_MAX_KEYSIZE; - SecretKeySpec skey = new SecretKeySpec(secret, 0, keysize, - "Blowfish"); - return skey; + return new SecretKeySpec(secret, 0, keysize, "Blowfish"); } else if (algorithm.equalsIgnoreCase("AES")) { // AES int keysize = secret.length; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java index 4cc979cb29a89..89d4fcfc402cb 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,10 @@ import java.math.BigInteger; import java.security.*; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.DHParameterSpec; -import javax.crypto.spec.DHGenParameterSpec; import sun.security.provider.ParameterCache; + import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE; import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java b/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java index c2085816453d5..ba8a564be11f8 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ElectronicCodeBook.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,9 @@ import java.security.InvalidKeyException; import java.security.ProviderException; -import sun.security.util.ArrayUtil; -import java.util.Objects; + import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in electronic codebook (ECB) mode. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java index 6c0e10eb6d0a4..985c1b81f4393 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/FeedbackCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,7 @@ abstract int encrypt(byte[] plain, int plainOffset, int plainLen, */ int encryptFinal(byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) - throws IllegalBlockSizeException, ShortBufferException { + throws IllegalBlockSizeException { return encrypt(plain, plainOffset, plainLen, cipher, cipherOffset); } /** @@ -199,7 +199,7 @@ abstract int decrypt(byte[] cipher, int cipherOffset, int cipherLen, */ int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset) - throws IllegalBlockSizeException, ShortBufferException { + throws IllegalBlockSizeException { return decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java index 7aaec3d6c1ae1..926a56c140b66 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,8 +79,7 @@ private long blocksUntilRollover() { ByteBuffer buf = ByteBuffer.wrap(counter, counter.length - 4, 4); buf.order(ByteOrder.BIG_ENDIAN); long ctr32 = 0xFFFFFFFFL & buf.getInt(); - long blocksLeft = (1L << 32) - ctr32; - return blocksLeft; + return (1L << 32) - ctr32; } private void checkBlock() { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java index b7aaf6059d535..6b8c2e9c1a965 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -190,9 +190,8 @@ int update(ByteBuffer ct, int inLen) { // If ct is a direct bytebuffer, send it directly to the intrinsic if (ct.isDirect()) { - int processed = inLen; processBlocksDirect(ct, inLen); - return processed; + return inLen; } else if (!ct.isReadOnly()) { // If a non-read only heap bytebuffer, use the array update method int processed = update(ct.array(), @@ -273,7 +272,7 @@ private static void ghashRangeCheck(byte[] in, int inOfs, int inLen, /* * This is an intrinsified method. The method's argument list must match * the hotspot signature. This method and methods called by it, cannot - * throw exceptions or allocate arrays as it will breaking intrinsics + * throw exceptions or allocate arrays as it will break intrinsics. */ @IntrinsicCandidate private static void processBlocks(byte[] data, int inOfs, int blocks, diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 8cfd7d13f12b2..44cfb76d1628e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,38 +25,24 @@ package com.sun.crypto.provider; -import jdk.internal.access.JavaNioAccess; -import jdk.internal.access.SharedSecrets; -import jdk.internal.misc.Unsafe; -import sun.nio.ch.DirectBuffer; -import sun.security.jca.JCAUtil; -import sun.security.util.ArrayUtil; - -import javax.crypto.AEADBadTagException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.CipherSpi; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.GCMParameterSpec; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.ProviderException; -import java.security.SecureRandom; +import java.security.*; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.util.Arrays; +import javax.crypto.*; +import javax.crypto.spec.GCMParameterSpec; +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.nio.ch.DirectBuffer; +import sun.security.jca.JCAUtil; +import sun.security.util.ArrayUtil; /** * This class represents ciphers in GaloisCounter (GCM) mode. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java index fecc30a5a085d..c6707fb994113 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,12 @@ package com.sun.crypto.provider; -import java.util.Arrays; - import java.nio.ByteBuffer; - +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; import javax.crypto.MacSpi; import javax.crypto.SecretKey; -import java.security.*; -import java.security.spec.*; - -import sun.security.x509.AlgorithmId; /** * This class constitutes the core of HMAC- algorithms, where @@ -87,8 +83,7 @@ abstract class HmacCore extends MacSpi implements Cloneable { break; } } - } catch (NoSuchAlgorithmException nsae) { - continue; + } catch (NoSuchAlgorithmException ignored) { } } if (md == null) { @@ -169,7 +164,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) * @param input the input byte to be processed. */ protected void engineUpdate(byte input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); first = false; @@ -187,8 +182,8 @@ protected void engineUpdate(byte input) { * @param offset the offset in input where the input starts. * @param len the number of bytes to process. */ - protected void engineUpdate(byte input[], int offset, int len) { - if (first == true) { + protected void engineUpdate(byte[] input, int offset, int len) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); first = false; @@ -205,7 +200,7 @@ protected void engineUpdate(byte input[], int offset, int len) { * @param input the input byte buffer. */ protected void engineUpdate(ByteBuffer input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); first = false; @@ -221,7 +216,7 @@ protected void engineUpdate(ByteBuffer input) { * @return the HMAC result. */ protected byte[] engineDoFinal() { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(k_ipad); } else { @@ -250,7 +245,7 @@ protected byte[] engineDoFinal() { * HMAC was initialized with. */ protected void engineReset() { - if (first == false) { + if (!first) { md.reset(); first = true; } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java index ccf85561db9ec..3e85ad51bb3bd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,7 @@ package com.sun.crypto.provider; -import java.nio.ByteBuffer; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; -import java.security.*; -import java.security.spec.*; +import java.security.NoSuchAlgorithmException; /** * This is an implementation of the HMAC-MD5 algorithm. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java index ba29e3c74793e..2634128dd286a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,8 @@ package com.sun.crypto.provider; -import java.security.SecureRandom; -import java.security.InvalidParameterException; import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java index b79dc9d96584c..0a17cad0ea397 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,7 @@ package com.sun.crypto.provider; -import java.nio.ByteBuffer; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; -import java.security.*; -import java.security.spec.*; +import java.security.NoSuchAlgorithmException; /** * This is an implementation of the HMAC-SHA1 algorithm. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java index 9d92d60ae3656..1997777750348 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,8 @@ package com.sun.crypto.provider; -import java.security.SecureRandom; -import java.security.InvalidParameterException; import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java b/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java index a86f313e2c9e1..43f153422849b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ISO10126Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,7 +119,6 @@ public int unpad(byte[] in, int off, int len) { * @return the length of the padding */ public int padLength(int len) { - int paddingOctet = blockSize - (len % blockSize); - return paddingOctet; + return blockSize - (len % blockSize); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java b/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java index fcc450387af9c..ab8f2d7097b04 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ private static final class PrivateKeyEntry { Date date; // the creation date of this entry byte[] protectedKey; Certificate[] chain; - }; + } // Secret key private static final class SecretKeyEntry { @@ -93,7 +93,7 @@ private static final class SecretKeyEntry { private static final class TrustedCertEntry { Date date; // the creation date of this entry Certificate cert; - }; + } /** * Private keys and certificates are stored in a hashtable. @@ -119,7 +119,7 @@ private static final class TrustedCertEntry { public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { - Key key = null; + Key key; Object entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); @@ -652,7 +652,7 @@ public void engineStore(OutputStream stream, char[] password) * the keystore (such as deleting or modifying key or * certificate entries). */ - byte digest[] = md.digest(); + byte[] digest = md.digest(); dos.write(digest); dos.flush(); @@ -691,8 +691,8 @@ public void engineLoad(InputStream stream, char[] password) MessageDigest md = null; CertificateFactory cf = null; Hashtable cfs = null; - ByteArrayInputStream bais = null; - byte[] encoded = null; + ByteArrayInputStream bais; + byte[] encoded; int trustedKeyCount = 0, privateKeyCount = 0, secretKeyCount = 0; if (stream == null) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java b/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java index 7892ca198a8e6..e5dc892032694 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KWUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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,10 +26,6 @@ package com.sun.crypto.provider; import java.util.Arrays; -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; -import javax.crypto.spec.*; /** * This class acts as the base class for AES KeyWrap algorithms as defined @@ -58,7 +54,7 @@ static final int W(byte[] icvIn, byte[] in, int inLen, ("Invalid data length for W: " + inLen); assert(icvIn.length == SEMI_BLKSIZE) : "Invalid ICV buffer size"; - // overwrite the first block of in with the icv semiblock + // overwrite the first block of in with the icv semi-block System.arraycopy(icvIn, 0, in, 0, SEMI_BLKSIZE); int n = inLen / SEMI_BLKSIZE - 1; @@ -93,7 +89,7 @@ static final int W(byte[] icvIn, byte[] in, int inLen, * data until the initial value and padding bytes are verified. * @param in input bytes, i.e. the to-be-processed data * @param inLen length of the to-be-processed bytes - * @param ivOut buffer for holding the recovered ICV semiblock + * @param ivOut buffer for holding the recovered ICV semi-block * @param cipher the initialized cipher object used * @return the recovered data length, i.e. {@code (inLen - icvOut.length)} */ diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java index eadc032b36ac6..f2d3efd685c06 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ final class KeyProtector { iterationCount > MAX_ITERATION_COUNT) { iterationCount = DEFAULT_ITERATION_COUNT; } - } catch (NumberFormatException e) {} + } catch (NumberFormatException ignored) {} } ITERATION_COUNT = iterationCount; } @@ -369,7 +369,7 @@ Key unseal(SealedObject so, int maxLength) sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); pbeKeySpec.clearPassword(); - SealedObjectForKeyProtector soForKeyProtector = null; + SealedObjectForKeyProtector soForKeyProtector; if (!(so instanceof SealedObjectForKeyProtector)) { soForKeyProtector = new SealedObjectForKeyProtector(so); } else { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java index dfd2ec2b04bb5..fb69a27c62d51 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyWrapCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -285,7 +285,7 @@ protected int engineGetOutputSize(int inLen) { padLen = SEMI_BLKSIZE - n; } } - // then add the first semiblock and padLen to result + // then add the first semi-block and padLen to result result = Math.addExact(result, SEMI_BLKSIZE + padLen); } else { result = inLen - SEMI_BLKSIZE; @@ -339,7 +339,7 @@ private void implInit(int opmode, Key key, byte[] iv, SecureRandom random) protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { try { - implInit(opmode, key, (byte[])null, random); + implInit(opmode, key, null, random); } catch (InvalidAlgorithmParameterException iae) { // should never happen throw new AssertionError(iae); @@ -394,9 +394,9 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, byte[] iv = null; if (params != null) { try { - AlgorithmParameterSpec spec = + IvParameterSpec spec = params.getParameterSpec(IvParameterSpec.class); - iv = ((IvParameterSpec)spec).getIV(); + iv = spec.getIV(); } catch (InvalidParameterSpecException ispe) { throw new InvalidAlgorithmParameterException( "Only IvParameterSpec is accepted"); @@ -462,7 +462,7 @@ private void implUpdate(byte[] in, int inOfs, int inLen) { if (inLen <= 0) return; if (opmode == Cipher.ENCRYPT_MODE && dataIdx == 0) { - // the first semiblock is for iv, store data after it + // the first semi-block is for iv, store data after it dataIdx = SEMI_BLKSIZE; } store(in, inOfs, inLen); @@ -595,8 +595,8 @@ private int implDoFinal(byte[] in, int inOfs, int inLen, byte[] out) } // helper routine for in-place encryption. - // 'inBuf' = semiblock | plain text | extra bytes if padding is used - // 'inLen' = semiblock length + plain text length + // 'inBuf' = semi-block | plain text | extra bytes if padding is used + // 'inLen' = semi-block length + plain text length private int helperEncrypt(byte[] inBuf, int inLen) throws IllegalBlockSizeException, ShortBufferException { @@ -646,7 +646,7 @@ private int helperDecrypt(byte[] inBuf, int inLen) */ @Override protected AlgorithmParameters engineGetParameters() { - AlgorithmParameters params = null; + AlgorithmParameters params; byte[] iv = cipher.getIV(); if (iv == null) { @@ -711,7 +711,7 @@ protected byte[] engineWrap(Key key) // output size is known, allocate output buffer byte[] out = new byte[engineGetOutputSize(encoded.length)]; - // reserve the first semiblock and do not write data + // reserve the first semi-block and do not write data int len = SEMI_BLKSIZE; System.arraycopy(encoded, 0, out, len, encoded.length); len += encoded.length; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java b/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java index 9d72472889357..3b826aa38f283 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/OAEPParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,11 +225,9 @@ protected byte[] engineGetEncoded(String encodingMethod) } protected String engineToString() { - StringBuilder sb = new StringBuilder(); - sb.append("MD: " + mdName + "\n"); - sb.append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n"); - sb.append("PSource: PSpecified " + - (p.length==0? "":Debug.toHexString(new BigInteger(p))) + "\n"); - return sb.toString(); + return "MD: " + mdName + "\n" + + "MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n" + + "PSource: PSpecified " + + (p.length == 0 ? "" : Debug.toHexString(new BigInteger(p))) + "\n"; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java b/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java index aa56144f09052..414659fcf3d40 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/OutputFeedback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ final class OutputFeedback extends FeedbackCipher { private final byte[] register; /* - * number of bytes for each stream unit, defaults to the blocksize + * number of bytes for each stream unit, defaults to the block size * of the embedded cipher */ private final int numBytes; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java index 02451e536c677..da73d0bc7ce95 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -261,7 +261,7 @@ protected SecretKey engineGenerateSecret(KeySpec keySpec) */ protected KeySpec engineGetKeySpec(SecretKey key, Class keySpecCl) throws InvalidKeySpecException { - if ((key instanceof SecretKey) + if ((key != null) && (validTypes.contains(key.getAlgorithm().toUpperCase(Locale.ENGLISH))) && (key.getFormat().equalsIgnoreCase("RAW"))) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java index 68b1771d7d967..e10b0b1a7cfb5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,7 +161,7 @@ byte[] getIV() { * does not use any parameters. */ AlgorithmParameters getParameters() { - AlgorithmParameters params = null; + AlgorithmParameters params; if (salt == null) { salt = new byte[8]; SunJCE.getRandom().nextBytes(salt); @@ -303,7 +303,7 @@ private byte[] deriveCipherKey(byte[] passwdBytes) { // Concatenate the output from each digest round with the // password, and use the result as the input to the next digest // operation. - byte[] toBeHashed = null; + byte[] toBeHashed; result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN + DESConstants.DES_BLOCK_SIZE]; for (i = 0; i < 2; i++) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index fb3dfa00148e0..d6b7d00d360df 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,8 +131,8 @@ abstract class PBES2Parameters extends AlgorithmParametersSpi { PBES2Parameters(String pbes2AlgorithmName) throws NoSuchAlgorithmException { int and; - String kdfAlgo = null; - String cipherAlgo = null; + String kdfAlgo; + String cipherAlgo; // Extract the KDF and encryption algorithm names this.pbes2AlgorithmName = pbes2AlgorithmName; @@ -210,9 +210,6 @@ protected void engineInit(AlgorithmParameterSpec paramSpec) protected void engineInit(byte[] encoded) throws IOException { - String kdfAlgo = null; - String cipherAlgo = null; - DerValue pBES2_params = new DerValue(encoded); if (pBES2_params.tag != DerValue.tag_Sequence) { throw new IOException("PBE parameter parsing error: " @@ -231,16 +228,15 @@ protected void engineInit(byte[] encoded) kdf = pBES2_params.data.getDerValue(); } - kdfAlgo = parseKDF(kdf); + String kdfAlgo = parseKDF(kdf); if (pBES2_params.tag != DerValue.tag_Sequence) { throw new IOException("PBE parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } - cipherAlgo = parseES(pBES2_params.data.getDerValue()); + String cipherAlgo = parseES(pBES2_params.data.getDerValue()); - this.pbes2AlgorithmName = new StringBuilder().append("PBEWith") - .append(kdfAlgo).append("And").append(cipherAlgo).toString(); + this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; } @SuppressWarnings("deprecation") @@ -305,7 +301,7 @@ private String parseKDF(DerValue keyDerivationFunc) throws IOException { @SuppressWarnings("deprecation") private String parseES(DerValue encryptionScheme) throws IOException { - String cipherAlgo = null; + String cipherAlgo; cipherAlgo_OID = encryptionScheme.data.getOID(); if (aes128CBC_OID.equals(cipherAlgo_OID)) { @@ -399,7 +395,7 @@ protected byte[] engineGetEncoded(String encodingMethod) /* * Returns a formatted string describing the parameters. * - * The algorithn name pattern is: "PBEWithAnd" + * The algorithm name pattern is: "PBEWithAnd" * where is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, * HmacSHA512, HmacSHA512/224, or HmacSHA512/256 and is * AES with a keysize suffix. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index a02ce2d15511a..c8b9c392a4b49 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,29 @@ package com.sun.crypto.provider; -import java.io.*; -import java.lang.ref.Reference; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamException; import java.lang.ref.Cleaner; +import java.lang.ref.Reference; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.util.Arrays; -import java.util.Locale; -import java.security.MessageDigest; -import java.security.KeyRep; import java.security.GeneralSecurityException; +import java.security.KeyRep; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Locale; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.PBEKeySpec; -import static java.nio.charset.StandardCharsets.UTF_8; - import jdk.internal.ref.CleanerFactory; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class represents a PBE key derived using PBKDF2 defined * in PKCS#5 v2.0. meaning that diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index 56059a89264a7..146999e35ce7d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ abstract class PBMAC1Core extends HmacCore { } private static PBKDF2Core getKDFImpl(String algo) { - PBKDF2Core kdf = null; + PBKDF2Core kdf; switch(algo) { case "HmacSHA1": kdf = new PBKDF2Core.HmacSHA1(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java b/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java index af072c6f5d708..a8ba711d658c3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PKCS5Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,6 @@ public int unpad(byte[] in, int off, int len) { * @return the length of the padding */ public int padLength(int len) { - int paddingOctet = blockSize - (len % blockSize); - return paddingOctet; + return blockSize - (len % blockSize); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java b/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java index 1752bb8ddddfd..1473cf4aba147 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/Poly1305.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * 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,16 +26,18 @@ package com.sun.crypto.provider; import java.nio.ByteBuffer; -import java.security.Key; import java.security.InvalidKeyException; +import java.security.Key; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import java.util.Objects; -import sun.security.util.math.*; -import sun.security.util.math.intpoly.*; -import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.security.util.math.IntegerFieldModuloP; +import sun.security.util.math.IntegerModuloP; +import sun.security.util.math.MutableIntegerModuloP; +import sun.security.util.math.intpoly.IntegerPolynomial1305; /** * This class represents the Poly1305 function defined in RFC 7539. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java b/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java index aa3100c1b7d10..78f25f33b2df8 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RC2Crypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ void initEffectiveKeyBits(int effectiveKeyBits) { static void checkKey(String algorithm, int keyLength) throws InvalidKeyException { - if (algorithm.equals("RC2") == false) { + if (!algorithm.equals("RC2")) { throw new InvalidKeyException("Key algorithm must be RC2"); } if ((keyLength < 5) || (keyLength > 128)) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index df76f78bfb5e0..b48917e755713 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.security.spec.MGF1ParameterSpec; +import java.util.Objects; import javax.crypto.*; import javax.crypto.spec.PSource; @@ -126,7 +127,7 @@ public RSACipher() { // modes do not make sense for RSA, but allow ECB // see JCE spec protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - if (mode.equalsIgnoreCase("ECB") == false) { + if (!mode.equalsIgnoreCase("ECB")) { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } } @@ -468,7 +469,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - byte[] encoded = null; + byte[] encoded; update(wrappedKey, 0, wrappedKey.length); try { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java b/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java index 057c139b5945c..0d25c0064c4f1 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SslMacCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * 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,11 +26,10 @@ package com.sun.crypto.provider; import java.nio.ByteBuffer; - -import javax.crypto.MacSpi; -import javax.crypto.SecretKey; import java.security.*; import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.MacSpi; +import javax.crypto.SecretKey; import static com.sun.crypto.provider.TlsPrfGenerator.genPad; @@ -109,7 +108,7 @@ void init(Key key, AlgorithmParameterSpec params) * @param input the input byte to be processed. */ void update(byte input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -128,8 +127,8 @@ void update(byte input) { * @param offset the offset in input where the input starts. * @param len the number of bytes to process. */ - void update(byte input[], int offset, int len) { - if (first == true) { + void update(byte[] input, int offset, int len) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -141,7 +140,7 @@ void update(byte input[], int offset, int len) { } void update(ByteBuffer input) { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -158,7 +157,7 @@ void update(ByteBuffer input) { * @return the Mac result. */ byte[] doFinal() { - if (first == true) { + if (first) { // compute digest for 1st pass; start with inner pad md.update(secret); md.update(pad1); @@ -189,7 +188,7 @@ byte[] doFinal() { * Mac was initialized with. */ void reset() { - if (first == false) { + if (!first) { md.reset(); first = true; } @@ -211,7 +210,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) protected void engineUpdate(byte input) { core.update(input); } - protected void engineUpdate(byte input[], int offset, int len) { + protected void engineUpdate(byte[] input, int offset, int len) { core.update(input, offset, len); } protected void engineUpdate(ByteBuffer input) { @@ -244,7 +243,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) protected void engineUpdate(byte input) { core.update(input); } - protected void engineUpdate(byte input[], int offset, int len) { + protected void engineUpdate(byte[] input, int offset, int len) { core.update(input, offset, len); } protected void engineUpdate(ByteBuffer input) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java index 56e4dd976632a..2440b45a2ae60 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,11 +62,11 @@ protected void engineInit(SecureRandom random) { @SuppressWarnings("deprecation") protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsKeyMaterialParameterSpec == false) { + if (!(params instanceof TlsKeyMaterialParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsKeyMaterialParameterSpec)params; - if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) { + if (!"RAW".equals(spec.getMasterSecret().getFormat())) { throw new InvalidAlgorithmParameterException( "Key format must be RAW"); } @@ -105,8 +105,6 @@ private SecretKey engineGenerateKey0(byte[] masterSecret) throws GeneralSecurity SecretKey clientMacKey = null; SecretKey serverMacKey = null; - SecretKey clientCipherKey = null; - SecretKey serverCipherKey = null; IvParameterSpec clientIv = null; IvParameterSpec serverIv = null; @@ -194,8 +192,10 @@ private SecretKey engineGenerateKey0(byte[] masterSecret) throws GeneralSecurity System.arraycopy(keyBlock, ofs, serverKeyBytes, 0, keyLength); ofs += keyLength; + SecretKey clientCipherKey; + SecretKey serverCipherKey; try { - if (isExportable == false) { + if (!isExportable) { // cipher keys clientCipherKey = new SecretKeySpec(clientKeyBytes, alg); serverCipherKey = new SecretKeySpec(serverKeyBytes, alg); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java index 1102f4b94ee1a..f8f733b6d2f74 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,12 +132,12 @@ protected void engineInit(SecureRandom random) { @SuppressWarnings("deprecation") protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsPrfParameterSpec == false) { + if (!(params instanceof TlsPrfParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsPrfParameterSpec)params; SecretKey key = spec.getSecret(); - if ((key != null) && ("RAW".equals(key.getFormat()) == false)) { + if ((key != null) && (!"RAW".equals(key.getFormat()))) { throw new InvalidAlgorithmParameterException( "Key encoding format must be RAW"); } @@ -378,7 +378,7 @@ private static void expand(MessageDigest digest, int hmacSize, * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF * calculations. As of 2010, there is no PKCS11-level support for TLS * 1.2 PRF calculations, and no known OS's have an internal variant - * we could use. Therefore for TLS 1.2, we are updating JSSE to request + * we could use. Therefore, for TLS 1.2, we are updating JSSE to request * a different provider algorithm: "SunTls12Prf". If we reused the * name "SunTlsPrf", the PKCS11 provider would need be updated to * fail correctly when presented with the wrong version number From dcf4e0d51f392afe2711223484e932e3826e8864 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 10 Jul 2024 03:30:19 +0000 Subject: [PATCH 207/288] 8335966: Remove incorrect problem listing of java/lang/instrument/NativeMethodPrefixAgent.java in ProblemList-Virtual.txt Reviewed-by: kevinw, amenkov --- test/jdk/ProblemList-Virtual.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index c45353e65edb7..d7692b578cd04 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -36,8 +36,6 @@ javax/management/remote/mandatory/loading/MissingClassTest.java 8145413 windows- javax/management/remote/mandatory/loading/RMIDownloadTest.java 8308366 windows-x64 -java/lang/instrument/NativeMethodPrefixAgent.java 8307169 generic-all - java/lang/ScopedValue/StressStackOverflow.java#default 8309646 generic-all java/lang/ScopedValue/StressStackOverflow.java#no-TieredCompilation 8309646 generic-all java/lang/ScopedValue/StressStackOverflow.java#TieredStopAtLevel1 8309646 generic-all From b5909cabeef22954f4d9c642b1cbf288b3454562 Mon Sep 17 00:00:00 2001 From: Koichi Sakata Date: Wed, 10 Jul 2024 05:57:11 +0000 Subject: [PATCH 208/288] 8323242: Remove vestigial DONT_USE_REGISTER_DEFINES Reviewed-by: gli, kvn --- src/hotspot/cpu/zero/register_zero.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hotspot/cpu/zero/register_zero.hpp b/src/hotspot/cpu/zero/register_zero.hpp index 1b6f52879ef16..fd30f2067623c 100644 --- a/src/hotspot/cpu/zero/register_zero.hpp +++ b/src/hotspot/cpu/zero/register_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -114,8 +114,6 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { }; CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); -#ifndef DONT_USE_REGISTER_DEFINES #define noreg ((Register)(noreg_RegisterEnumValue)) -#endif #endif // CPU_ZERO_REGISTER_ZERO_HPP From a44b60c8c14ad998e51239f48e64779304aaac50 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 10 Jul 2024 07:53:52 +0000 Subject: [PATCH 209/288] 8335778: runtime/ClassInitErrors/TestStackOverflowDuringInit.java fails on ppc64 platforms after JDK-8334545 Reviewed-by: dholmes, asteiner --- .../runtime/ClassInitErrors/TestStackOverflowDuringInit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java index 3917abe85ad57..180dc539795fa 100644 --- a/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java +++ b/test/hotspot/jtreg/runtime/ClassInitErrors/TestStackOverflowDuringInit.java @@ -31,7 +31,7 @@ * @requires vm.flagless * @comment Run with the smallest stack possible to limit the execution time. * This is the smallest stack that is supported by all platforms. - * @run main/othervm -Xss240K -Xint TestStackOverflowDuringInit + * @run main/othervm -Xss384K -Xint TestStackOverflowDuringInit */ import java.io.ByteArrayOutputStream; From 537d20afbff255489a7b1bdb0410b9d1aba715b7 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 10 Jul 2024 09:55:56 +0000 Subject: [PATCH 210/288] 8335766: Switch case with pattern matching and guard clause compiles inconsistently Reviewed-by: abimpoudis --- .../com/sun/tools/javac/parser/JavacParser.java | 10 +++++++++- .../tools/javac/patterns/DisambiguatePatterns.java | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index ef2d71831dc59..f570ad54c58e8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -3436,7 +3436,15 @@ PatternResult analyzePattern(int lookahead) { : PatternResult.PATTERN; } parenDepth++; break; - case RPAREN: parenDepth--; break; + case RPAREN: + parenDepth--; + if (parenDepth == 0 && + typeDepth == 0 && + peekToken(lookahead, TokenKind.IDENTIFIER) && + S.token(lookahead + 1).name() == names.when) { + return PatternResult.PATTERN; + } + break; case ARROW: return parenDepth > 0 ? PatternResult.EXPRESSION : pendingResult; case FINAL: diff --git a/test/langtools/tools/javac/patterns/DisambiguatePatterns.java b/test/langtools/tools/javac/patterns/DisambiguatePatterns.java index ef4d065f91295..d6180c1810f90 100644 --- a/test/langtools/tools/javac/patterns/DisambiguatePatterns.java +++ b/test/langtools/tools/javac/patterns/DisambiguatePatterns.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,6 +109,10 @@ public static void main(String... args) throws Throwable { ExpressionType.EXPRESSION); test.disambiguationTest("a & b", ExpressionType.EXPRESSION); + test.disambiguationTest("R r when (x > 0)", + ExpressionType.PATTERN); + test.disambiguationTest("R(int x) when (x > 0)", + ExpressionType.PATTERN); } private final ParserFactory factory; From e0fb949460d0c7e2ab1697a6466e7d4831a20a33 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 10 Jul 2024 14:28:20 +0000 Subject: [PATCH 211/288] 8335779: JFR: Hide sleep events Reviewed-by: mgronlun --- .../share/jfr/support/jfrIntrinsics.hpp | 2 +- src/hotspot/share/runtime/objectMonitor.cpp | 2 +- .../share/classes/jdk/jfr/internal/JVM.java | 1 + .../classes/jdk/jfr/internal/JVMSupport.java | 4 +- .../jdk/jfr/internal/MetadataRepository.java | 4 +- .../jfr/internal/consumer/OngoingStream.java | 16 ++-- .../jfr/internal/consumer/RecordingInput.java | 7 +- .../internal/consumer/RepositoryFiles.java | 19 ++-- .../internal/{ => management}/HiddenWait.java | 12 ++- .../internal/management/StreamBarrier.java | 48 ++++++---- .../classes/jdk/jfr/internal/util/Utils.java | 23 +---- .../jdk/management/jfr/DownLoadThread.java | 14 +-- .../classes/jdk/management/jfr/FileDump.java | 52 ++++++----- test/jdk/jdk/jfr/jvm/TestHiddenWait.java | 88 +++++++++++++++++++ 14 files changed, 192 insertions(+), 100 deletions(-) rename src/jdk.jfr/share/classes/jdk/jfr/internal/{ => management}/HiddenWait.java (82%) create mode 100644 test/jdk/jdk/jfr/jvm/TestHiddenWait.java diff --git a/src/hotspot/share/jfr/support/jfrIntrinsics.hpp b/src/hotspot/share/jfr/support/jfrIntrinsics.hpp index 6520f3cb00ca0..77affc69926f0 100644 --- a/src/hotspot/share/jfr/support/jfrIntrinsics.hpp +++ b/src/hotspot/share/jfr/support/jfrIntrinsics.hpp @@ -47,7 +47,7 @@ class JfrIntrinsicSupport : AllStatic { #define JFR_HAVE_INTRINSICS #define JFR_TEMPLATES(template) \ - template(jdk_jfr_internal_HiddenWait, "jdk/jfr/internal/HiddenWait") \ + template(jdk_jfr_internal_management_HiddenWait, "jdk/jfr/internal/management/HiddenWait") \ template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \ template(jdk_jfr_internal_event_EventWriterFactory, "jdk/jfr/internal/event/EventWriterFactory") \ template(jdk_jfr_internal_event_EventConfiguration_signature, "Ljdk/jfr/internal/event/EventConfiguration;") \ diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index ba463231592c5..c509ed691cdb8 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1442,7 +1442,7 @@ bool ObjectMonitor::check_owner(TRAPS) { static inline bool is_excluded(const Klass* monitor_klass) { assert(monitor_klass != nullptr, "invariant"); NOT_JFR_RETURN_(false); - JFR_ONLY(return vmSymbols::jdk_jfr_internal_HiddenWait() == monitor_klass->name();) + JFR_ONLY(return vmSymbols::jdk_jfr_internal_management_HiddenWait() == monitor_klass->name();) } static void post_monitor_wait_event(EventJavaMonitorWait* event, diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index 2e600c8c02974..cc0ee05a948a5 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -31,6 +31,7 @@ import jdk.jfr.Event; import jdk.jfr.internal.event.EventConfiguration; import jdk.jfr.internal.event.EventWriter; +import jdk.jfr.internal.management.HiddenWait; /** * Interface against the JVM. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java index 114052ecea250..7fde28a3d21fc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java @@ -30,6 +30,7 @@ import jdk.jfr.Recording; import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.util.Utils; import jdk.jfr.internal.util.ValueFormatter; @@ -118,7 +119,8 @@ private static void awaitUniqueTimestamp() { lastTimestamp = time; return; } - Utils.takeNap(1); + HiddenWait hiddenWait = new HiddenWait(); + hiddenWait.takeNap(1); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 4a7bc734d7571..49afd0082d8a9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -47,6 +47,7 @@ import jdk.jfr.ValueDescriptor; import jdk.jfr.internal.consumer.RepositoryFiles; import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.Utils; @@ -57,6 +58,7 @@ public final class MetadataRepository { private final Map nativeEventTypes = LinkedHashMap.newHashMap(150); private final Map nativeControls = LinkedHashMap.newHashMap(150); private final SettingsManager settingsManager = new SettingsManager(); + private final HiddenWait threadSleeper = new HiddenWait(); private Constructor cachedEventConfigurationConstructor; private boolean staleMetadata = true; private boolean unregistered; @@ -341,7 +343,7 @@ private void awaitEpochMilliShift() { lastMillis = millis; return; } - Utils.takeNap(1); + threadSleeper.takeNap(1); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java index 1816d00f345a7..e0dd7fa2ad8d5 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.SecuritySupport.SafePath; import jdk.jfr.internal.management.EventByteStream; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.management.ManagementSupport; public final class OngoingStream extends EventByteStream { @@ -44,6 +45,7 @@ public final class OngoingStream extends EventByteStream { private final RepositoryFiles repositoryFiles; private final Recording recording; + private final HiddenWait threadSleeper = new HiddenWait(); private final int blockSize; private final long endTimeNanos; private final byte[] headerBytes = new byte[HEADER_SIZE]; @@ -195,19 +197,13 @@ private byte[] readWithHeader(int size) throws IOException { return bytes; } } - takeNap(); + if (!threadSleeper.takeNap(10)) { + throw new IOException("Read operation interrupted"); + } } return EMPTY_ARRAY; } - private void takeNap() throws IOException { - try { - Thread.sleep(10); - } catch (InterruptedException ie) { - throw new IOException("Read operation interrupted", ie); - } - } - private boolean ensureInput() throws IOException { if (input == null) { if (SecuritySupport.getFileSize(new SafePath(path)) < HEADER_SIZE) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java index 90a03130f4990..69ec73f57fd6f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * 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,6 +31,8 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.file.Path; + +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.util.Utils; public final class RecordingInput implements DataInput, AutoCloseable { @@ -67,6 +69,7 @@ public void reset() { } private final int blockSize; private final FileAccess fileAccess; + private final HiddenWait threadSleeper = new HiddenWait(); private long pollCount = 1000; private RandomAccessFile file; private String filename; @@ -453,6 +456,6 @@ public void pollWait() throws IOException { if (pollCount < 0) { throw new IOException("Recording file is stuck in locked stream state."); } - Utils.takeNap(1); + threadSleeper.takeNap(1); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java index 6ef88ecad3750..3f0611f998173 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java @@ -46,9 +46,10 @@ import jdk.jfr.internal.Logger; import jdk.jfr.internal.Repository; import jdk.jfr.internal.SecuritySupport.SafePath; +import jdk.jfr.internal.management.HiddenWait;; public final class RepositoryFiles { - private static final Object WAIT_OBJECT = new Object(); + private static final HiddenWait WAIT_OBJECT = new HiddenWait(); private static final String DIRECTORY_PATTERN = "DDDD_DD_DD_DD_DD_DD_"; public static void notifyNewFile() { synchronized (WAIT_OBJECT) { @@ -59,7 +60,7 @@ public static void notifyNewFile() { private final FileAccess fileAccess; private final NavigableMap pathSet = new TreeMap<>(); private final Map pathLookup = new HashMap<>(); - private final Object waitObject; + private final HiddenWait waitObject; private boolean allowSubDirectory; private volatile boolean closed; private Path repository; @@ -67,7 +68,7 @@ public static void notifyNewFile() { public RepositoryFiles(FileAccess fileAccess, Path repository, boolean allowSubDirectory) { this.repository = repository; this.fileAccess = fileAccess; - this.waitObject = repository == null ? WAIT_OBJECT : new Object(); + this.waitObject = repository == null ? WAIT_OBJECT : new HiddenWait(); this.allowSubDirectory = allowSubDirectory; } @@ -108,7 +109,7 @@ private boolean updatePaths(boolean wait) { // was accessed. Just ignore, and retry later. } if (wait) { - nap(); + waitObject.takeNap(1000); } else { return pathLookup.size() > beforeSize; } @@ -157,16 +158,6 @@ private Path path(long timestamp, boolean wait) { } } - private void nap() { - try { - synchronized (waitObject) { - waitObject.wait(1000); - } - } catch (InterruptedException e) { - // ignore - } - } - private boolean updatePaths() throws IOException, DirectoryIteratorException { boolean foundNew = false; Path repoPath = repository; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/HiddenWait.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/HiddenWait.java similarity index 82% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/HiddenWait.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/management/HiddenWait.java index 26505990332c9..9070faad5a658 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/HiddenWait.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/HiddenWait.java @@ -22,11 +22,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.jfr.internal; +package jdk.jfr.internal.management; /** * The HiddenWait class is used to exclude jdk.JavaMonitorWait events * from being generated when Object.wait() is called on an object of this type. */ public final class HiddenWait { + + public synchronized boolean takeNap(long timeoutMillis) { + try { + this.wait(timeoutMillis); + return true; + } catch (InterruptedException e) { + // Ok, ignore + return false; + } + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java index 0b3132da2178b..7f1db163b4e3d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/StreamBarrier.java @@ -39,45 +39,57 @@ * processing should not continue. */ public final class StreamBarrier implements Closeable { - + private final HiddenWait lock = new HiddenWait(); private boolean activated = false; private boolean used = false; private long end = Long.MAX_VALUE; // Blocks thread until barrier is deactivated - public synchronized void check() { - while (activated) { - try { - this.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + public void check() { + synchronized (lock) { + while (activated) { + try { + lock.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } } } - public synchronized void setStreamEnd(long timestamp) { - end = timestamp; + public void setStreamEnd(long timestamp) { + synchronized(lock) { + end = timestamp; + } } - public synchronized long getStreamEnd() { - return end; + public long getStreamEnd() { + synchronized(lock) { + return end; + } } - public synchronized void activate() { - activated = true; - used = true; + public void activate() { + synchronized (lock) { + activated = true; + used = true; + } } @Override public synchronized void close() throws IOException { - activated = false; - this.notifyAll(); + synchronized (lock) { + activated = false; + lock.notifyAll(); + } } /** * Returns {@code true) if barrier is, or has been, in active state, {@code false) otherwise. */ - public synchronized boolean used() { - return used; + public boolean used() { + synchronized (lock) { + return used; + } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index 5e04a25fe7ddf..ae83727096a2a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -48,19 +48,19 @@ import jdk.jfr.Event; import jdk.jfr.EventType; import jdk.jfr.RecordingState; -import jdk.jfr.internal.HiddenWait; import jdk.jfr.internal.LogLevel; import jdk.jfr.internal.LogTag; import jdk.jfr.internal.Logger; import jdk.jfr.internal.MirrorEvent; import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.Type; +import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.settings.PeriodSetting; import jdk.jfr.internal.settings.StackTraceSetting; import jdk.jfr.internal.settings.ThresholdSetting; public final class Utils { - private static final Object flushObject = new Object(); + private static final HiddenWait flushObject = new HiddenWait(); private static final String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk."; /** @@ -351,17 +351,6 @@ private static boolean isSupportedType(Class type) { return Type.isValidJavaFieldType(type.getName()); } - public static void takeNap(long millis) { - HiddenWait hiddenWait = new HiddenWait(); - try { - synchronized(hiddenWait) { - hiddenWait.wait(millis); - } - } catch (InterruptedException e) { - // ok - } - } - public static void notifyFlush() { synchronized (flushObject) { flushObject.notifyAll(); @@ -369,13 +358,7 @@ public static void notifyFlush() { } public static void waitFlush(long timeOut) { - synchronized (flushObject) { - try { - flushObject.wait(timeOut); - } catch (InterruptedException e) { - // OK - } - } + flushObject.takeNap(timeOut); } public static Instant epochNanosToInstant(long epochNanos) { diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java index 5ce66692537cb..05895f0f4a99b 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DownLoadThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * 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,12 +30,14 @@ import java.util.Map; import jdk.jfr.internal.management.ManagementSupport; +import jdk.jfr.internal.management.HiddenWait; final class DownLoadThread extends Thread { private final RemoteRecordingStream stream; private final Instant startTime; private final Instant endTime; private final DiskRepository diskRepository; + private final HiddenWait threadSleeper = new HiddenWait(); DownLoadThread(RemoteRecordingStream stream, String name) { super(name); @@ -64,7 +66,7 @@ public void run() { if (bytes.length != 0) { diskRepository.write(bytes); } else { - takeNap(); + threadSleeper.takeNap(1000); } } } catch (IOException ioe) { @@ -73,12 +75,4 @@ public void run() { diskRepository.complete(); } } - - private void takeNap() { - try { - Thread.sleep(1000); - } catch (InterruptedException ie) { - // ignore - } - } } diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java index 7da0fe351c450..37ba296732635 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FileDump.java @@ -32,8 +32,10 @@ import java.util.Deque; import jdk.management.jfr.DiskRepository.DiskChunk; +import jdk.jfr.internal.management.HiddenWait; final class FileDump { + private final HiddenWait lock = new HiddenWait(); private final Deque chunks = new ArrayDeque<>(); private final long stopTimeMillis; private boolean complete; @@ -42,45 +44,53 @@ final class FileDump { this.stopTimeMillis = stopTimeMillis; } - public synchronized void add(DiskChunk dc) { - if (isComplete()) { - return; - } - dc.acquire(); - chunks.addFirst(dc); - long endMillis = dc.endTimeNanos / 1_000_000; - if (endMillis >= stopTimeMillis) { - setComplete(); + public void add(DiskChunk dc) { + synchronized (lock) { + if (isComplete()) { + return; + } + dc.acquire(); + chunks.addFirst(dc); + long endMillis = dc.endTimeNanos / 1_000_000; + if (endMillis >= stopTimeMillis) { + setComplete(); + } } } - public synchronized boolean isComplete() { - return complete; + public boolean isComplete() { + synchronized (lock) { + return complete; + } } - public synchronized void setComplete() { - complete = true; - this.notifyAll(); + public void setComplete() { + synchronized (lock) { + complete = true; + lock.notifyAll(); + } } - public synchronized void close() { - for (DiskChunk dc : chunks) { - dc.release(); + public void close() { + synchronized (lock) { + for (DiskChunk dc : chunks) { + dc.release(); + } + chunks.clear(); + complete = true; } - chunks.clear(); - complete = true; } private DiskChunk oldestChunk() throws InterruptedException { while (true) { - synchronized (this) { + synchronized (lock) { if (!chunks.isEmpty()) { return chunks.pollLast(); } if (complete) { return null; } - this.wait(); + lock.wait(); } } } diff --git a/test/jdk/jdk/jfr/jvm/TestHiddenWait.java b/test/jdk/jdk/jfr/jvm/TestHiddenWait.java new file mode 100644 index 0000000000000..f4b810f192e48 --- /dev/null +++ b/test/jdk/jdk/jfr/jvm/TestHiddenWait.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.jvm; + +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import jdk.jfr.Recording; +import jdk.jfr.Name; +import jdk.jfr.Event; +import jdk.jfr.FlightRecorder; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.Events; + +/** + * @test TestHiddenWait + * @key jfr + * @summary Checks that JFR code don't emit noise in the form of ThreadSleep and JavaMonitorWait events. + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.jvm.TestHiddenWait + */ +public class TestHiddenWait { + static final String PERIODIC_EVENT_NAME = "test.Periodic"; + + @Name(PERIODIC_EVENT_NAME) + public static class PeriodicEvent extends Event { + } + + public static void main(String... args) throws Exception { + FlightRecorder.addPeriodicEvent(PeriodicEvent.class, () -> { + PeriodicEvent event = new PeriodicEvent(); + event.commit(); + }); + try (Recording r = new Recording()) { + AtomicLong counter = new AtomicLong(); + r.enable("jdk.ThreadSleep").withoutThreshold(); + r.enable("jdk.JavaMonitorWait").withoutThreshold(); + r.enable(PERIODIC_EVENT_NAME).withPeriod(Duration.ofMillis(100)); + r.start(); + // Triggers Object.wait() in stream barrier + try (RecordingStream b = new RecordingStream()) { + b.startAsync(); + b.stop(); + } + // Wait for for periodic events + try (RecordingStream s = new RecordingStream()) { + s.onEvent(PERIODIC_EVENT_NAME, e -> { + if (counter.incrementAndGet() >= 2) { + s.close(); + } + }); + s.start(); + } + List events = Events.fromRecording(r); + for (RecordedEvent event : events) { + if (!event.getEventType().getName().equals(PERIODIC_EVENT_NAME)) { + System.out.println(event); + throw new Exception("Didn't expect ThreadSleep or JavaMonitorWait events"); + } + } + } + } +} From e6c5aa7a6cb54c647d261facdcffa6a410849627 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 10 Jul 2024 15:12:49 +0000 Subject: [PATCH 212/288] 8336012: Fix usages of jtreg-reserved properties Reviewed-by: jjg --- test/jdk/java/lang/invoke/PrivateInvokeTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/jdk/java/lang/invoke/PrivateInvokeTest.java b/test/jdk/java/lang/invoke/PrivateInvokeTest.java index 12edf8e326316..8ae78d96713c6 100644 --- a/test/jdk/java/lang/invoke/PrivateInvokeTest.java +++ b/test/jdk/java/lang/invoke/PrivateInvokeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,8 +67,6 @@ public class PrivateInvokeTest { String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbose"); if (vstr == null) vstr = System.getProperty(THIS_CLASS.getName()+".verbose"); - if (vstr == null) - vstr = System.getProperty("test.verbose"); if (vstr != null) verbose = Integer.parseInt(vstr); } private static int referenceKind(Method m) { From fb9a227e02ebf826edb762283e15dd7e402f8433 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 10 Jul 2024 15:34:27 +0000 Subject: [PATCH 213/288] 8313909: [JVMCI] assert(cp->tag_at(index).is_unresolved_klass()) in lookupKlassInPool Reviewed-by: yzheng, never --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index d92d193017362..68168c56b9aac 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -897,7 +897,9 @@ C2V_VMENTRY_NULL(jobject, lookupKlassInPool, (JNIEnv* env, jobject, ARGUMENT_PAI } else if (tag.is_symbol()) { symbol = cp->symbol_at(index); } else { - assert(cp->tag_at(index).is_unresolved_klass(), "wrong tag"); + if (!tag.is_unresolved_klass()) { + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Expected %d at index %d, got %d", JVM_CONSTANT_UnresolvedClassInError, index, tag.value())); + } symbol = cp->klass_name_at(index); } } From fb66716a1bc914db194c5b0b833cc2317704f166 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 10 Jul 2024 16:12:40 +0000 Subject: [PATCH 214/288] 8331725: ubsan: pc may not always be the entry point for a VtableStub Reviewed-by: kvn, mbaesken --- src/hotspot/share/code/vtableStubs.cpp | 24 ++++++++++++++++++++---- src/hotspot/share/code/vtableStubs.hpp | 23 +++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/code/vtableStubs.cpp b/src/hotspot/share/code/vtableStubs.cpp index 5a54426d6a420..a65852e247fae 100644 --- a/src/hotspot/share/code/vtableStubs.cpp +++ b/src/hotspot/share/code/vtableStubs.cpp @@ -255,6 +255,19 @@ inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index){ } +inline uint VtableStubs::unsafe_hash(address entry_point) { + // The entrypoint may or may not be a VtableStub. Generate a hash as if it was. + address vtable_stub_addr = entry_point - VtableStub::entry_offset(); + assert(CodeCache::contains(vtable_stub_addr), "assumed to always be the case"); + address vtable_type_addr = vtable_stub_addr + offset_of(VtableStub, _type); + address vtable_index_addr = vtable_stub_addr + offset_of(VtableStub, _index); + bool is_vtable_stub = *vtable_type_addr == static_cast(VtableStub::Type::vtable_stub); + int vtable_index; + memcpy(&vtable_index, vtable_index_addr, sizeof(vtable_index)); + return hash(is_vtable_stub, vtable_index); +} + + VtableStub* VtableStubs::lookup(bool is_vtable_stub, int vtable_index) { assert_lock_strong(VtableStubs_lock); unsigned hash = VtableStubs::hash(is_vtable_stub, vtable_index); @@ -275,12 +288,15 @@ void VtableStubs::enter(bool is_vtable_stub, int vtable_index, VtableStub* s) { } VtableStub* VtableStubs::entry_point(address pc) { + // The pc may or may not be the entry point for a VtableStub. Use unsafe_hash + // to generate the hash that would have been used if it was. The lookup in the + // _table will only succeed if there is a VtableStub with an entry point at + // the pc. MutexLocker ml(VtableStubs_lock, Mutex::_no_safepoint_check_flag); - VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset()); - uint hash = VtableStubs::hash(stub->is_vtable_stub(), stub->index()); + uint hash = VtableStubs::unsafe_hash(pc); VtableStub* s; - for (s = Atomic::load(&_table[hash]); s != nullptr && s != stub; s = s->next()) {} - return (s == stub) ? s : nullptr; + for (s = Atomic::load(&_table[hash]); s != nullptr && s->entry_point() != pc; s = s->next()) {} + return (s != nullptr && s->entry_point() == pc) ? s : nullptr; } bool VtableStubs::contains(address pc) { diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 426753ef00813..06acd8f25b921 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -28,7 +28,6 @@ #include "asm/macroAssembler.hpp" #include "code/vmreg.hpp" #include "memory/allStatic.hpp" -#include "sanitizers/ub.hpp" #include "utilities/checkedCast.hpp" // A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables @@ -94,6 +93,7 @@ class VtableStubs : AllStatic { static VtableStub* lookup (bool is_vtable_stub, int vtable_index); static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s); static inline uint hash (bool is_vtable_stub, int vtable_index); + static inline uint unsafe_hash (address entry_point); static address find_stub (bool is_vtable_stub, int vtable_index); static void bookkeeping(MacroAssembler* masm, outputStream* out, VtableStub* s, address npe_addr, address ame_addr, bool is_vtable_stub, @@ -119,6 +119,12 @@ class VtableStub { private: friend class VtableStubs; + enum class Type : uint8_t { + itable_stub, + vtable_stub, + }; + + static address _chunk; // For allocation static address _chunk_end; // For allocation static VMReg _receiver_location; // Where to find receiver @@ -127,14 +133,14 @@ class VtableStub { const short _index; // vtable index short _ame_offset; // Where an AbstractMethodError might occur short _npe_offset; // Where a NullPointerException might occur - bool _is_vtable_stub; // True if vtable stub, false, is itable stub + Type _type; // Type, either vtable stub or itable stub /* code follows here */ // The vtableStub code void* operator new(size_t size, int code_size) throw(); VtableStub(bool is_vtable_stub, short index) : _next(nullptr), _index(index), _ame_offset(-1), _npe_offset(-1), - _is_vtable_stub(is_vtable_stub) {} + _type(is_vtable_stub ? Type::vtable_stub : Type::itable_stub) {} VtableStub* next() const { return _next; } int index() const { return _index; } static VMReg receiver_location() { return _receiver_location; } @@ -142,12 +148,12 @@ class VtableStub { public: address code_begin() const { return (address)(this + 1); } - address code_end() const { return code_begin() + VtableStubs::code_size_limit(_is_vtable_stub); } + address code_end() const { return code_begin() + VtableStubs::code_size_limit(is_vtable_stub()); } address entry_point() const { return code_begin(); } static int entry_offset() { return sizeof(class VtableStub); } bool matches(bool is_vtable_stub, int index) const { - return _index == index && _is_vtable_stub == is_vtable_stub; + return _index == index && this->is_vtable_stub() == is_vtable_stub; } bool contains(address pc) const { return code_begin() <= pc && pc < code_end(); } @@ -173,11 +179,8 @@ class VtableStub { public: // Query - bool is_itable_stub() { return !_is_vtable_stub; } - // We reinterpret arbitrary memory as VtableStub. This does not cause failures because the lookup/equality - // check will reject false objects. Disabling UBSan is a temporary workaround until JDK-8331725 is fixed. - ATTRIBUTE_NO_UBSAN - bool is_vtable_stub() { return _is_vtable_stub; } + bool is_itable_stub() const { return _type == Type::itable_stub; } + bool is_vtable_stub() const { return _type == Type::vtable_stub; } bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; } bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; } From 7ab96c74e2c39f430a5c2f65a981da7314a2385b Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Wed, 10 Jul 2024 16:26:16 +0000 Subject: [PATCH 215/288] 8335409: Can't allocate and retain memory from resource area in frame::oops_interpreted_do oop closure after 8329665 Reviewed-by: dholmes, stuefe, coleenp, shade --- src/hotspot/share/interpreter/oopMapCache.cpp | 60 ++++++++----------- src/hotspot/share/interpreter/oopMapCache.hpp | 23 ++++--- src/hotspot/share/runtime/frame.cpp | 1 - 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index a10f8c439eaa4..87b124e9d7968 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -66,9 +66,6 @@ class OopMapCacheEntry: private InterpreterOopMap { public: OopMapCacheEntry() : InterpreterOopMap() { _next = nullptr; -#ifdef ASSERT - _resource_allocate_bit_mask = false; -#endif } }; @@ -177,9 +174,13 @@ class VerifyClosure : public OffsetClosure { InterpreterOopMap::InterpreterOopMap() { initialize(); -#ifdef ASSERT - _resource_allocate_bit_mask = true; -#endif +} + +InterpreterOopMap::~InterpreterOopMap() { + if (has_valid_mask() && mask_size() > small_mask_limit) { + assert(_bit_mask[0] != 0, "should have pointer to C heap"); + FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); + } } bool InterpreterOopMap::is_empty() const { @@ -399,37 +400,24 @@ void OopMapCacheEntry::deallocate(OopMapCacheEntry* const entry) { // Implementation of OopMapCache -void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) { - assert(_resource_allocate_bit_mask, - "Should not resource allocate the _bit_mask"); - assert(from->has_valid_mask(), - "Cannot copy entry with an invalid mask"); +void InterpreterOopMap::copy_from(const OopMapCacheEntry* src) { + // The expectation is that this InterpreterOopMap is recently created + // and empty. It is used to get a copy of a cached entry. + assert(!has_valid_mask(), "InterpreterOopMap object can only be filled once"); + assert(src->has_valid_mask(), "Cannot copy entry with an invalid mask"); - set_method(from->method()); - set_bci(from->bci()); - set_mask_size(from->mask_size()); - set_expression_stack_size(from->expression_stack_size()); - _num_oops = from->num_oops(); + set_method(src->method()); + set_bci(src->bci()); + set_mask_size(src->mask_size()); + set_expression_stack_size(src->expression_stack_size()); + _num_oops = src->num_oops(); // Is the bit mask contained in the entry? - if (from->mask_size() <= small_mask_limit) { - memcpy((void *)_bit_mask, (void *)from->_bit_mask, - mask_word_size() * BytesPerWord); + if (src->mask_size() <= small_mask_limit) { + memcpy(_bit_mask, src->_bit_mask, mask_word_size() * BytesPerWord); } else { - // The expectation is that this InterpreterOopMap is a recently created - // and empty. It is used to get a copy of a cached entry. - // If the bit mask has a value, it should be in the - // resource area. - assert(_bit_mask[0] == 0 || - Thread::current()->resource_area()->contains((void*)_bit_mask[0]), - "The bit mask should have been allocated from a resource area"); - // Allocate the bit_mask from a Resource area for performance. Allocating - // from the C heap as is done for OopMapCache has a significant - // performance impact. - _bit_mask[0] = (uintptr_t) NEW_RESOURCE_ARRAY(uintptr_t, mask_word_size()); - assert(_bit_mask[0] != 0, "bit mask was not allocated"); - memcpy((void*) _bit_mask[0], (void*) from->_bit_mask[0], - mask_word_size() * BytesPerWord); + _bit_mask[0] = (uintptr_t) NEW_C_HEAP_ARRAY(uintptr_t, mask_word_size(), mtClass); + memcpy((void*) _bit_mask[0], (void*) src->_bit_mask[0], mask_word_size() * BytesPerWord); } } @@ -512,7 +500,7 @@ void OopMapCache::lookup(const methodHandle& method, for (int i = 0; i < probe_depth; i++) { OopMapCacheEntry *entry = entry_at(probe + i); if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { - entry_for->resource_copy(entry); + entry_for->copy_from(entry); assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); log_debug(interpreter, oopmap)("- found at hash %d", probe + i); return; @@ -526,7 +514,7 @@ void OopMapCache::lookup(const methodHandle& method, OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass); tmp->initialize(); tmp->fill(method, bci); - entry_for->resource_copy(tmp); + entry_for->copy_from(tmp); if (method->should_not_be_cached()) { // It is either not safe or not a good idea to cache this Method* @@ -627,7 +615,7 @@ void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, Inter tmp->initialize(); tmp->fill(method, bci); if (tmp->has_valid_mask()) { - entry->resource_copy(tmp); + entry->copy_from(tmp); } OopMapCacheEntry::deallocate(tmp); } diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 7037b2c7d1fcf..062b4178ce06e 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -36,13 +36,14 @@ // OopMapCache's are allocated lazily per InstanceKlass. // The oopMap (InterpreterOopMap) is stored as a bit mask. If the -// bit_mask can fit into two words it is stored in +// bit_mask can fit into four words it is stored in // the _bit_mask array, otherwise it is allocated on the heap. // For OopMapCacheEntry the bit_mask is allocated in the C heap // because these entries persist between garbage collections. -// For InterpreterOopMap the bit_mask is allocated in -// a resource area for better performance. InterpreterOopMap -// should only be created and deleted during same garbage collection. +// For InterpreterOopMap the bit_mask is allocated in the C heap +// to avoid issues with allocations from the resource area that have +// to live accross the oop closure. InterpreterOopMap should only be +// created and deleted during the same garbage collection. // // If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used // per entry instead of one. In all cases, @@ -88,9 +89,6 @@ class InterpreterOopMap: ResourceObj { unsigned short _bci; // the bci for which the mask is valid protected: -#ifdef ASSERT - bool _resource_allocate_bit_mask; -#endif int _num_oops; intptr_t _bit_mask[N]; // the bit mask if // mask_size <= small_mask_limit, @@ -128,12 +126,13 @@ class InterpreterOopMap: ResourceObj { public: InterpreterOopMap(); + ~InterpreterOopMap(); - // Copy the OopMapCacheEntry in parameter "from" into this - // InterpreterOopMap. If the _bit_mask[0] in "from" points to - // allocated space (i.e., the bit mask was to large to hold - // in-line), allocate the space from a Resource area. - void resource_copy(OopMapCacheEntry* from); + // Copy the OopMapCacheEntry in parameter "src" into this + // InterpreterOopMap. If the _bit_mask[0] in "src" points to + // allocated space (i.e., the bit mask was too large to hold + // in-line), allocate the space from the C heap. + void copy_from(const OopMapCacheEntry* src); void iterate_oop(OffsetClosure* oop_closure) const; void print() const; diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 8f5d2ad4acbf1..1aed46d58804f 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -947,7 +947,6 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f); // process locals & expression stack - ResourceMark rm(thread); InterpreterOopMap mask; if (query_oop_map_cache) { m->mask_for(m, bci, &mask); From 66db71563c3ebd715a1192a9b399b618d7bdb8d0 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 10 Jul 2024 16:36:39 +0000 Subject: [PATCH 216/288] 8335637: Add explicit non-null return value expectations to Object.toString() Reviewed-by: jpai, alanb, smarks, prappo --- src/java.base/share/classes/java/lang/Object.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/java.base/share/classes/java/lang/Object.java b/src/java.base/share/classes/java/lang/Object.java index b8bfdc3e3f9bf..d9813df57a4f0 100644 --- a/src/java.base/share/classes/java/lang/Object.java +++ b/src/java.base/share/classes/java/lang/Object.java @@ -237,6 +237,10 @@ public boolean equals(Object obj) { /** * {@return a string representation of the object} + * + * Satisfying this method's contract implies a non-{@code null} + * result must be returned. + * * @apiNote * In general, the * {@code toString} method returns a string that From 242f1133f8e1b373de3714cefc7f6701c39707fe Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 10 Jul 2024 19:42:23 +0000 Subject: [PATCH 217/288] 8334481: [JVMCI] add LINK_TO_NATIVE to MethodHandleAccessProvider.IntrinsicMethod Reviewed-by: dnsimon --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + .../jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java | 2 ++ .../share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 + .../classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java | 4 +++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 8f83d483bcf4b..f55c7bf91a9b6 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -778,6 +778,7 @@ declare_constant(vmIntrinsics::_linkToStatic) \ declare_constant(vmIntrinsics::_linkToSpecial) \ declare_constant(vmIntrinsics::_linkToInterface) \ + declare_constant(vmIntrinsics::_linkToNative) \ \ declare_constant(vmSymbols::FIRST_SID) \ declare_constant(vmSymbols::SID_LIMIT) \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java index 7e47196a42b89..3d3d140b1ca79 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java @@ -146,6 +146,8 @@ public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) { return IntrinsicMethod.LINK_TO_STATIC; } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) { return IntrinsicMethod.LINK_TO_VIRTUAL; + } else if (intrinsicId == config.vmIntrinsicLinkToNative) { + return IntrinsicMethod.LINK_TO_NATIVE; } return null; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index c49f24efed51e..57f9473c90209 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -342,6 +342,7 @@ final int baseVtableLength() { final int vmIntrinsicLinkToStatic = getConstant("vmIntrinsics::_linkToStatic", Integer.class); final int vmIntrinsicLinkToSpecial = getConstant("vmIntrinsics::_linkToSpecial", Integer.class); final int vmIntrinsicLinkToInterface = getConstant("vmIntrinsics::_linkToInterface", Integer.class); + final int vmIntrinsicLinkToNative = getConstant("vmIntrinsics::_linkToNative", Integer.class); final int codeInstallResultOk = getConstant("JVMCI::ok", Integer.class); final int codeInstallResultDependenciesFailed = getConstant("JVMCI::dependencies_failed", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java index f053905b160c9..eb8b9721d49ce 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java @@ -45,7 +45,9 @@ enum IntrinsicMethod { /** The method {@code MethodHandle.linkToVirtual}. */ LINK_TO_VIRTUAL, /** The method {@code MethodHandle.linkToInterface}. */ - LINK_TO_INTERFACE + LINK_TO_INTERFACE, + /** The method {@code MethodHandle.linkToNative}. */ + LINK_TO_NATIVE } /** From cad68e06ecad1e19091d1af9c0f9b8145d6842fb Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 10 Jul 2024 21:06:39 +0000 Subject: [PATCH 218/288] 8335935: Chained builders not sending transformed models to next transforms Reviewed-by: asotona --- .../java/lang/classfile/CodeBuilder.java | 4 +- .../classfile/impl/BlockCodeBuilderImpl.java | 16 +- .../classfile/impl/BufferedCodeBuilder.java | 4 +- .../classfile/impl/ChainedClassBuilder.java | 16 +- .../classfile/impl/ChainedMethodBuilder.java | 10 +- .../classfile/impl/DirectCodeBuilder.java | 4 +- .../internal/classfile/impl/LabelContext.java | 4 +- .../classfile/impl/TerminalCodeBuilder.java | 8 +- .../impl/TransformingCodeBuilder.java | 91 ---------- test/jdk/jdk/classfile/TransformTests.java | 163 ++++++++++++++++++ 10 files changed, 196 insertions(+), 124 deletions(-) delete mode 100644 src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index cffa560bef305..a166637509174 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -86,7 +86,7 @@ import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.BytecodeHelpers.handleDescToHandleInfo; -import jdk.internal.classfile.impl.TransformingCodeBuilder; + import jdk.internal.javac.PreviewFeature; /** @@ -192,7 +192,7 @@ public sealed interface CodeBuilder default CodeBuilder transforming(CodeTransform transform, Consumer handler) { var resolved = transform.resolve(this); resolved.startHandler().run(); - handler.accept(new TransformingCodeBuilder(this, resolved.consumer())); + handler.accept(new ChainedCodeBuilder(this, resolved.consumer())); resolved.endHandler().run(); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java index ffe1a2bd6160f..66e974b4a51b6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,13 +51,13 @@ public BlockCodeBuilderImpl(CodeBuilder parent, Label breakLabel) { public void start() { topLocal = topLocal(parent); - terminalMaxLocals = topLocal(terminal); - terminal.with((LabelTarget) startLabel); + terminalMaxLocals = terminal.curTopLocal(); + parent.with((LabelTarget) startLabel); } public void end() { - terminal.with((LabelTarget) endLabel); - if (terminalMaxLocals != topLocal(terminal)) { + parent.with((LabelTarget) endLabel); + if (terminalMaxLocals != terminal.curTopLocal()) { throw new IllegalStateException("Interference in local variable slot management"); } } @@ -73,10 +73,8 @@ public boolean isEmpty() { private int topLocal(CodeBuilder parent) { return switch (parent) { case BlockCodeBuilderImpl b -> b.topLocal; - case ChainedCodeBuilder b -> topLocal(b.terminal); - case DirectCodeBuilder b -> b.curTopLocal(); - case BufferedCodeBuilder b -> b.curTopLocal(); - case TransformingCodeBuilder b -> topLocal(b.delegate); + case ChainedCodeBuilder b -> b.terminal.curTopLocal(); + case TerminalCodeBuilder b -> b.curTopLocal(); }; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index 60e73cdd987c0..8603c77ab8b2a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ import java.util.function.Consumer; public final class BufferedCodeBuilder - implements TerminalCodeBuilder, LabelContext { + implements TerminalCodeBuilder { private final SplitConstantPool constantPool; private final ClassFileImpl context; private final List elements = new ArrayList<>(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index cc19bf9d31c8d..b33d192f9b355 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,13 +33,11 @@ public final class ChainedClassBuilder implements ClassBuilder, Consumer { - private final ClassBuilder downstream; private final DirectClassBuilder terminal; private final Consumer consumer; public ChainedClassBuilder(ClassBuilder downstream, Consumer consumer) { - this.downstream = downstream; this.consumer = consumer; this.terminal = switch (downstream) { case ChainedClassBuilder cb -> cb.terminal; @@ -60,10 +58,11 @@ public Optional original() { @Override public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { - return downstream.with(new BufferedFieldBuilder(terminal.constantPool, terminal.context, + consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context, name, descriptor, null) .run(handler) .toModel()); + return this; } @Override @@ -72,16 +71,18 @@ public ClassBuilder transformField(FieldModel field, FieldTransform transform) { field.fieldName(), field.fieldType(), field); builder.transform(field, transform); - return downstream.with(builder.toModel()); + consumer.accept(builder.toModel()); + return this; } @Override public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, Consumer handler) { - return downstream.with(new BufferedMethodBuilder(terminal.constantPool, terminal.context, + consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context, name, descriptor, null) .run(handler) .toModel()); + return this; } @Override @@ -89,7 +90,8 @@ public ClassBuilder transformMethod(MethodModel method, MethodTransform transfor BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, method.methodName(), method.methodType(), method); builder.transform(method, transform); - return downstream.with(builder.toModel()); + consumer.accept(builder.toModel()); + return this; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java index 38850aec10978..866dda2c5bc53 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,13 +36,11 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; public final class ChainedMethodBuilder implements MethodBuilder { - final MethodBuilder downstream; final TerminalMethodBuilder terminal; final Consumer consumer; public ChainedMethodBuilder(MethodBuilder downstream, Consumer consumer) { - this.downstream = downstream; this.consumer = consumer; this.terminal = switch (downstream) { case ChainedMethodBuilder cb -> cb.terminal; @@ -58,16 +56,18 @@ public MethodBuilder with(MethodElement element) { @Override public MethodBuilder withCode(Consumer handler) { - return downstream.with(terminal.bufferedCodeBuilder(null) + consumer.accept(terminal.bufferedCodeBuilder(null) .run(handler) .toModel()); + return this; } @Override public MethodBuilder transformCode(CodeModel code, CodeTransform transform) { BufferedCodeBuilder builder = terminal.bufferedCodeBuilder(code); builder.transform(code, transform); - return downstream.with(builder.toModel()); + consumer.accept(builder.toModel()); + return this; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index b961a12031f59..0b6549a82da9e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ public final class DirectCodeBuilder extends AbstractDirectBuilder - implements TerminalCodeBuilder, LabelContext { + implements TerminalCodeBuilder { private final List characterRanges = new ArrayList<>(); final List handlers = new ArrayList<>(); private final List localVariables = new ArrayList<>(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java index e17adcbcf121f..749abbed23b6d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 +27,7 @@ import java.lang.classfile.Label; public sealed interface LabelContext - permits BufferedCodeBuilder, CodeImpl, DirectCodeBuilder { + permits TerminalCodeBuilder, CodeImpl { Label newLabel(); Label getLabel(int bci); void setLabelTarget(Label label, int bci); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java index e13b09b0a4d0d..6e3ca516bf480 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ import java.lang.classfile.CodeBuilder; -public sealed interface TerminalCodeBuilder extends CodeBuilder - permits DirectCodeBuilder, BufferedCodeBuilder, TransformingCodeBuilder { - +public sealed interface TerminalCodeBuilder extends CodeBuilder, LabelContext + permits DirectCodeBuilder, BufferedCodeBuilder { + int curTopLocal(); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java deleted file mode 100644 index 4ffc75d3edc82..0000000000000 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformingCodeBuilder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. - * 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.internal.classfile.impl; - -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeModel; -import java.util.Optional; -import java.util.function.Consumer; -import java.lang.classfile.CodeElement; -import java.lang.classfile.Label; -import java.lang.classfile.TypeKind; -import java.lang.classfile.constantpool.ConstantPoolBuilder; - -public final class TransformingCodeBuilder implements TerminalCodeBuilder { - - final CodeBuilder delegate; - final Consumer consumer; - - public TransformingCodeBuilder(CodeBuilder delegate, Consumer consumer) { - this.delegate = delegate; - this.consumer = consumer; - } - - @Override - public CodeBuilder with(CodeElement e) { - consumer.accept(e); - return this; - } - - @Override - public Optional original() { - return delegate.original(); - } - - @Override - public Label newLabel() { - return delegate.newLabel(); - } - - @Override - public Label startLabel() { - return delegate.startLabel(); - } - - @Override - public Label endLabel() { - return delegate.endLabel(); - } - - @Override - public int receiverSlot() { - return delegate.receiverSlot(); - } - - @Override - public int parameterSlot(int paramNo) { - return delegate.parameterSlot(paramNo); - } - - @Override - public int allocateLocal(TypeKind typeKind) { - return delegate.allocateLocal(typeKind); - } - - @Override - public ConstantPoolBuilder constantPool() { - return delegate.constantPool(); - } -} diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java index 1df7b73bda56a..0cc1dafdf3274 100644 --- a/test/jdk/jdk/classfile/TransformTests.java +++ b/test/jdk/jdk/classfile/TransformTests.java @@ -23,9 +23,22 @@ /* * @test + * @bug 8336010 * @summary Testing ClassFile transformations. * @run junit TransformTests */ +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.FieldTransform; +import java.lang.classfile.Label; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.instruction.BranchInstruction; +import java.lang.classfile.instruction.LabelTarget; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; @@ -39,8 +52,13 @@ import java.lang.classfile.CodeTransform; import java.lang.classfile.MethodModel; import java.lang.classfile.instruction.ConstantInstruction; +import java.util.HashSet; +import java.util.Set; + import org.junit.jupiter.api.Test; +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; import static org.junit.jupiter.api.Assertions.*; /** @@ -126,6 +144,151 @@ void testSeqN() throws Exception { assertEquals(invoke(cc.transformClass(cm, transformCode(foo2foo.andThen(foo2bar).andThen(bar2baz)))), "baz"); } + /** + * Test to ensure class elements, such as field and + * methods defined with transform/with, are visible + * to next transforms. + */ + @Test + void testClassChaining() throws Exception { + var bytes = Files.readAllBytes(testClassPath); + var cf = ClassFile.of(); + var cm = cf.parse(bytes); + var otherCm = cf.parse(cf.build(ClassDesc.of("Temp"), clb -> clb + .withMethodBody("baz", MTD_void, ACC_STATIC, CodeBuilder::return_) + .withField("baz", CD_long, ACC_STATIC))); + + var methodBaz = otherCm.methods().getFirst(); + var fieldBaz = otherCm.fields().getFirst(); + + ClassTransform transform1 = ClassTransform.endHandler(cb -> { + ClassBuilder ret; + ret = cb.withMethodBody("bar", MTD_void, ACC_STATIC, CodeBuilder::return_); + assertSame(cb, ret); + ret = cb.transformMethod(methodBaz, MethodTransform.ACCEPT_ALL); + assertSame(cb, ret); + ret = cb.withField("bar", CD_int, ACC_STATIC); + assertSame(cb, ret); + ret = cb.transformField(fieldBaz, FieldTransform.ACCEPT_ALL); + assertSame(cb, ret); + }); + + Set methodNames = new HashSet<>(); + Set fieldNames = new HashSet<>(); + ClassTransform transform2 = (cb, ce) -> { + if (ce instanceof MethodModel mm) { + methodNames.add(mm.methodName().stringValue()); + } + if (ce instanceof FieldModel fm) { + fieldNames.add(fm.fieldName().stringValue()); + } + cb.with(ce); + }; + + cf.transformClass(cm, transform1.andThen(transform2)); + + assertEquals(Set.of(INIT_NAME, "foo", "bar", "baz"), methodNames); + assertEquals(Set.of("bar", "baz"), fieldNames); + } + + /** + * Test to ensure method elements, such as generated + * or transformed code, are visible to transforms. + */ + @Test + void testMethodChaining() throws Exception { + var mtd = MethodTypeDesc.of(CD_String); + + var cf = ClassFile.of(); + + // withCode + var cm = cf.parse(cf.build(ClassDesc.of("Temp"), clb -> clb + .withMethod("baz", mtd, ACC_STATIC | ACC_NATIVE, _ -> {}))); + + MethodTransform transform1 = MethodTransform.endHandler(mb -> { + var ret = mb.withCode(cob -> cob.loadConstant("foo").areturn()); + assertSame(mb, ret); + }); + + boolean[] sawWithCode = { false }; + MethodTransform transform2 = (mb, me) -> { + if (me instanceof CodeModel) { + sawWithCode[0] = true; + } + mb.with(me); + }; + + cf.transformClass(cm, ClassTransform.transformingMethods(transform1.andThen(transform2))); + + assertTrue(sawWithCode[0], "Code attribute generated not visible"); + + // transformCode + var outerCm = cf.parse(testClassPath); + var foo = outerCm.methods().stream() + .filter(m -> m.flags().has(AccessFlag.STATIC)) + .findFirst().orElseThrow(); + + MethodTransform transform3 = MethodTransform.endHandler(mb -> { + var ret = mb.transformCode(foo.code().orElseThrow(), CodeTransform.ACCEPT_ALL); + assertSame(mb, ret); + }); + + boolean[] sawTransformCode = { false }; + MethodTransform transform4 = (mb, me) -> { + if (me instanceof CodeModel) { + sawTransformCode[0] = true; + } + mb.with(me); + }; + + cf.transformClass(cm, ClassTransform.transformingMethods(transform3.andThen(transform4))); + + assertTrue(sawTransformCode[0], "Code attribute transformed not visible"); + } + + /** + * Test to ensure code elements, such as code block + * begin and end labels, are visible to transforms. + */ + @Test + void testCodeChaining() throws Exception { + var bytes = Files.readAllBytes(testClassPath); + var cf = ClassFile.of(); + var cm = cf.parse(bytes); + + CodeTransform transform1 = new CodeTransform() { + @Override + public void atStart(CodeBuilder builder) { + builder.block(bcb -> { + bcb.loadConstant(9876L); + bcb.goto_(bcb.endLabel()); + }); + } + + @Override + public void accept(CodeBuilder builder, CodeElement element) { + builder.with(element); + } + }; + Set

    "x&#178;=5"
    * - * + * *
    "x²=5"
    * - * + * *
    "x&#178;=5"
    * * * - * Built-in - * character entity - * + * Built-in character entity + * *
    "y&lt;6"
    * - * + * *
    "y<6"
    * - * + * *
    "y&lt;6"
    * * * - * Literal newline between - * - *
    - * "x=5&#10;y=6"
    + * Literal newline between + * + *
    "x=5&#10;y=6"
    * - * + * *
    "x=5 y=6"
    * - * + * *
    "x=5&#10;y=6"
    * * * - * Normalized newline between - * + * Normalized newline between + * *
    "x=5
      * y=6"
    * - * + * *
    "x=5 y=6"
    * - * + * *
    "x=5 y=6"
    * * * - * Entity e with literal newline - * + * Entity e with literal newline + * *
      * <!ENTITY e '...&#10;...'> [...]> "x=5&e;y=6"
    * - * Dependent on Implementation and Load Options - * Dependent on Implementation and Load/Save Options + * Dependent on Implementation and Load Options + * Dependent on Implementation and Load/Save Options * * * From 5100303c6c5e4224d2c41f90719139bb5f4e236e Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 11 Jul 2024 18:40:40 +0000 Subject: [PATCH 232/288] 8335668: NumberFormat integer only parsing should throw exception for edge case Reviewed-by: naoto --- .../classes/java/text/DecimalFormat.java | 14 +++++--- .../Format/NumberFormat/LenientParseTest.java | 30 ++++++++++++++-- .../Format/NumberFormat/StrictParseTest.java | 34 ++++++++++++++++--- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 1f249888a28f5..04acca1ceb51d 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -2379,8 +2379,8 @@ private final boolean subparse(String text, ParsePosition parsePosition, NumericPosition pos = subparseNumber(text, position, digits, true, isExponent, status); position = pos.fullPos; - // First character after the prefix was un-parseable, should - // fail regardless if lenient or strict. + // First character after the prefix was un-parseable or parsing integer + // only with no integer portion. Should fail regardless if lenient or strict. if (position == -1) { parsePosition.index = oldStart; parsePosition.errorIndex = oldStart; @@ -2421,8 +2421,8 @@ private final boolean subparse(String text, ParsePosition parsePosition, } // When parsing integer only, index should be int pos - // If intPos is 0, the entire value was integer - if (isParseIntegerOnly() && pos.intPos > 0) { + // If intPos is -1, the entire value was integer and index should be full pos + if (isParseIntegerOnly() && pos.intPos != -1) { parsePosition.index = pos.intPos; } else { // increment the index by the suffix @@ -2474,7 +2474,7 @@ NumericPosition subparseNumber(String text, int position, boolean isExponent, boolean[] status) { // process digits or Inf, find decimal position status[STATUS_INFINITE] = false; - int intIndex = 0; + int intIndex = -1; if (!isExponent && text.regionMatches(position, symbols.getInfinity(), 0, symbols.getInfinity().length())) { position += symbols.getInfinity().length(); @@ -2570,6 +2570,10 @@ NumericPosition subparseNumber(String text, int position, // Cancel out backup setting (see grouping handler below) backup = -1; } else if (!isExponent && ch == decimal) { + if (isParseIntegerOnly() && startPos == position) { + // Parsing int only with no integer portion, fail + return new NumericPosition(-1, intIndex); + } // Check grouping size on decimal separator if (parseStrict && isGroupingViolation(position, prevSeparatorIndex)) { return new NumericPosition( diff --git a/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java b/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java index 41f8961ff32e2..c85fe0f6cbb59 100644 --- a/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java +++ b/test/jdk/java/text/Format/NumberFormat/LenientParseTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8327640 8331485 8333456 + * @bug 8327640 8331485 8333456 8335668 * @summary Test suite for NumberFormat parsing when lenient. * @run junit/othervm -Duser.language=en -Duser.country=US LenientParseTest * @run junit/othervm -Duser.language=ja -Duser.country=JP LenientParseTest @@ -128,6 +128,28 @@ public void numFmtStrictIntegerOnlyUsed(String toParse, int expectedValue, int e dFmt.setParseIntegerOnly(false); } + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test + public void integerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getIntegerInstance(); + failParse(fmt, localizeText("."), 0); + failParse(fmt, localizeText(".0"), 0); + failParse(fmt, localizeText(".55"), 0); + } + + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test // Non-localized, run once + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void compactIntegerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + fmt.setParseIntegerOnly(true); + failParse(fmt, ".K", 0); + failParse(fmt, ".0K", 0); + failParse(fmt, ".55K", 0); + } + @Test // Non-localized, only run once @EnabledIfSystemProperty(named = "user.language", matches = "en") public void badExponentParseNumberFormatTest() { @@ -313,7 +335,11 @@ private static Stream validFullParseStrings() { Arguments.of("10000", 10000d), Arguments.of("100,000", 100000d), Arguments.of("1,000,000", 1000000d), - Arguments.of("10,000,000", 10000000d)) + Arguments.of("10,000,000", 10000000d), + // Smaller value cases (w/ decimal) + Arguments.of(".1", .1d), + Arguments.of("1.1", 1.1d), + Arguments.of("11.1", 11.1d)) .map(args -> Arguments.of( localizeText(String.valueOf(args.get()[0])), args.get()[1])); } diff --git a/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java b/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java index 333bc1b050637..3e90ccb39ceaf 100644 --- a/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java +++ b/test/jdk/java/text/Format/NumberFormat/StrictParseTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8327640 8331485 8333755 + * @bug 8327640 8331485 8333755 8335668 * @summary Test suite for NumberFormat parsing with strict leniency * @run junit/othervm -Duser.language=en -Duser.country=US StrictParseTest * @run junit/othervm -Duser.language=ja -Duser.country=JP StrictParseTest @@ -203,6 +203,28 @@ public void numFmtStrictIntegerOnlyUsedTest(String toParse, Number expVal) { } } + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test + public void integerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getIntegerInstance(); + failParse(fmt, localizeText("."), 0); + failParse(fmt, localizeText(".0"), 0); + failParse(fmt, localizeText(".55"), 0); + } + + // 8335668: Parsing with integer only against String with no integer portion + // should fail, not return 0. Expected error index should be 0 + @Test // Non-localized, run once + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void compactIntegerParseOnlyFractionOnlyTest() { + var fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + fmt.setParseIntegerOnly(true); + failParse(fmt, ".K", 0); + failParse(fmt, ".0K", 0); + failParse(fmt, ".55K", 0); + } + // 8333755: Parsing behavior should follow normal strict behavior // when it comes to failures. @ParameterizedTest @@ -426,8 +448,8 @@ private static Stream badParseStrings() { Arguments.of("1,234a", 5), Arguments.of("1,.a", 2), Arguments.of("1.a", 2), - Arguments.of(".22a", 3), - Arguments.of(".1a1", 2), + Arguments.of("1.22a", 4), + Arguments.of("1.1a1", 3), Arguments.of("1,234,a", 5), // Double decimal Arguments.of("1,234..5", 5)) @@ -453,7 +475,11 @@ private static Stream validParseStrings() { Arguments.of("10000", 10000d), Arguments.of("100,000", 100000d), Arguments.of("1,000,000", 1000000d), - Arguments.of("10,000,000", 10000000d)) + Arguments.of("10,000,000", 10000000d), + // Smaller value cases (w/ decimal) + Arguments.of(".1", .1d), + Arguments.of("1.1", 1.1d), + Arguments.of("11.1", 11.1d)) .map(args -> Arguments.of( localizeText(String.valueOf(args.get()[0])), args.get()[1])); } From 9eb611e7f07ebb6eb0cbcca32d644abf8352c991 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 11 Jul 2024 19:53:52 +0000 Subject: [PATCH 233/288] 8334055: Unhelpful 'required: reference' diagnostics after JDK-8043226 Reviewed-by: vromero --- .../classes/com/sun/tools/javac/comp/Attr.java | 9 +-------- .../failures/CantAnnotateMissingSymbol.java | 16 ++++++++++++++++ .../failures/CantAnnotateMissingSymbol.out | 2 ++ .../failures/CantAnnotatePackages.java | 2 +- .../failures/CantAnnotatePackages.out | 6 +++--- .../failures/CantAnnotateScoping.java | 2 +- .../failures/CantAnnotateScoping.out | 9 ++++----- 7 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index f58319496e968..9b79846ba40df 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5241,14 +5241,7 @@ public void visitModifiers(JCModifiers tree) { public void visitAnnotatedType(JCAnnotatedType tree) { attribAnnotationTypes(tree.annotations, env); - Type underlyingType = - attribTree(tree.underlyingType, env, new ResultInfo(KindSelector.TYP_PCK, Type.noType)); - if (underlyingType.hasTag(PACKAGE)) { - // Type annotations are not admissible on packages, but we handle packages here to - // report better diagnostics later in validateAnnotatedType. - result = tree.type = underlyingType; - return; - } + Type underlyingType = attribType(tree.underlyingType, env); Type annotatedType = underlyingType.preannotatedType(); if (!env.info.isNewClass) diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java new file mode 100644 index 0000000000000..469cffa37a61f --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.java @@ -0,0 +1,16 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8026564 8043226 + * @summary 8334055 + * @compile/fail/ref=CantAnnotateMissingSymbol.out -XDrawDiagnostics CantAnnotateMissingSymbol.java + */ + +import java.lang.annotation.*; +import java.util.List; + +class CantAnnotateMissingSymbol { + List<@TA NoSuch> x; +} + +@Target(ElementType.TYPE_USE) +@interface TA { } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out new file mode 100644 index 0000000000000..b875cd2be7b80 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateMissingSymbol.out @@ -0,0 +1,2 @@ +CantAnnotateMissingSymbol.java:12:14: compiler.err.cant.resolve.location: kindname.class, NoSuch, , , (compiler.misc.location: kindname.class, CantAnnotateMissingSymbol, null) +1 error diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java index d7587dfcf5fc2..d35351b6f4084 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8026564 8043226 + * @bug 8026564 8043226 8334055 * @summary The parts of a fully-qualified type can't be annotated. * @author Werner Dietl * @compile/fail/ref=CantAnnotatePackages.out -XDrawDiagnostics CantAnnotatePackages.java diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out index 6e2b9cb93b0e2..b91d65828b97b 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out @@ -1,5 +1,5 @@ +CantAnnotatePackages.java:16:14: compiler.err.cant.resolve.location: kindname.class, java, , , (compiler.misc.location: kindname.class, CantAnnotatePackages, null) +CantAnnotatePackages.java:17:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotatePackages.java:18:14: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) CantAnnotatePackages.java:14:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object -CantAnnotatePackages.java:16:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object -CantAnnotatePackages.java:17:9: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object -CantAnnotatePackages.java:18:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object 4 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java index aec691c913dd6..4bdd791909c27 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8006733 8006775 8043226 + * @bug 8006733 8006775 8043226 8334055 * @summary Ensure behavior for nested types is correct. * @author Werner Dietl * @compile/fail/ref=CantAnnotateScoping.out -XDrawDiagnostics CantAnnotateScoping.java diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out index 2ae736ad315d4..ade5333a446fa 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out @@ -1,13 +1,12 @@ -CantAnnotateScoping.java:68:18: compiler.err.doesnt.exist: java.XXX +CantAnnotateScoping.java:63:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotateScoping.java:68:9: compiler.err.cant.resolve.location: kindname.class, XXX, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotateScoping.java:71:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) CantAnnotateScoping.java:38:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner CantAnnotateScoping.java:51:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object CantAnnotateScoping.java:60:37: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation: @TA,@TA2), java.lang, @DTA @TA @TA2 java.lang.Object CantAnnotateScoping.java:40:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner -CantAnnotateScoping.java:63:11: compiler.err.annotation.type.not.applicable.to.type: DA -CantAnnotateScoping.java:68:11: compiler.err.annotation.type.not.applicable.to.type: DA -CantAnnotateScoping.java:71:9: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object CantAnnotateScoping.java:44:34: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation: @TA,@TA2), Test.Outer, @TA @TA2 Test.Outer.SInner CantAnnotateScoping.java:44:25: compiler.err.annotation.type.not.applicable.to.type: DA CantAnnotateScoping.java:48:38: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner CantAnnotateScoping.java:48:34: compiler.err.annotation.type.not.applicable.to.type: DA -12 errors +11 errors From 73e3e0edeb20c6f701b213423476f92fb05dd262 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Thu, 11 Jul 2024 20:18:16 +0000 Subject: [PATCH 234/288] 8321509: False positive in get_trampoline fast path causes crash Reviewed-by: kvn, adinn, thartmann --- .../cpu/aarch64/globalDefinitions_aarch64.hpp | 4 +- .../cpu/aarch64/nativeInst_aarch64.cpp | 39 +++++++++---------- .../cpu/aarch64/nativeInst_aarch64.hpp | 7 ++-- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 33 ++++++++++------ src/hotspot/share/code/relocInfo.cpp | 8 ++++ src/hotspot/share/code/relocInfo.hpp | 5 +++ 6 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 63f6c9491c8de..faf635dc33282 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -76,4 +76,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define USE_POINTERS_TO_REGISTER_IMPL_ARRAY +#define USE_TRAMPOLINE_STUB_FIX_OWNER + #endif // CPU_AARCH64_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index c88705618e63d..5a3f9d228ca89 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -51,13 +51,18 @@ void NativeInstruction::wrote(int offset) { } address NativeCall::destination() const { - address addr = (address)this; - address destination = instruction_address() + displacement(); + address addr = instruction_address(); + address destination = addr + displacement(); + + // Performance optimization: no need to call find_blob() if it is a self-call + if (destination == addr) { + return destination; + } // Do we use a trampoline stub for this call? CodeBlob* cb = CodeCache::find_blob(addr); - assert(cb && cb->is_nmethod(), "sanity"); - nmethod *nm = (nmethod *)cb; + assert(cb != nullptr && cb->is_nmethod(), "nmethod expected"); + nmethod *nm = cb->as_nmethod(); if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { // Yes we do, so get the destination from the trampoline stub. const address trampoline_stub_addr = destination; @@ -72,12 +77,8 @@ address NativeCall::destination() const { // call instruction at all times. // // Used in the runtime linkage of calls; see class CompiledIC. -// -// Add parameter assert_lock to switch off assertion -// during code generation, where no patching lock is needed. -void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { - assert(!assert_lock || - (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || +void NativeCall::set_destination_mt_safe(address dest) { + assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); @@ -104,22 +105,18 @@ void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { } address NativeCall::get_trampoline() { - address call_addr = addr_at(0); + address call_addr = instruction_address(); CodeBlob *code = CodeCache::find_blob(call_addr); - assert(code != nullptr, "Could not find the containing code blob"); + assert(code != nullptr && code->is_nmethod(), "nmethod expected"); + nmethod* nm = code->as_nmethod(); - address bl_destination - = MacroAssembler::pd_call_destination(call_addr); - if (code->contains(bl_destination) && + address bl_destination = call_addr + displacement(); + if (nm->stub_contains(bl_destination) && is_NativeCallTrampolineStub_at(bl_destination)) return bl_destination; - if (code->is_nmethod()) { - return trampoline_stub_Relocation::get_trampoline_for(call_addr, (nmethod*)code); - } - - return nullptr; + return trampoline_stub_Relocation::get_trampoline_for(call_addr, nm); } // Inserts a native call instruction at a given pc diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 974214d985b5d..0eb5ff815be1d 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2108, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -174,6 +174,7 @@ class NativeCall: public NativeInstruction { int displacement() const { return (int_at(displacement_offset) << 6) >> 4; } address displacement_address() const { return addr_at(displacement_offset); } address return_address() const { return addr_at(return_address_offset); } + address raw_destination() const { return instruction_address() + displacement(); } address destination() const; void set_destination(address dest) { @@ -213,9 +214,7 @@ class NativeCall: public NativeInstruction { // // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) - - // The parameter assert_lock disables the assertion during code generation. - void set_destination_mt_safe(address dest, bool assert_lock = true); + void set_destination_mt_safe(address dest); address get_trampoline(); #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 332f24996930f..c4c8648d552d0 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -60,13 +60,12 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be a call here"); - if (NativeCall::is_call_at(addr())) { - address trampoline = nativeCall_at(addr())->get_trampoline(); - if (trampoline) { - return nativeCallTrampolineStub_at(trampoline)->destination(); + if (orig_addr == nullptr) { + if (NativeCall::is_call_at(addr())) { + NativeCall* call = nativeCall_at(addr()); + return call->destination(); } - } - if (orig_addr != nullptr) { + } else { address new_addr = MacroAssembler::pd_call_destination(orig_addr); // If call is branch to self, don't try to relocate it, just leave it // as branch to self. This happens during code generation if the code @@ -82,16 +81,26 @@ address Relocation::pd_call_destination(address orig_addr) { void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { - address trampoline = nativeCall_at(addr())->get_trampoline(); - if (trampoline) { - nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false); - return; - } + NativeCall* call = nativeCall_at(addr()); + call->set_destination(x); + } else { + MacroAssembler::pd_patch_instruction(addr(), x); } - MacroAssembler::pd_patch_instruction(addr(), x); assert(pd_call_destination(addr()) == x, "fail in reloc"); } +void trampoline_stub_Relocation::pd_fix_owner_after_move() { + NativeCall* call = nativeCall_at(owner()); + assert(call->raw_destination() == owner(), "destination should be empty"); + address trampoline = addr(); + address dest = nativeCallTrampolineStub_at(trampoline)->destination(); + if (!Assembler::reachable_from_branch_at(owner(), dest)) { + dest = trampoline; + } + call->set_destination(dest); +} + + address* Relocation::pd_address_in_code() { return (address*)(addr() + 8); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 3b19b63f24469..a379f88ddc180 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -373,6 +373,14 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer } +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER +void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { + // Finalize owner destination only for nmethods + if (dest->blob() != nullptr) return; + pd_fix_owner_after_move(); +} +#endif + //// pack/unpack methods void oop_Relocation::pack_data_to(CodeSection* dest) { diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 6d0907d97dedc..25cca49e50bb8 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -1258,6 +1258,11 @@ class runtime_call_w_cp_Relocation : public CallRelocation { // in the code, it can patch it to jump to the trampoline where is // sufficient space for a far branch. Needed on PPC. class trampoline_stub_Relocation : public Relocation { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + void pd_fix_owner_after_move(); + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; +#endif + public: static RelocationHolder spec(address static_call) { return RelocationHolder::construct(static_call); From 889055713ea83f899ebd7bf640dcf3c3e1a82ebe Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 11 Jul 2024 20:44:21 +0000 Subject: [PATCH 235/288] 8335623: Clean up HtmlTag.HtmlTag and make the ARIA role attribute global Reviewed-by: liach --- .../jdk/javadoc/internal/doclint/HtmlTag.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java index 0c820dae91392..fa9d3ea578dd4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java @@ -507,7 +507,7 @@ public enum Attr { PROFILE, REV, REVERSED, - ROLE, + ROLE(true), ROWSPAN, RULES, SCHEME, @@ -606,26 +606,6 @@ private static class AttrMap extends EnumMap { this.attrs = new EnumMap<>(Attr.class); for (Map m: attrMaps) this.attrs.putAll(m); - attrs.put(Attr.CLASS, AttrKind.OK); - attrs.put(Attr.ID, AttrKind.OK); - attrs.put(Attr.STYLE, AttrKind.OK); - attrs.put(Attr.ROLE, AttrKind.OK); - // for now, assume that all ARIA attributes are allowed on all tags. - attrs.put(Attr.ARIA_ACTIVEDESCENDANT, AttrKind.OK); - attrs.put(Attr.ARIA_CONTROLS, AttrKind.OK); - attrs.put(Attr.ARIA_DESCRIBEDBY, AttrKind.OK); - attrs.put(Attr.ARIA_EXPANDED, AttrKind.OK); - attrs.put(Attr.ARIA_LABEL, AttrKind.OK); - attrs.put(Attr.ARIA_LABELLEDBY, AttrKind.OK); - attrs.put(Attr.ARIA_LEVEL, AttrKind.OK); - attrs.put(Attr.ARIA_MULTISELECTABLE, AttrKind.OK); - attrs.put(Attr.ARIA_OWNS, AttrKind.OK); - attrs.put(Attr.ARIA_POSINSET, AttrKind.OK); - attrs.put(Attr.ARIA_READONLY, AttrKind.OK); - attrs.put(Attr.ARIA_REQUIRED, AttrKind.OK); - attrs.put(Attr.ARIA_SELECTED, AttrKind.OK); - attrs.put(Attr.ARIA_SETSIZE, AttrKind.OK); - attrs.put(Attr.ARIA_SORT, AttrKind.OK); } public boolean accepts(HtmlTag t) { From 687601ebcaedf133fd4d5cecc42c5aadf9c73f3c Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 11 Jul 2024 20:45:34 +0000 Subject: [PATCH 236/288] 8336257: Additional tests in jmxremote/startstop to match on PID not app name Reviewed-by: cjplummer, alanb, amenkov, dcubed --- .../sun/management/jmxremote/startstop/JMXStartStopTest.java | 5 +++-- .../jmxremote/startstop/JMXStatusPerfCountersTest.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java b/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java index 13a4f7bea73f0..3d125325449f5 100644 --- a/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java +++ b/test/jdk/sun/management/jmxremote/startstop/JMXStartStopTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,7 +72,7 @@ public class JMXStartStopTest { private static final boolean verbose = false; - private static ManagementAgentJcmd jcmd = new ManagementAgentJcmd(TEST_APP_NAME, verbose); + private static ManagementAgentJcmd jcmd; private static void dbg_print(String msg) { if (verbose) { @@ -347,6 +347,7 @@ public synchronized void start() throws InterruptedException, IOException, Timeo "the requested port not being available"); } pid = p.pid(); + jcmd = new ManagementAgentJcmd(p, verbose); } catch (TimeoutException e) { if (p != null) { p.destroy(); diff --git a/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java b/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java index fc7a0de2d0630..e3703ba8dbc87 100644 --- a/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java +++ b/test/jdk/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ public static void setupClass() throws Exception { @BeforeTest public void setup() { - jcmd = new ManagementAgentJcmd(TEST_APP_NAME, false); } @BeforeMethod @@ -76,6 +75,7 @@ public void startTestApp() throws Exception { TEST_APP_NAME, testAppPb, (Predicate)l->l.trim().equals("main enter") ); + jcmd = new ManagementAgentJcmd(testApp, false); } @AfterMethod From b3ef2a600cfec31723dc78fe552e9cf9976b0337 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 11 Jul 2024 20:51:27 +0000 Subject: [PATCH 237/288] 8336036: Synthetic documentation for a record's equals is incorrect for floating-point types Reviewed-by: prappo --- .../doclets/toolkit/resources/doclets.properties | 6 ++++-- .../doclet/testRecordTypes/TestRecordTypes.java | 14 +++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 859289ff8bd21..0ee9429ec0c65 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -319,10 +319,12 @@ doclet.record_equals_doc.fullbody.head=\ doclet.record_equals_doc.fullbody.tail.both=\ Reference components are compared with \ {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; \ - primitive components are compared with '=='. + primitive components are compared with the compare method from \ + their corresponding wrapper classes. doclet.record_equals_doc.fullbody.tail.primitive=\ - All components in this record class are compared with '=='. + All components in this record class are compared with the compare \ + method from their corresponding wrapper classes. doclet.record_equals_doc.fullbody.tail.reference=\ All components in this record class are compared with \ diff --git a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java index c4579c501ec77..f9aa3cfd6fa49 100644 --- a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java +++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,8 @@ public record R(int r1) { }"""); """ Indicates whether some other object is "equal to" this one. The objects are equa\ l if the other object is of the same class and if all the record components are \ - equal. All components in this record class are compared with '=='.""", + equal. All components in this record class are compared with the compare method from their corresponding wrapper classes.""", """ r1""", """ @@ -300,7 +301,8 @@ public record R(int r1) { }"""); """ Indicates whether some other object is "equal to" this one. The objects are equa\ l if the other object is of the same class and if all the record components are \ - equal. All components in this record class are compared with '=='.""", + equal. All components in this record class are compared with the compare method from their corresponding wrapper classes.""", """ r1""", """ @@ -311,7 +313,8 @@ l if the other object is of the same class and if all the record components are @Test public void testGeneratedEqualsPrimitive(Path base) throws IOException { testGeneratedEquals(base, "int a, int b", - "All components in this record class are compared with '=='."); + "All components in this record class are compared with the compare method " + + "from their corresponding wrapper classes."); } @Test @@ -324,7 +327,8 @@ public void testGeneratedEqualsReference(Path base) throws IOException { public void testGeneratedEqualsMixed(Path base) throws IOException { testGeneratedEquals(base, "int a, Object b", "Reference components are compared with Objects::equals(Object,Object); " - + "primitive components are compared with '=='."); + + "primitive components are compared with the compare method from their " + + "corresponding wrapper classes."); } private void testGeneratedEquals(Path base, String comps, String expect) throws IOException { From 81a0d1ba03bbdbe718302b3925cdc207d5d05232 Mon Sep 17 00:00:00 2001 From: Vanitha B P Date: Thu, 11 Jul 2024 21:27:30 +0000 Subject: [PATCH 238/288] 8325525: Create jtreg test case for JDK-8325203 Reviewed-by: asemenyuk, almatvee --- .../apps/ChildProcessAppLauncher.java | 37 ++++++++ .../jpackage/windows/WinChildProcessTest.java | 88 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java create mode 100644 test/jdk/tools/jpackage/windows/WinChildProcessTest.java diff --git a/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java b/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java new file mode 100644 index 0000000000000..11be90bc45622 --- /dev/null +++ b/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +public class ChildProcessAppLauncher { + + public static void main(String[] args) throws IOException { + String calcPath = Path.of(System.getenv("SystemRoot"), "system32", "calc.exe").toString(); + ProcessBuilder processBuilder = new ProcessBuilder(calcPath); + Process process = processBuilder.start(); + System.out.println("Calc id=" + process.pid()); + System.exit(0); + } +} diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java new file mode 100644 index 0000000000000..2928f7f1c5ffe --- /dev/null +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 8325203 + * @summary Test that Jpackage windows executable application kills the launched 3rd party application + * when System.exit(0) is invoked along with terminating java program. + * @library ../helpers + * @library /test/lib + * @requires os.family == "windows" + * @build WinChildProcessTest + * @build jdk.jpackage.test.* + * @build WinChildProcessTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * --jpt-run=WinChildProcessTest + * + */ + +import java.util.List; +import java.util.Optional; + +import java.nio.file.Path; + +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Executor; +import jdk.jpackage.test.TKit; + +public class WinChildProcessTest { + private static final Path TEST_APP_JAVA = TKit.TEST_SRC_ROOT + .resolve("apps/ChildProcessAppLauncher.java"); + + @Test + public static void test() throws Throwable { + long calcPid = 0; + try { + JPackageCommand cmd = JPackageCommand + .helloAppImage(TEST_APP_JAVA + "*Hello"); + + // Create the image of the third party application launcher + cmd.executeAndAssertImageCreated(); + + // Start the third party application launcher and dump and save the + // output of the application + List output = new Executor().saveOutput().dumpOutput() + .setExecutable(cmd.appLauncherPath().toAbsolutePath()) + .execute(0).getOutput(); + String pidStr = output.get(0); + + // parse calculator PID + calcPid = Long.parseLong(pidStr.split("=", 2)[1]); + + // Check whether the termination of third party application launcher + // also terminating the launched third party application + // If third party application is not terminated the test is + // successful else failure + Optional processHandle = ProcessHandle.of(calcPid); + boolean isAlive = processHandle.isPresent() + && processHandle.get().isAlive(); + System.out.println("Is Alive " + isAlive); + TKit.assertTrue(isAlive, "Check is calculator process is alive"); + } finally { + // Kill only a specific calculator instance + Runtime.getRuntime().exec("taskkill /F /PID " + calcPid); + } + } +} \ No newline at end of file From c703d290425f85a06e61d72c9672ac2adac92db9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 12 Jul 2024 05:56:53 +0000 Subject: [PATCH 239/288] 8335710: serviceability/dcmd/vm/SystemDumpMapTest.java and SystemMapTest.java fail on Linux Alpine after 8322475 Reviewed-by: stuefe, lucy --- .../jtreg/serviceability/dcmd/vm/SystemMapTestBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java index 000e977a590e5..3d1284b09eeee 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SystemMapTestBase.java @@ -49,8 +49,8 @@ public class SystemMapTestBase { regexBase_committed + "/bin/java", // libjvm regexBase_committed + "/lib/.*/libjvm.so", - // vdso library, should be part of all user space apps on all architectures OpenJDK supports. - regexBase_committed + "\\[vdso\\]", + // heap segment, should be part of all user space apps on all architectures OpenJDK supports. + regexBase_committed + "\\[heap\\]", // we should see the hs-perf data file, and it should appear as shared as well as committed regexBase_shared_and_committed + "hsperfdata_.*" }; From 1fe3ada001e188754df5de00bf6804f028ad274b Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 12 Jul 2024 08:14:56 +0000 Subject: [PATCH 240/288] 8336284: Test TestClhsdbJstackLock.java/TestJhsdbJstackLock.java fails with -Xcomp after JDK-8335743 Reviewed-by: cjplummer, amenkov --- test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java | 2 +- test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java b/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java index e4d4361e6512b..266b14167ef4e 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java +++ b/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java @@ -59,7 +59,7 @@ public static void main (String... args) throws Exception { "^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$", "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$", "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$", - "^\\s+- waiting on <0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)$")); + "^\\s+- waiting on (<0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)|)$")); unExpStrMap.put("jstack", List.of( "missing reason for ")); test.run(app.getPid(), cmds, expStrMap, unExpStrMap); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java index 98c4286609178..d3c7f61103165 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java @@ -65,7 +65,7 @@ public static void main (String... args) throws Exception { out.shouldMatch("^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$"); out.shouldMatch("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$"); out.shouldMatch("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$"); - out.shouldMatch("^\\s+- waiting on <0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)$"); + out.shouldMatch("^\\s+- waiting on (<0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)|)$"); out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); From f677b90eb93026d3fdfd4ae19d48415a7d8318e8 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 12 Jul 2024 08:19:24 +0000 Subject: [PATCH 241/288] 8267887: RMIConnector_NPETest.java fails after removal of RMI Activation (JDK-8267123) Reviewed-by: cjplummer, sspitsyn --- test/jdk/ProblemList.txt | 2 - .../connection/RMIConnector_NPETest.java | 77 ------------------- 2 files changed, 79 deletions(-) delete mode 100644 test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 20dfcef539de3..05e42b4933046 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -528,8 +528,6 @@ javax/management/MBeanServer/OldMBeanServerTest.java 8030957 aix-all javax/management/monitor/DerivedGaugeMonitorTest.java 8042211 generic-all -javax/management/remote/mandatory/connection/RMIConnector_NPETest.java 8267887 generic-all - javax/management/remote/mandatory/connection/BrokenConnectionTest.java 8262312 linux-all ############################################################################ diff --git a/test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java b/test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java deleted file mode 100644 index 29a91a464c713..0000000000000 --- a/test/jdk/javax/management/remote/mandatory/connection/RMIConnector_NPETest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. - * 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 NPE IN RMIConnector.connect - * @bug 6984520 - * @library /java/rmi/testlibrary - * @modules java.management.rmi - * java.rmi/sun.rmi.registry - * java.rmi/sun.rmi.server - * java.rmi/sun.rmi.transport - * java.rmi/sun.rmi.transport.tcp - * @run clean RMIConnector_NPETest - * @run build TestLibrary RMID - * @run build RMIConnector_NPETest - * @run main RMIConnector_NPETest - */ -import java.io.IOException; -import javax.management.*; -import javax.management.remote.rmi.*; - -public class RMIConnector_NPETest { - public static void main(String argv[]) throws Exception { - RMID rmid = RMID.createRMID(); - Exception failureCause = null; - RMIConnector agent = null; - - try { - rmid.start(); - int rmidPort = rmid.getPort(); - MBeanServer mbs = MBeanServerFactory.createMBeanServer(); - RMIJRMPServerImpl rmiserver = new RMIJRMPServerImpl(rmidPort, null, null, null); - rmiserver.setMBeanServer(mbs); - agent = new RMIConnector(rmiserver, null); - agent.connect(); - } catch (NullPointerException npe) { - failureCause = npe; - } catch (Exception e) { - // OK - } finally { - if (agent != null) { - try { - agent.close(); - } catch (IOException e) { - // ignore - } - } - rmid.destroy(); - } - - if (failureCause != null) { - TestLibrary.bomb("Test failed", failureCause); - } - - } -} From 7a6203296416268f1c3f269d0db2b0c817642a34 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 12 Jul 2024 09:30:38 +0000 Subject: [PATCH 242/288] 8336081: Fix -Wzero-as-null-pointer-constant warnings in JVMTypedFlagLimit ctors Reviewed-by: dholmes, jwaters --- src/hotspot/share/runtime/flags/jvmFlagLimit.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp b/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp index 69df96f226dd8..4a9c9c66d9b37 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLimit.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,7 +155,7 @@ class JVMTypedFlagLimit : public JVMFlagLimit { // dummy - no range or constraint. This object will not be emitted into the .o file // because we declare it as "const" but has no reference to it. constexpr JVMTypedFlagLimit(int type_enum) : - JVMFlagLimit(0, 0, JVMFlagConstraintPhase::AtParse, 0), _min(0), _max(0) {} + JVMFlagLimit(0, 0, JVMFlagConstraintPhase::AtParse, 0), _min(), _max() {} // range only constexpr JVMTypedFlagLimit(int type_enum, T min, T max) : @@ -163,7 +163,7 @@ class JVMTypedFlagLimit : public JVMFlagLimit { // constraint only constexpr JVMTypedFlagLimit(int type_enum, ConstraintMarker dummy2, short func, JVMFlagConstraintPhase phase) : - JVMFlagLimit(type_enum, func, phase, HAS_CONSTRAINT), _min(0), _max(0) {} + JVMFlagLimit(type_enum, func, phase, HAS_CONSTRAINT), _min(), _max() {} // range and constraint constexpr JVMTypedFlagLimit(int type_enum, T min, T max, ConstraintMarker dummy2, short func, JVMFlagConstraintPhase phase) : From 9b6f6c5c9dd6d0fbb056e8d84c3a0888a3320edf Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 12 Jul 2024 09:33:04 +0000 Subject: [PATCH 243/288] 8336082: Fix -Wzero-as-null-pointer-constant warnings in SimpleCompactHashtable Reviewed-by: coleenp, dholmes --- .../share/classfile/compactHashtable.hpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index e99369cc5c376..6cb689ad20df6 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -204,18 +204,20 @@ class SimpleCompactHashtable { u4* _entries; public: - SimpleCompactHashtable() { - _entry_count = 0; - _bucket_count = 0; - _buckets = 0; - _entries = 0; - } + SimpleCompactHashtable() : + _base_address(nullptr), + _bucket_count(0), + _entry_count(0), + _buckets(nullptr), + _entries(nullptr) + {} void reset() { + _base_address = nullptr; _bucket_count = 0; _entry_count = 0; - _buckets = 0; - _entries = 0; + _buckets = nullptr; + _entries = nullptr; } void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries); From eec0e155f303ff4bbdab172765ca7c92c2b94cbd Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Fri, 12 Jul 2024 12:09:58 +0000 Subject: [PATCH 244/288] 8335619: Add an @apiNote to j.l.i.ClassFileTransformer to warn about recursive class loading and ClassCircularityErrors Reviewed-by: alanb, stuefe, liach --- .../lang/instrument/ClassFileTransformer.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java index d4c17f1cfdcf7..ee2037fac5bfb 100644 --- a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java +++ b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,11 +155,28 @@ * logging or debugging of format corruptions. * *

    - * Note the term class file is used as defined in section 3.1 of - * The Java Virtual Machine Specification, to mean a - * sequence of bytes in class file format, whether or not they reside in a + * Note the term class file is used as defined in chapter {@jvms 4} The + * {@code class} File Format of The Java Virtual Machine Specification, + * to mean a sequence of bytes in class file format, whether or not they reside in a * file. * + * @apiNote + * Great care must be taken when transforming core JDK classes which are at the + * same time required during the transformation process as this can lead to class + * circularity or linkage errors. + * + *

    + * If for example the invocation of {@link #transform transform()} for a class + * {@code C} requires loading or resolving the same class {@code C}, + * an error is thrown that is an instance of {@link LinkageError} (or a subclass). + * If the {@link LinkageError} occurs during reference resolution (see section + * {@jvms 5.4.3} Resolution of The Java Virtual Machine Specification) + * for a class {@code D}, the resolution of the corresponding reference in class + * {@code D} will permanently fail with the same error at any subsequent attempt. + * This means that a {@link LinkageError} triggered during transformation of + * {@code C} in a class {@code D} not directly related to {@code C} can repeatedly + * occur later in arbitrary user code which uses {@code D}. + * * @see java.lang.instrument.Instrumentation * @since 1.5 */ From 559826c2922851dbe45ead23ad1d73b1846334ac Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 12 Jul 2024 12:17:21 +0000 Subject: [PATCH 245/288] 8332474: Tighten up ToolBox' JavacTask to not silently accept javac crash as a failure Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Modules.java | 1 + .../tools/lib/toolbox/AbstractTask.java | 60 ++++++++++++++++--- .../tools/lib/toolbox/JavacTask.java | 20 +++++++ 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 1136cb5621a79..3d893252218b5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -330,6 +330,7 @@ private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set> implements Task { private final Map redirects = new EnumMap<>(OutputKind.class); private final Map envVars = new HashMap<>(); private Expect expect = Expect.SUCCESS; - int expectedExitCode = 0; + //validator for exit codes, first parameter is the exit code + //the second the test name: + private BiConsumer exitCodeValidator = null; /** * Create a task that will execute in the specified mode. @@ -67,7 +70,7 @@ protected AbstractTask(ToolBox tb, Mode mode) { * @return the result of calling {@code run()} */ public Result run(Expect expect) { - expect(expect, Integer.MIN_VALUE); + expect(expect, (_, _) -> {}); return run(); } @@ -83,17 +86,56 @@ public Result run(Expect expect, int exitCode) { return run(); } + /** + * Sets the expected outcome of the task and calls {@code run()}. + * @param expect the expected outcome + * @param exitCodeValidator an exit code validator. The first parameter will + * be the actual exit code, the second test name, + * should throw TaskError if the exit code is not + * as expected. Only used if the expected outcome + * is {@code FAIL} + * @return the result of calling {@code run()} + */ + public Result run(Expect expect, + BiConsumer exitCodeValidator) { + expect(expect, exitCodeValidator); + return run(); + } + + /** + * Sets the expected outcome and expected exit code of the task. + * The exit code will not be checked if the outcome is + * {@code Expect.SUCCESS} or if the exit code is set to + * {@code Integer.MIN_VALUE}. + * @param expect the expected outcome + * @param expectedExitCode the expected exit code + */ + protected void expect(Expect expect, int expectedExitCode) { + expect(expect, (exitCode, testName) -> { + if (expectedExitCode != Integer.MIN_VALUE && + exitCode != expectedExitCode) { + throw new TaskError("Task " + testName + "failed with unexpected exit code " + + exitCode + ", expected " + expectedExitCode); + } + }); + } + /** * Sets the expected outcome and expected exit code of the task. * The exit code will not be checked if the outcome is * {@code Expect.SUCCESS} or if the exit code is set to * {@code Integer.MIN_VALUE}. * @param expect the expected outcome - * @param exitCode the expected exit code + * @param exitCodeValidator an exit code validator. The first parameter will + * be the actual exit code, the second test name, + * should throw TaskError if the exit code is not + * as expected. Only used if the expected outcome + * is {@code FAIL} */ - protected void expect(Expect expect, int exitCode) { + protected void expect(Expect expect, + BiConsumer exitCodeValidator) { this.expect = expect; - this.expectedExitCode = exitCode; + this.exitCodeValidator = exitCodeValidator; } /** @@ -119,11 +161,11 @@ protected Result checkExit(Result result) throws TaskError { throw new TaskError("Task " + name() + " succeeded unexpectedly"); } - if (expectedExitCode != Integer.MIN_VALUE - && result.exitCode != expectedExitCode) { + try { + exitCodeValidator.accept(result.exitCode, name()); + } catch (Throwable t) { result.writeAll(); - throw new TaskError("Task " + name() + "failed with unexpected exit code " - + result.exitCode + ", expected " + expectedExitCode); + throw t; } break; } diff --git a/test/langtools/tools/lib/toolbox/JavacTask.java b/test/langtools/tools/lib/toolbox/JavacTask.java index 5991d9e6063bc..ed056099e84e3 100644 --- a/test/langtools/tools/lib/toolbox/JavacTask.java +++ b/test/langtools/tools/lib/toolbox/JavacTask.java @@ -314,6 +314,26 @@ public String name() { return "javac"; } + @Override + public Result run(Expect expect) { + int expectedExitCode = expect == Expect.SUCCESS ? 0 : 1; + + return run(expect, (exitCode, testName) -> { + if (exitCode == 4) { + throw new TaskError("Task " + testName + " failed due to a javac crash " + + "(exit code 4)"); + } + }); + } + + @Override + public Result run(Expect expect, int exitCode) { + if (exitCode == 4) { + throw new IllegalArgumentException("Disallowed exit code: 4"); + } + return super.run(expect, exitCode); + } + /** * Calls the compiler with the arguments as currently configured. * @return a Result object indicating the outcome of the compilation From 2fc7eb44a018974734832576a0a2631ae747e0cd Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 12 Jul 2024 12:37:58 +0000 Subject: [PATCH 246/288] 8155030: The Menu Mnemonics are always displayed for GTK LAF Hides mnemonics on menus, buttons, and labels for GTK L&F. Moved shared code for hiding mnemonics into sun/swing/MnemonicHandler and AltProcessor to avoid code duplication. Reviewed-by: prr, tr, achung, dnguyen, aivanov --- .../classes/com/apple/laf/AquaButtonUI.java | 7 +- .../classes/com/apple/laf/AquaLabelUI.java | 21 +-- .../com/apple/laf/AquaLookAndFeel.java | 11 +- .../com/apple/laf/AquaMenuPainter.java | 38 ++++-- .../java/swing/plaf/gtk/GTKGraphicsUtils.java | 21 ++- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 70 ++++++++-- .../share/classes/sun/swing/AltProcessor.java | 67 ++++++++++ .../classes/sun/swing/MnemonicHandler.java} | 100 ++++++--------- .../plaf/windows/WindowsGraphicsUtils.java | 75 ++++------- .../swing/plaf/windows/WindowsLabelUI.java | 7 +- .../plaf/windows/WindowsLookAndFeel.java | 42 +----- .../swing/plaf/windows/WindowsMenuBarUI.java | 6 +- .../swing/plaf/windows/WindowsMenuItemUI.java | 5 +- .../plaf/windows/WindowsPopupMenuUI.java | 9 +- .../swing/plaf/windows/WindowsRootPaneUI.java | 36 +++--- .../swing/JMenuBar/TestMenuMnemonic.java | 8 +- .../JMenuBar/TestMenuMnemonicLinuxAndMac.java | 121 ++++++++++++++++++ .../javax/swing/LookAndFeel/bug4736093.java | 12 +- .../plaf/windows/6921687/bug6921687.java | 11 +- 19 files changed, 428 insertions(+), 239 deletions(-) create mode 100644 src/java.desktop/share/classes/sun/swing/AltProcessor.java rename src/java.desktop/{macosx/classes/com/apple/laf/AquaMnemonicHandler.java => share/classes/sun/swing/MnemonicHandler.java} (52%) create mode 100644 test/jdk/javax/swing/JMenuBar/TestMenuMnemonicLinuxAndMac.java diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java index dab893252cfdb..063923ff80754 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,7 @@ import com.apple.laf.AquaUtilControlSize.Sizeable; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +import sun.swing.MnemonicHandler; import sun.swing.SwingUtilities2; public class AquaButtonUI extends BasicButtonUI implements Sizeable { @@ -487,12 +488,10 @@ protected void paintIcon(final Graphics g, final AbstractButton b, final Rectang * Use the paintText method which takes the AbstractButton argument. */ protected void paintText(final Graphics g, final JComponent c, final Rectangle localTextRect, final String text) { - final Graphics2D g2d = g instanceof Graphics2D ? (Graphics2D)g : null; - final AbstractButton b = (AbstractButton)c; final ButtonModel model = b.getModel(); final FontMetrics fm = g.getFontMetrics(); - final int mnemonicIndex = AquaMnemonicHandler.isMnemonicHidden() ? -1 : b.getDisplayedMnemonicIndex(); + final int mnemonicIndex = MnemonicHandler.isMnemonicHidden() ? -1 : b.getDisplayedMnemonicIndex(); /* Draw the Text */ if (model.isEnabled()) { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java index fb5682d05413e..e0f282325e412 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,19 @@ package com.apple.laf; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; - -import sun.swing.SwingUtilities2; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicLabelUI; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +import sun.swing.MnemonicHandler; +import sun.swing.SwingUtilities2; public class AquaLabelUI extends BasicLabelUI { private static final RecyclableSingleton aquaLabelUI = new RecyclableSingletonFromDefaultConstructor(AquaLabelUI.class); @@ -55,7 +58,7 @@ protected void uninstallListeners(final JLabel c) { protected void paintEnabledText(final JLabel l, final Graphics g, final String s, final int textX, final int textY) { int mnemIndex = l.getDisplayedMnemonicIndex(); - if (AquaMnemonicHandler.isMnemonicHidden()) { + if (MnemonicHandler.isMnemonicHidden()) { mnemIndex = -1; } @@ -72,7 +75,7 @@ protected void paintEnabledText(final JLabel l, final Graphics g, final String s */ protected void paintDisabledText(final JLabel l, final Graphics g, final String s, final int textX, final int textY) { int accChar = l.getDisplayedMnemonicIndex(); - if (AquaMnemonicHandler.isMnemonicHidden()) { + if (MnemonicHandler.isMnemonicHidden()) { accChar = -1; } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java index d68cd1448eaa9..83604e5d835cd 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,8 @@ import apple.laf.JRSUIControl; import apple.laf.JRSUIUtils; +import sun.swing.AltProcessor; +import sun.swing.MnemonicHandler; import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; @@ -174,7 +176,9 @@ public Void run() { spf.setActive(true); PopupFactory.setSharedInstance(spf); - KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(AquaMnemonicHandler.getInstance()); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addKeyEventPostProcessor(AltProcessor.getInstance()); + MnemonicHandler.setMnemonicHidden(true); } /** @@ -185,7 +189,8 @@ public Void run() { * @see #initialize */ public void uninitialize() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(AquaMnemonicHandler.getInstance()); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removeKeyEventPostProcessor(AltProcessor.getInstance()); final PopupFactory popupFactory = PopupFactory.getSharedInstance(); if (popupFactory instanceof ScreenPopupFactory spf) { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java index 5a13822fd5acd..8f1a6799ff6b6 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,39 @@ package com.apple.laf; -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; -import sun.swing.SwingUtilities2; - -import apple.laf.JRSUIConstants.*; - +import apple.laf.JRSUIConstants.State; +import apple.laf.JRSUIConstants.Widget; import com.apple.laf.AquaIcon.InvertableIcon; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +import sun.swing.MnemonicHandler; +import sun.swing.SwingUtilities2; /** * AquaMenuPainter, implements paintMenuItem to avoid code duplication @@ -287,7 +305,7 @@ protected void paintMenuItem(final Client client, final Graphics g, final JCompo if (v != null) { v.paint(g, textRect); } else { - final int mnemonic = (AquaMnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic()); + final int mnemonic = (MnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic()); drawString(g, c, text, mnemonic, textRect.x, textRect.y + fm.getAscent(), isEnabled, isSelected); } } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java index 0ef404593f592..2a0aa7be41c45 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKGraphicsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,19 @@ */ package com.sun.java.swing.plaf.gtk; -import javax.swing.*; -import javax.swing.plaf.synth.*; import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.plaf.synth.Region; +import javax.swing.plaf.synth.SynthConstants; +import javax.swing.plaf.synth.SynthContext; +import javax.swing.plaf.synth.SynthGraphicsUtils; + +import sun.swing.MnemonicHandler; + /** * @author Joshua Outwater */ @@ -49,6 +56,11 @@ public void paintText(SynthContext context, Graphics g, String text, int componentState = context.getComponentState(); String themeName = GTKLookAndFeel.getGtkThemeName(); + + if (MnemonicHandler.isMnemonicHidden()) { + mnemonicIndex = -1; + } + if (themeName != null && themeName.startsWith("blueprint") && shouldShadowText(context.getRegion(), componentState)) { @@ -115,7 +127,8 @@ public void paintText(SynthContext context, Graphics g, String text, g.setColor(color); } } - super.paintText(context, g, text, bounds, mnemonicIndex); + super.paintText(context, g, text, bounds, + MnemonicHandler.isMnemonicHidden() ? -1 : mnemonicIndex); } private static boolean shouldShadowText(Region id, int state) { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 65f29ea8384fe..93ba22d8dd3da 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -25,28 +25,50 @@ package com.sun.java.swing.plaf.gtk; -import java.awt.*; -import java.beans.*; -import java.io.File; -import java.lang.ref.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Toolkit; +import java.awt.Window; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Locale; -import javax.swing.*; -import javax.swing.colorchooser.*; -import javax.swing.plaf.*; -import javax.swing.plaf.synth.*; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.LayoutStyle; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.colorchooser.AbstractColorChooserPanel; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.DimensionUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.synth.Region; +import javax.swing.plaf.synth.SynthConstants; +import javax.swing.plaf.synth.SynthLookAndFeel; +import javax.swing.plaf.synth.SynthStyleFactory; import javax.swing.text.DefaultEditorKit; import com.sun.java.swing.plaf.gtk.GTKConstants.PositionType; import com.sun.java.swing.plaf.gtk.GTKConstants.StateType; -import java.util.HashMap; -import java.util.Map; import sun.awt.SunToolkit; import sun.awt.UNIXToolkit; -import sun.awt.OSInfo; import sun.security.action.GetPropertyAction; +import sun.swing.AltProcessor; import sun.swing.DefaultLayoutStyle; +import sun.swing.MnemonicHandler; import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; @@ -866,7 +888,6 @@ public Object createValue(UIDefaults table) { "ctrl released ENTER", "release" }, - "ScrollBar.squareButtons", Boolean.FALSE, "ScrollBar.thumbHeight", Integer.valueOf(14), "ScrollBar.width", Integer.valueOf(16), @@ -1414,6 +1435,10 @@ static boolean isLeftToRight(Component c) { return c.getComponentOrientation().isLeftToRight(); } + /** + * {@inheritDoc} + */ + @Override public void initialize() { /* * We need to call loadGTK() to ensure that the native GTK @@ -1456,6 +1481,23 @@ public void initialize() { gtkAAFontSettingsCond = SwingUtilities2.isLocalDisplay(); aaTextInfo = new HashMap<>(2); SwingUtilities2.putAATextInfo(gtkAAFontSettingsCond, aaTextInfo); + + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addKeyEventPostProcessor(AltProcessor.getInstance()); + + // By default mnemonics are hidden for GTK L&F + MnemonicHandler.setMnemonicHidden(true); + } + + /** + * {@inheritDoc} + */ + @Override + public void uninitialize() { + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removeKeyEventPostProcessor(AltProcessor.getInstance()); + MnemonicHandler.setMnemonicHidden(false); + super.uninitialize(); } static ReferenceQueue queue = new ReferenceQueue(); diff --git a/src/java.desktop/share/classes/sun/swing/AltProcessor.java b/src/java.desktop/share/classes/sun/swing/AltProcessor.java new file mode 100644 index 0000000000000..c7bb7b3d4102e --- /dev/null +++ b/src/java.desktop/share/classes/sun/swing/AltProcessor.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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 sun.swing; + +import java.awt.KeyEventPostProcessor; +import java.awt.Window; +import java.awt.event.KeyEvent; + +import javax.swing.JRootPane; +import javax.swing.SwingUtilities; + +public final class AltProcessor implements KeyEventPostProcessor { + + private AltProcessor() {} + + private static final AltProcessor altProcessor = new AltProcessor(); + + public static KeyEventPostProcessor getInstance() { + return altProcessor; + } + + @Override + public boolean postProcessKeyEvent(final KeyEvent ev) { + if (ev.getKeyCode() != KeyEvent.VK_ALT) { + return false; + } + + final JRootPane root = SwingUtilities.getRootPane(ev.getComponent()); + final Window winAncestor = (root == null ? null : SwingUtilities.getWindowAncestor(root)); + + switch (ev.getID()) { + case KeyEvent.KEY_PRESSED: + MnemonicHandler.setMnemonicHidden(false); + break; + case KeyEvent.KEY_RELEASED: + MnemonicHandler.setMnemonicHidden(true); + break; + } + + MnemonicHandler.repaintMnemonicsInWindow(winAncestor); + + return false; + } +} diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java b/src/java.desktop/share/classes/sun/swing/MnemonicHandler.java similarity index 52% rename from src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java rename to src/java.desktop/share/classes/sun/swing/MnemonicHandler.java index 76c9735882807..b4f0cac7c611a 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java +++ b/src/java.desktop/share/classes/sun/swing/MnemonicHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * 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,39 +23,27 @@ * questions. */ -package com.apple.laf; +package sun.swing; -import java.awt.*; -import java.awt.event.KeyEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Window; -import javax.swing.*; +import javax.swing.AbstractButton; +import javax.swing.JLabel; +import javax.swing.UIManager; -import com.apple.laf.AquaUtils.RecyclableSingleton; -import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; +public final class MnemonicHandler { -public class AquaMnemonicHandler { - private static final RecyclableSingleton altProcessor = new RecyclableSingletonFromDefaultConstructor(AltProcessor.class); - public static KeyEventPostProcessor getInstance() { - return altProcessor.get(); - } + private static boolean isMnemonicHidden; - protected static boolean isMnemonicHidden = true; // true by default - - public static void setMnemonicHidden(final boolean hide) { - if (UIManager.getBoolean("Button.showMnemonics")) { - // Do not hide mnemonics if the UI defaults do not support this - isMnemonicHidden = false; - } else { - isMnemonicHidden = hide; - } - } + private MnemonicHandler() {} /** - * Gets the state of the hide mnemonic flag. This only has meaning if this feature is supported by the underlying OS. + * Gets the state of the hide mnemonic flag. + * This only has meaning if this feature is supported by the underlying OS. * * @return true if mnemonics are hidden, otherwise, false - * @see #setMnemonicHidden - * @since 1.4 */ public static boolean isMnemonicHidden() { if (UIManager.getBoolean("Button.showMnemonics")) { @@ -65,34 +53,27 @@ public static boolean isMnemonicHidden() { return isMnemonicHidden; } - static class AltProcessor implements KeyEventPostProcessor { - public boolean postProcessKeyEvent(final KeyEvent ev) { - if (ev.getKeyCode() != KeyEvent.VK_ALT) { - return false; - } - - final JRootPane root = SwingUtilities.getRootPane(ev.getComponent()); - final Window winAncestor = (root == null ? null : SwingUtilities.getWindowAncestor(root)); - - switch(ev.getID()) { - case KeyEvent.KEY_PRESSED: - setMnemonicHidden(false); - break; - case KeyEvent.KEY_RELEASED: - setMnemonicHidden(true); - break; - } - - repaintMnemonicsInWindow(winAncestor); - - return false; + /** + * Sets the state of the hide mnemonic flag. This flag is used by the + * component UI delegates to determine if the mnemonic should be rendered. + * This method is a non operation if the underlying operating system + * does not support the mnemonic hiding feature. + * + * @param hide true if mnemonics should be hidden + */ + public static void setMnemonicHidden(final boolean hide) { + if (UIManager.getBoolean("Button.showMnemonics")) { + // Do not hide mnemonics if the UI defaults do not support this + isMnemonicHidden = false; + } else { + isMnemonicHidden = hide; } } - /* + /** * Repaints all the components with the mnemonics in the given window and all its owned windows. */ - static void repaintMnemonicsInWindow(final Window w) { + public static void repaintMnemonicsInWindow(final Window w) { if (w == null || !w.isShowing()) { return; } @@ -105,29 +86,22 @@ static void repaintMnemonicsInWindow(final Window w) { repaintMnemonicsInContainer(w); } - /* + /** * Repaints all the components with the mnemonics in container. * Recursively searches for all the subcomponents. */ - static void repaintMnemonicsInContainer(final Container cont) { - for (int i = 0; i < cont.getComponentCount(); i++) { - final Component c = cont.getComponent(i); + private static void repaintMnemonicsInContainer(final Container cont) { + final Component[] elements = cont.getComponents(); + for (final Component c : elements) { if (c == null || !c.isVisible()) { continue; } - if (c instanceof AbstractButton && ((AbstractButton)c).getMnemonic() != '\0') { - c.repaint(); - continue; - } - - if (c instanceof JLabel && ((JLabel)c).getDisplayedMnemonic() != '\0') { + if ((c instanceof AbstractButton b && b.getMnemonic() != '\0') + || (c instanceof JLabel l && l.getDisplayedMnemonic() != '\0')) { c.repaint(); - continue; - } - - if (c instanceof Container) { - repaintMnemonicsInContainer((Container)c); + } else if (c instanceof Container) { + repaintMnemonicsInContainer((Container) c); } } } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java index ff38130f728e5..cb4b5caa86de9 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsGraphicsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,31 @@ package com.sun.java.swing.plaf.windows; -import sun.swing.SwingUtilities2; - -import java.awt.*; - -import javax.swing.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JRadioButton; +import javax.swing.JToggleButton; +import javax.swing.UIManager; import javax.swing.plaf.UIResource; -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import sun.swing.MnemonicHandler; +import sun.swing.SwingUtilities2; + +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.Prop; +import static com.sun.java.swing.plaf.windows.TMSchema.State; +import static com.sun.java.swing.plaf.windows.TMSchema.TypeEnum; /** * A collection of static utility methods used for rendering the Windows look @@ -60,7 +77,7 @@ public static void paintText(Graphics g, AbstractButton b, int mnemIndex = b.getDisplayedMnemonicIndex(); // W2K Feature: Check to see if the Underscore should be rendered. - if (WindowsLookAndFeel.isMnemonicHidden() == true) { + if (MnemonicHandler.isMnemonicHidden()) { mnemIndex = -1; } @@ -191,46 +208,4 @@ static boolean isLeftToRight(Component c) { return c.getComponentOrientation().isLeftToRight(); } - /* - * Repaints all the components with the mnemonics in the given window and - * all its owned windows. - */ - static void repaintMnemonicsInWindow(Window w) { - if(w == null || !w.isShowing()) { - return; - } - - Window[] ownedWindows = w.getOwnedWindows(); - for(int i=0;i