From c203e7093e9b8c52cdf4ae249ab27d16d6a2c623 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 26 Aug 2025 18:37:22 +0000 Subject: [PATCH 001/295] 8366037: Remove oopDesc::mark_addr() Reviewed-by: shade, stefank, tschatzl --- src/hotspot/share/gc/g1/g1OopClosures.inline.hpp | 6 +++--- .../share/gc/parallel/psPromotionManager.inline.hpp | 4 ++-- src/hotspot/share/oops/oop.hpp | 4 +++- src/hotspot/share/oops/oop.inline.hpp | 7 +++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 8d84f144f02..c0c67fda949 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +50,8 @@ inline void G1ScanClosureBase::prefetch_and_push(T* p, const oop obj) { // stall. We'll try to prefetch the object (for write, given that // we might need to install the forwarding reference) and we'll // get back to it when pop it from the queue - Prefetch::write(obj->mark_addr(), 0); - Prefetch::read(obj->mark_addr(), (HeapWordSize*2)); + Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); + Prefetch::read(obj->base_addr(), oopDesc::mark_offset_in_bytes() + (HeapWordSize*2)); // slightly paranoid test; I'm trying to catch potential // problems before we go into push_on_queue to know where the diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 4946b0fde82..451a7dae189 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ inline void PSPromotionManager::claim_or_forward_depth(T* p) { if (PSScavenge::is_obj_in_young(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(!PSScavenge::is_obj_in_to_space(obj), "revisiting object?"); - Prefetch::write(obj->mark_addr(), 0); + Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); push_depth(ScannerTask(p)); } } diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 02f87da2937..3ec0ce5764a 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -65,9 +65,11 @@ class oopDesc { // Must be trivial; see verifying static assert after the class. oopDesc() = default; + inline void* base_addr(); + inline const void* base_addr() const; + inline markWord mark() const; inline markWord mark_acquire() const; - inline markWord* mark_addr() const; inline void set_mark(markWord m); static inline void set_mark(HeapWord* mem, markWord m); diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 4ca1bfce472..16c444a43f8 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -47,6 +47,9 @@ // Implementation of all inlined member functions defined in oop.hpp // We need a separate file to avoid circular references +void* oopDesc::base_addr() { return this; } +const void* oopDesc::base_addr() const { return this; } + markWord oopDesc::mark() const { return Atomic::load(&_mark); } @@ -55,10 +58,6 @@ markWord oopDesc::mark_acquire() const { return Atomic::load_acquire(&_mark); } -markWord* oopDesc::mark_addr() const { - return (markWord*) &_mark; -} - void oopDesc::set_mark(markWord m) { Atomic::store(&_mark, m); } From c75534517729b903b63263cf64dc2ff841e3dcb1 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 26 Aug 2025 18:54:16 +0000 Subject: [PATCH 002/295] 8365197: javax.imageio.stream MemoryCache based streams no longer need a disposer. Reviewed-by: psadhukhan, jdv, serb --- .../stream/MemoryCacheImageInputStream.java | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java index 1799254c59a..0630e19e98c 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -27,8 +27,6 @@ package javax.imageio.stream; import java.io.InputStream; import java.io.IOException; -import sun.java2d.Disposer; -import sun.java2d.DisposerRecord; /** * An implementation of {@code ImageInputStream} that gets its @@ -48,12 +46,6 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { private MemoryCache cache = new MemoryCache(); - /** The referent to be registered with the Disposer. */ - private final Object disposerReferent = new Object(); - - /** The DisposerRecord that resets the underlying MemoryCache. */ - private final DisposerRecord disposerRecord; - /** * Constructs a {@code MemoryCacheImageInputStream} that will read * from a given {@code InputStream}. @@ -68,9 +60,6 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { throw new IllegalArgumentException("stream == null!"); } this.stream = stream; - - disposerRecord = new StreamDisposerRecord(cache); - Disposer.addRecord(disposerReferent, disposerRecord); } public int read() throws IOException { @@ -165,23 +154,8 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { */ public void close() throws IOException { super.close(); - disposerRecord.dispose(); // this resets the MemoryCache stream = null; + cache.reset(); cache = null; } - - private static class StreamDisposerRecord implements DisposerRecord { - private MemoryCache cache; - - public StreamDisposerRecord(MemoryCache cache) { - this.cache = cache; - } - - public synchronized void dispose() { - if (cache != null) { - cache.reset(); - cache = null; - } - } - } } From b426151a33158637eb04c07a5133d95cbb8bf04c Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 26 Aug 2025 20:54:27 +0000 Subject: [PATCH 003/295] 8365885: Clean up constant pool reflection native code Reviewed-by: iklam, alanb --- src/hotspot/share/include/jvm.h | 36 ++++----- src/hotspot/share/prims/jvm.cpp | 36 ++++----- .../jdk/internal/reflect/ConstantPool.java | 78 ++++++++++--------- .../share/native/libjava/ConstantPool.c | 74 +++++++++--------- .../constantPool/ConstantPoolTest.java | 33 +++++--- .../constantPool/ConstantPoolTestDummy.jasm | 8 +- 6 files changed, 140 insertions(+), 125 deletions(-) diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 4d39537e5a1..2f0958bcac4 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -644,58 +644,58 @@ JNIEXPORT jobject JNICALL JVM_GetClassConstantPool(JNIEnv *env, jclass cls); JNIEXPORT jint JNICALL JVM_ConstantPoolGetSize -(JNIEnv *env, jobject unused, jobject jcpool); +(JNIEnv *env, jobject jcpool); JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAtIfLoaded -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jint JNICALL JVM_ConstantPoolGetClassRefIndexAt -(JNIEnv *env, jobject obj, jobject unused, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAtIfLoaded -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAtIfLoaded -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetMemberRefInfoAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jint JNICALL JVM_ConstantPoolGetNameAndTypeRefIndexAt -(JNIEnv *env, jobject obj, jobject unused, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetNameAndTypeRefInfoAt -(JNIEnv *env, jobject obj, jobject unused, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jint JNICALL JVM_ConstantPoolGetIntAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jlong JNICALL JVM_ConstantPoolGetLongAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jfloat JNICALL JVM_ConstantPoolGetFloatAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jdouble JNICALL JVM_ConstantPoolGetDoubleAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jstring JNICALL JVM_ConstantPoolGetStringAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jstring JNICALL JVM_ConstantPoolGetUTF8At -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jbyte JNICALL JVM_ConstantPoolGetTagAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); /* * Parameter reflection diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 098bd729c0b..abec3bc59b6 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1927,7 +1927,7 @@ JVM_ENTRY(jobject, JVM_GetClassConstantPool(JNIEnv *env, jclass cls)) JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj, jobject unused)) +JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); return cp->length(); @@ -1935,7 +1935,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj, jobject unused JVM_END -JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); @@ -1948,7 +1948,7 @@ JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject u } JVM_END -JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); @@ -1992,7 +1992,7 @@ static jobject get_method_at_helper(const constantPoolHandle& cp, jint index, bo return JNIHandles::make_local(THREAD, method); } -JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2002,7 +2002,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAtIfLoaded(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2037,7 +2037,7 @@ static jobject get_field_at_helper(constantPoolHandle cp, jint index, bool force return JNIHandles::make_local(THREAD, field); } -JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jobject unusedl, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2047,7 +2047,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2057,7 +2057,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, } JVM_END -JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2082,7 +2082,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject } JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2095,7 +2095,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, job } JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2108,7 +2108,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject ob } JVM_END -JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2129,7 +2129,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, job } JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); @@ -2141,7 +2141,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jobject unuse } JVM_END -JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0L)); @@ -2153,7 +2153,7 @@ JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jobject unu } JVM_END -JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0.0f)); @@ -2165,7 +2165,7 @@ JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jobject u } JVM_END -JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0.0)); @@ -2177,7 +2177,7 @@ JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); @@ -2190,7 +2190,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2205,7 +2205,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jobject u } JVM_END -JVM_ENTRY(jbyte, JVM_ConstantPoolGetTagAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jbyte, JVM_ConstantPoolGetTagAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); diff --git a/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java b/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java index a43034126e4..d56ecff5e36 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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,41 +34,41 @@ import java.util.Set; public class ConstantPool { // Number of entries in this constant pool (= maximum valid constant pool index) - public int getSize() { return getSize0 (constantPoolOop); } - public Class getClassAt (int index) { return getClassAt0 (constantPoolOop, index); } - public Class getClassAtIfLoaded (int index) { return getClassAtIfLoaded0 (constantPoolOop, index); } + public int getSize() { return getSize0 (); } + public Class getClassAt (int index) { return getClassAt0 (index); } + public Class getClassAtIfLoaded (int index) { return getClassAtIfLoaded0 (index); } // Returns a class reference index for a method or a field. public int getClassRefIndexAt(int index) { - return getClassRefIndexAt0(constantPoolOop, index); + return getClassRefIndexAt0(index); } // Returns either a Method or Constructor. // Static initializers are returned as Method objects. - public Member getMethodAt (int index) { return getMethodAt0 (constantPoolOop, index); } - public Member getMethodAtIfLoaded(int index) { return getMethodAtIfLoaded0(constantPoolOop, index); } - public Field getFieldAt (int index) { return getFieldAt0 (constantPoolOop, index); } - public Field getFieldAtIfLoaded (int index) { return getFieldAtIfLoaded0 (constantPoolOop, index); } + public Member getMethodAt (int index) { return getMethodAt0 (index); } + public Member getMethodAtIfLoaded(int index) { return getMethodAtIfLoaded0(index); } + public Field getFieldAt (int index) { return getFieldAt0 (index); } + public Field getFieldAtIfLoaded (int index) { return getFieldAtIfLoaded0 (index); } // Fetches the class name, member (field, method or interface // method) name, and type descriptor as an array of three Strings - public String[] getMemberRefInfoAt (int index) { return getMemberRefInfoAt0 (constantPoolOop, index); } + public String[] getMemberRefInfoAt (int index) { return getMemberRefInfoAt0 (index); } // Returns a name and type reference index for a method, a field or an invokedynamic. public int getNameAndTypeRefIndexAt(int index) { - return getNameAndTypeRefIndexAt0(constantPoolOop, index); + return getNameAndTypeRefIndexAt0(index); } // Fetches the name and type from name_and_type index as an array of two Strings public String[] getNameAndTypeRefInfoAt(int index) { - return getNameAndTypeRefInfoAt0(constantPoolOop, index); + return getNameAndTypeRefInfoAt0(index); } - public int getIntAt (int index) { return getIntAt0 (constantPoolOop, index); } - public long getLongAt (int index) { return getLongAt0 (constantPoolOop, index); } - public float getFloatAt (int index) { return getFloatAt0 (constantPoolOop, index); } - public double getDoubleAt (int index) { return getDoubleAt0 (constantPoolOop, index); } - public String getStringAt (int index) { return getStringAt0 (constantPoolOop, index); } - public String getUTF8At (int index) { return getUTF8At0 (constantPoolOop, index); } + public int getIntAt (int index) { return getIntAt0 (index); } + public long getLongAt (int index) { return getLongAt0 (index); } + public float getFloatAt (int index) { return getFloatAt0 (index); } + public double getDoubleAt (int index) { return getDoubleAt0 (index); } + public String getStringAt (int index) { return getStringAt0 (index); } + public String getUTF8At (int index) { return getUTF8At0 (index); } public Tag getTagAt(int index) { - return Tag.valueOf(getTagAt0(constantPoolOop, index)); + return Tag.valueOf(getTagAt0(index)); } - public static enum Tag { + public enum Tag { UTF8(1), INTEGER(3), FLOAT(4), @@ -82,7 +82,9 @@ public class ConstantPool { NAMEANDTYPE(12), METHODHANDLE(15), METHODTYPE(16), + DYNAMIC(17), INVOKEDYNAMIC(18), + // For index after long/double and 0 INVALID(0); private final int tagCode; @@ -111,22 +113,22 @@ public class ConstantPool { // HotSpot-internal constant pool object (set by the VM, name known to the VM) private Object constantPoolOop; - private native int getSize0 (Object constantPoolOop); - private native Class getClassAt0 (Object constantPoolOop, int index); - private native Class getClassAtIfLoaded0 (Object constantPoolOop, int index); - private native int getClassRefIndexAt0 (Object constantPoolOop, int index); - private native Member getMethodAt0 (Object constantPoolOop, int index); - private native Member getMethodAtIfLoaded0(Object constantPoolOop, int index); - private native Field getFieldAt0 (Object constantPoolOop, int index); - private native Field getFieldAtIfLoaded0 (Object constantPoolOop, int index); - private native String[] getMemberRefInfoAt0 (Object constantPoolOop, int index); - private native int getNameAndTypeRefIndexAt0(Object constantPoolOop, int index); - private native String[] getNameAndTypeRefInfoAt0(Object constantPoolOop, int index); - private native int getIntAt0 (Object constantPoolOop, int index); - private native long getLongAt0 (Object constantPoolOop, int index); - private native float getFloatAt0 (Object constantPoolOop, int index); - private native double getDoubleAt0 (Object constantPoolOop, int index); - private native String getStringAt0 (Object constantPoolOop, int index); - private native String getUTF8At0 (Object constantPoolOop, int index); - private native byte getTagAt0 (Object constantPoolOop, int index); + private native int getSize0 (); + private native Class getClassAt0 (int index); + private native Class getClassAtIfLoaded0 (int index); + private native int getClassRefIndexAt0 (int index); + private native Member getMethodAt0 (int index); + private native Member getMethodAtIfLoaded0(int index); + private native Field getFieldAt0 (int index); + private native Field getFieldAtIfLoaded0 (int index); + private native String[] getMemberRefInfoAt0 (int index); + private native int getNameAndTypeRefIndexAt0(int index); + private native String[] getNameAndTypeRefInfoAt0(int index); + private native int getIntAt0 (int index); + private native long getLongAt0 (int index); + private native float getFloatAt0 (int index); + private native double getDoubleAt0 (int index); + private native String getStringAt0 (int index); + private native String getUTF8At0 (int index); + private native byte getTagAt0 (int index); } diff --git a/src/java.base/share/native/libjava/ConstantPool.c b/src/java.base/share/native/libjava/ConstantPool.c index 3fb7b74e518..2fea25c728a 100644 --- a/src/java.base/share/native/libjava/ConstantPool.c +++ b/src/java.base/share/native/libjava/ConstantPool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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,110 +27,110 @@ #include "jdk_internal_reflect_ConstantPool.h" JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getSize0 -(JNIEnv *env, jobject unused, jobject jcpool) +(JNIEnv *env, jobject jcpool) { - return JVM_ConstantPoolGetSize(env, unused, jcpool); + return JVM_ConstantPoolGetSize(env, jcpool); } JNIEXPORT jclass JNICALL Java_jdk_internal_reflect_ConstantPool_getClassAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetClassAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetClassAt(env, jcpool, index); } JNIEXPORT jclass JNICALL Java_jdk_internal_reflect_ConstantPool_getClassAtIfLoaded0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetClassAtIfLoaded(env, unused, jcpool, index); + return JVM_ConstantPoolGetClassAtIfLoaded(env, jcpool, index); } JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getClassRefIndexAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetClassRefIndexAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetClassRefIndexAt(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getMethodAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetMethodAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetMethodAt(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getMethodAtIfLoaded0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetMethodAtIfLoaded(env, unused, jcpool, index); + return JVM_ConstantPoolGetMethodAtIfLoaded(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getFieldAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetFieldAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetFieldAt(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getFieldAtIfLoaded0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetFieldAtIfLoaded(env, unused, jcpool, index); + return JVM_ConstantPoolGetFieldAtIfLoaded(env, jcpool, index); } JNIEXPORT jobjectArray JNICALL Java_jdk_internal_reflect_ConstantPool_getMemberRefInfoAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetMemberRefInfoAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetMemberRefInfoAt(env, jcpool, index); } JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefIndexAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetNameAndTypeRefIndexAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetNameAndTypeRefIndexAt(env, jcpool, index); } JNIEXPORT jobjectArray JNICALL Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefInfoAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetNameAndTypeRefInfoAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetNameAndTypeRefInfoAt(env, jcpool, index); } JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getIntAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetIntAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetIntAt(env, jcpool, index); } JNIEXPORT jlong JNICALL Java_jdk_internal_reflect_ConstantPool_getLongAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetLongAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetLongAt(env, jcpool, index); } JNIEXPORT jfloat JNICALL Java_jdk_internal_reflect_ConstantPool_getFloatAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetFloatAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetFloatAt(env, jcpool, index); } JNIEXPORT jdouble JNICALL Java_jdk_internal_reflect_ConstantPool_getDoubleAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetDoubleAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetDoubleAt(env, jcpool, index); } JNIEXPORT jstring JNICALL Java_jdk_internal_reflect_ConstantPool_getStringAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetStringAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetStringAt(env, jcpool, index); } JNIEXPORT jstring JNICALL Java_jdk_internal_reflect_ConstantPool_getUTF8At0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetUTF8At(env, unused, jcpool, index); + return JVM_ConstantPoolGetUTF8At(env, jcpool, index); } JNIEXPORT jbyte JNICALL Java_jdk_internal_reflect_ConstantPool_getTagAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetTagAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetTagAt(env, jcpool, index); } diff --git a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java index 903a08e56df..f53b6cf0032 100644 --- a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java +++ b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +29,21 @@ * java.base/jdk.internal.reflect * @library /test/lib * @compile ConstantPoolTestDummy.jasm - * @run main jdk.internal.reflect.constantPool.ConstantPoolTest + * @compile ConstantPoolTest.java + * @run junit ConstantPoolTest */ -package jdk.internal.reflect.constantPool; - +import java.lang.classfile.ClassFile; import java.util.HashMap; import java.util.Map; import jdk.internal.access.SharedSecrets; import jdk.internal.reflect.ConstantPool; import jdk.test.lib.Asserts; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ConstantPoolTest { @@ -46,13 +51,23 @@ public class ConstantPoolTest { private static final ConstantPool CP = SharedSecrets.getJavaLangAccess() .getConstantPool(TEST_CLASS); - public static void main(String[] s) { - for (TestCase testCase : TestCase.values()) { - testCase.test(); - } + @ParameterizedTest + @EnumSource(TestCase.class) + void runTestCases(TestCase testCase) { + testCase.test(); } - public static enum TestCase { + @Test + void testSize() throws Throwable { + byte[] data; + try (var in = ConstantPoolTest.class.getResourceAsStream("/ConstantPoolTestDummy.class")) { + data = in.readAllBytes(); + } + var testClass = ClassFile.of().parse(data); + assertEquals(testClass.constantPool().size(), CP.getSize()); + } + + public enum TestCase { GET_TAG_AT { { referenceMap.put(1, ConstantPool.Tag.METHODREF); diff --git a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm index 3884f1644ff..03934b930e0 100644 --- a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm +++ b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +21,6 @@ * questions. */ -package jdk/internal/reflect/constantPool; - super public #2; //class ConstantPoolTestDummy version 52:0 { @@ -41,7 +39,7 @@ const #7 = Asciz "LineNumberTable"; const #8 = Asciz "SourceFile"; const #9 = Asciz "ConstantPoolTestDummy.java"; const #10 = NameAndType #4:#5; // "":"()V" -const #11 = Asciz "jdk/internal/reflect/constantPool/ConstantPoolTestDummy"; +const #11 = Asciz "ConstantPoolTestDummy"; const #12 = Asciz "java/lang/Object"; const #13 = long 6l; const #15 = int 1; @@ -76,7 +74,7 @@ const #44 = Asciz "Lookup"; const #45 = class #47; // java/lang/invoke/MethodHandles const #46 = Asciz "java/lang/invoke/MethodHandles$Lookup"; const #47 = Asciz "java/lang/invoke/MethodHandles"; -const #48 = Field #2.#49; // jdk/internal/reflect/constantPool/ConstantPoolTestDummy.myField:"I" +const #48 = Field #2.#49; // ConstantPoolTestDummy.myField:"I" const #49 = NameAndType #50:#51; // myField:"I" const #50 = Asciz "myField"; const #51 = Asciz "I"; From 23670fd41895ccc38931f836d218ff7392a6065a Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 26 Aug 2025 21:49:57 +0000 Subject: [PATCH 004/295] 8363972: Lenient parsing of minus sign pattern in DecimalFormat/CompactNumberFormat Reviewed-by: jlu, rriggs --- .../build/tools/cldrconverter/Bundle.java | 1 + .../tools/cldrconverter/LDMLParseHandler.java | 28 ++ .../java/text/CompactNumberFormat.java | 24 +- .../classes/java/text/DecimalFormat.java | 71 ++++- .../java/text/DecimalFormatSymbols.java | 54 +++- .../share/classes/java/text/NumberFormat.java | 6 +- .../TestCompactNumber.java | 9 +- .../NumberFormat/LenientMinusSignTest.java | 251 ++++++++++++++++++ 8 files changed, 406 insertions(+), 38 deletions(-) create mode 100644 test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index cbef22d91c0..c4aaa28193a 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java @@ -79,6 +79,7 @@ class Bundle { "NumberElements/nan", "NumberElements/currencyDecimal", "NumberElements/currencyGroup", + "NumberElements/lenientMinusSigns", }; private static final String[] TIME_PATTERN_KEYS = { diff --git a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index 6d5dde0d181..98c0605f8b7 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java @@ -844,6 +844,26 @@ class LDMLParseHandler extends AbstractLDMLHandler { }); break; + // Lenient parsing + case "parseLenients": + if ("lenient".equals(attributes.getValue("level"))) { + pushKeyContainer(qName, attributes, attributes.getValue("scope")); + } else { + pushIgnoredContainer(qName); + } + break; + + case "parseLenient": + // Use only the lenient minus sign for now + if (currentContainer instanceof KeyContainer kc + && kc.getKey().equals("number") + && attributes.getValue("sample").equals("-")) { + pushStringEntry(qName, attributes, currentNumberingSystem + "NumberElements/lenientMinusSigns"); + } else { + pushIgnoredContainer(qName); + } + break; + default: // treat anything else as a container pushContainer(qName, attributes); @@ -1150,6 +1170,14 @@ class LDMLParseHandler extends AbstractLDMLHandler { currentStyle = ""; putIfEntry(); break; + case "parseLenient": + if (currentContainer instanceof StringEntry se) { + // Convert to a simple concatenation of lenient minuses + // e.g. "[\--﹣ ‐‑ ‒ – −⁻₋ ➖]" -> "--﹣‐‑‒–−⁻₋➖" for the root locale + put(se.getKey(), se.getValue().replaceAll("[\\[\\]\\\\ ]", "")); + } + break; + default: putIfEntry(); } diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index fae11cbdba1..7163b2dd63b 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -147,7 +147,7 @@ import java.util.stream.Collectors; * a compact pattern. This special pattern can appear explicitly for any specific * range, or considered as a default pattern for an empty string. * - *

Negative Subpatterns

+ *

Negative Subpatterns

* A compact pattern contains a positive and negative subpattern * separated by a subpattern boundary character {@code ';'}, * for example, {@code "0K;-0K"}. Each subpattern has a prefix, @@ -159,7 +159,10 @@ import java.util.stream.Collectors; * the negative prefix and suffix. The number of minimum integer digits, * and other characteristics are all the same as the positive pattern. * That means that {@code "0K;-00K"} produces precisely the same behavior - * as {@code "0K;-0K"}. + * as {@code "0K;-0K"}. In {@link NumberFormat##leniency lenient parsing} + * mode, loose matching of the minus sign pattern is enabled, following the + * LDML’s + * loose matching specification. * *

Escaping Special Characters

* Many characters in a compact pattern are taken literally, they are matched @@ -1585,6 +1588,9 @@ public final class CompactNumberFormat extends NumberFormat { * and are not digits that occur within the numerical portion * *

+ * When lenient, the minus sign in the {@link ##negative_subpatterns + * negative subpatterns} is loosely matched against lenient minus sign characters. + *

* The subclass returned depends on the value of * {@link #isParseBigDecimal}. *

    @@ -1693,14 +1699,12 @@ public final class CompactNumberFormat extends NumberFormat { // Given text does not match the non empty valid compact prefixes // check with the default prefixes if (!gotPositive && !gotNegative) { - if (text.regionMatches(pos.index, defaultPosPrefix, 0, - defaultPosPrefix.length())) { + if (decimalFormat.matchAffix(text, position, defaultPosPrefix)) { // Matches the default positive prefix matchedPosPrefix = defaultPosPrefix; gotPositive = true; } - if (text.regionMatches(pos.index, defaultNegPrefix, 0, - defaultNegPrefix.length())) { + if (decimalFormat.matchAffix(text, position, defaultNegPrefix)) { // Matches the default negative prefix matchedNegPrefix = defaultNegPrefix; gotNegative = true; @@ -1924,7 +1928,7 @@ public final class CompactNumberFormat extends NumberFormat { if (!affix.isEmpty() && !affix.equals(defaultAffix)) { // Look ahead only for the longer match than the previous match if (matchedAffix.length() < affix.length()) { - return text.regionMatches(position, affix, 0, affix.length()); + return decimalFormat.matchAffix(text, position, affix); } } return false; @@ -2026,8 +2030,7 @@ public final class CompactNumberFormat extends NumberFormat { if (!gotPos && !gotNeg) { String positiveSuffix = defaultDecimalFormat.getPositiveSuffix(); String negativeSuffix = defaultDecimalFormat.getNegativeSuffix(); - boolean containsPosSuffix = text.regionMatches(position, - positiveSuffix, 0, positiveSuffix.length()); + boolean containsPosSuffix = decimalFormat.matchAffix(text, position, positiveSuffix); boolean endsWithPosSuffix = containsPosSuffix && text.length() == position + positiveSuffix.length(); if (parseStrict ? endsWithPosSuffix : containsPosSuffix) { @@ -2035,8 +2038,7 @@ public final class CompactNumberFormat extends NumberFormat { matchedPosSuffix = positiveSuffix; gotPos = true; } - boolean containsNegSuffix = text.regionMatches(position, - negativeSuffix, 0, negativeSuffix.length()); + boolean containsNegSuffix = decimalFormat.matchAffix(text, position, negativeSuffix); boolean endsWithNegSuffix = containsNegSuffix && text.length() == position + negativeSuffix.length(); if (parseStrict ? endsWithNegSuffix : containsNegSuffix) { diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 50bb1e01336..aa881aecc8a 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -296,7 +296,7 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * #setMaximumIntegerDigits(int)} can be used to manually adjust the maximum * integer digits. * - *

    Negative Subpatterns

    + *

    Negative Subpatterns

    * A {@code DecimalFormat} pattern contains a positive and negative * subpattern, for example, {@code "#,##0.00;(#,##0.00)"}. Each * subpattern has a prefix, numeric part, and suffix. The negative subpattern @@ -307,7 +307,11 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * serves only to specify the negative prefix and suffix; the number of digits, * minimal digits, and other characteristics are all the same as the positive * pattern. That means that {@code "#,##0.0#;(#)"} produces precisely - * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}. + * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}. In + * {@link NumberFormat##leniency lenient parsing} mode, loose matching of the + * minus sign pattern is enabled, following the LDML’s + * + * loose matching specification. * *

    The prefixes, suffixes, and various symbols used for infinity, digits, * grouping separators, decimal separators, etc. may be set to arbitrary @@ -2189,6 +2193,9 @@ public class DecimalFormat extends NumberFormat { * and are not digits that occur within the numerical portion *

*

+ * When lenient, the minus sign in the {@link ##negative_subpatterns + * negative subpatterns} is loosely matched against lenient minus sign characters. + *

* The subclass returned depends on the value of {@link #isParseBigDecimal} * as well as on the string being parsed. *

    @@ -2385,10 +2392,8 @@ public class DecimalFormat extends NumberFormat { boolean gotPositive, gotNegative; // check for positivePrefix; take longest - gotPositive = text.regionMatches(position, positivePrefix, 0, - positivePrefix.length()); - gotNegative = text.regionMatches(position, negativePrefix, 0, - negativePrefix.length()); + gotPositive = matchAffix(text, position, positivePrefix); + gotNegative = matchAffix(text, position, negativePrefix); if (gotPositive && gotNegative) { if (positivePrefix.length() > negativePrefix.length()) { @@ -2424,15 +2429,13 @@ public class DecimalFormat extends NumberFormat { // When lenient, text only needs to contain the suffix. if (!isExponent) { if (gotPositive) { - boolean containsPosSuffix = - text.regionMatches(position, positiveSuffix, 0, positiveSuffix.length()); + boolean containsPosSuffix = matchAffix(text, position, positiveSuffix); boolean endsWithPosSuffix = containsPosSuffix && text.length() == position + positiveSuffix.length(); gotPositive = parseStrict ? endsWithPosSuffix : containsPosSuffix; } if (gotNegative) { - boolean containsNegSuffix = - text.regionMatches(position, negativeSuffix, 0, negativeSuffix.length()); + boolean containsNegSuffix = matchAffix(text, position, negativeSuffix); boolean endsWithNegSuffix = containsNegSuffix && text.length() == position + negativeSuffix.length(); gotNegative = parseStrict ? endsWithNegSuffix : containsNegSuffix; @@ -3501,6 +3504,54 @@ public class DecimalFormat extends NumberFormat { if (needQuote) buffer.append('\''); } + /** + * {@return true if the text matches the affix} + * In lenient mode, lenient minus signs also match the hyphen-minus + * (U+002D). Package-private access, as this is called from + * CompactNumberFormat. + * + * Note: Minus signs in the supplementary character range or normalization + * equivalents are not matched, as they may alter the affix length. + */ + boolean matchAffix(String text, int position, String affix) { + var alen = affix.length(); + var tlen = text.length(); + + if (alen == 0) { + // always match with an empty affix, as affix is optional + return true; + } + if (position >= tlen) { + return false; + } + if (parseStrict) { + return text.regionMatches(position, affix, 0, alen); + } + + var lms = symbols.getLenientMinusSigns(); + int i = 0; + int limit = Math.min(tlen, position + alen); + for (; position + i < limit; i++) { + char t = text.charAt(position + i); + char a = affix.charAt(i); + int tIndex = lms.indexOf(t); + int aIndex = lms.indexOf(a); + // Non LMS. Match direct + if (tIndex < 0 && aIndex < 0) { + if (t != a) { + return false; + } + } else { + // By here, at least one LMS. Ensure both LMS. + if (tIndex < 0 || aIndex < 0) { + return false; + } + } + } + // Return true if entire affix was matched + return i == alen; + } + /** * Implementation of producing a pattern. This method returns a positive and * negative (if needed), pattern string in the form of : Prefix (optional) diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index da20af60662..dfb344f26a7 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -718,6 +718,17 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { this.minusSign = findNonFormatChar(minusSignText, '-'); } + /** + * {@return the lenient minus signs} Multiple lenient minus signs + * are concatenated to form the returned string. Each codepoint + * in the string is a valid minus sign pattern. If there are no + * lenient minus signs defined in this locale, {@code minusSignText} + * is returned. + */ + String getLenientMinusSigns() { + return lenientMinusSigns; + } + //------------------------------------------------------------ // END Package Private methods ... to be made public later //------------------------------------------------------------ @@ -818,18 +829,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { private void initialize(Locale locale) { this.locale = locale; - // check for region override - Locale override = locale.getUnicodeLocaleType("nu") == null ? - CalendarDataUtility.findRegionOverride(locale) : - locale; - - // get resource bundle data - LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override); - // Avoid potential recursions - if (!(adapter instanceof ResourceBundleBasedAdapter)) { - adapter = LocaleProviderAdapter.getResourceBundleBased(); - } - Object[] data = adapter.getLocaleResources(override).getDecimalFormatSymbolsData(); + Object[] data = loadNumberData(locale); String[] numberElements = (String[]) data[0]; decimalSeparator = numberElements[0].charAt(0); @@ -854,11 +854,30 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { monetaryGroupingSeparator = numberElements.length < 13 || numberElements[12].isEmpty() ? groupingSeparator : numberElements[12].charAt(0); + // Lenient minus signs + lenientMinusSigns = numberElements.length < 14 ? minusSignText : numberElements[13]; + // maybe filled with previously cached values, or null. intlCurrencySymbol = (String) data[1]; currencySymbol = (String) data[2]; } + private Object[] loadNumberData(Locale locale) { + // check for region override + Locale override = locale.getUnicodeLocaleType("nu") == null ? + CalendarDataUtility.findRegionOverride(locale) : + locale; + + // get resource bundle data + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override); + // Avoid potential recursions + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + + return adapter.getLocaleResources(override).getDecimalFormatSymbolsData(); + } + /** * Obtains non-format single character from String */ @@ -995,6 +1014,14 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { } currencyInitialized = true; } + + if (loadNumberData(locale) instanceof Object[] d && + d[0] instanceof String[] numberElements && + numberElements.length >= 14) { + lenientMinusSigns = numberElements[13]; + } else { + lenientMinusSigns = minusSignText; + } } /** @@ -1174,6 +1201,9 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { private transient Currency currency; private transient volatile boolean currencyInitialized; + // Lenient minus. No need to be set by applications + private transient String lenientMinusSigns; + /** * Cached hash code. */ diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 0f4da56de0c..759ed7ae5ea 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -195,7 +195,11 @@ import sun.util.locale.provider.LocaleServiceProviderPool; * Lenient parsing should be used when attempting to parse a number * out of a String that contains non-numerical or non-format related values. * For example, using a {@link Locale#US} currency format to parse the number - * {@code 1000} out of the String "$1,000.00 was paid". + * {@code 1000} out of the String "$1,000.00 was paid". Lenient parsing also + * allows loose matching of characters in the source text. For example, an + * implementation of the {@code NumberFormat} class may allow matching "−" + * (U+2212 MINUS SIGN) to the "-" (U+002D HYPHEN-MINUS) pattern character + * when used as a negative prefix. *

    * Strict parsing should be used when attempting to ensure a String adheres exactly * to a locale's conventions, and can thus serve to validate input. For example, successfully diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java index 16de2247779..e9972f62f3e 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 + * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 8363972 * @summary Checks the functioning of compact number format * @modules jdk.localedata * @run testng/othervm TestCompactNumber @@ -462,6 +462,8 @@ public class TestCompactNumber { {FORMAT_SE_SHORT, "12345679,89\u00a0bn", 1.2345679890000001E19, Double.class}, {FORMAT_SE_SHORT, "\u2212999", -999L, Long.class}, {FORMAT_SE_SHORT, "\u22128\u00a0mn", -8000000L, Long.class}, + // lenient parsing. Hyphen-minus should match the localized minus sign + {FORMAT_SE_SHORT, "-8\u00a0mn", -8000000L, Long.class}, {FORMAT_SE_SHORT, "\u22128\u00a0dt", -8000L, Long.class}, {FORMAT_SE_SHORT, "\u221212345679\u00a0bn", -1.2345679E19, Double.class}, {FORMAT_SE_SHORT, "\u221212345679,89\u00a0bn", -1.2345679890000001E19, Double.class}, @@ -503,8 +505,7 @@ public class TestCompactNumber { {FORMAT_EN_US_SHORT, "K12,347", null}, // Invalid prefix for ja_JP {FORMAT_JA_JP_SHORT, "\u4E071", null}, - // Localized minus sign should be used - {FORMAT_SE_SHORT, "-8\u00a0mn", null},}; + }; } @DataProvider(name = "invalidParse") diff --git a/test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java b/test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java new file mode 100644 index 00000000000..251cac7c9cb --- /dev/null +++ b/test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8363972 + * @summary Unit tests for lenient minus parsing + * @modules jdk.localedata + * java.base/java.text:+open + * @run junit LenientMinusSignTest + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.invoke.MethodHandles; +import java.text.CompactNumberFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class LenientMinusSignTest { + private static final Locale FINNISH = Locale.of("fi"); + private static final DecimalFormatSymbols DFS = + new DecimalFormatSymbols(Locale.ROOT); + private static final String MINUS_PATTERN = "\u002D"; + + // "parseLenient" data from CLDR v47. These data are subject to change + private static Stream minus() { + return Stream.of( + MINUS_PATTERN, // "-" Hyphen-Minus + "\uFF0D", // "-" Fullwidth Hyphen-Minus + "\uFE63", // "﹣" Small Hyphen-Minus + "\u2010", // "‐" Hyphen + "\u2011", // "‑" Non-Breaking Hyphen + "\u2012", // "‒" Figure Dash + "\u2013", // "–" En Dash + "\u2212", // "−" Minus Sign + "\u207B", // "⁻" Superscript Minus + "\u208B", // "₋" Subscript Minus + "\u2796" // "➖" Heavy Minus Sign + ); + } + + @Test + void testFinnishMinus() throws ParseException { + // originally reported in JDK-8189097 + // Should not throw a ParseException + assertEquals(NumberFormat.getInstance(FINNISH).parse(MINUS_PATTERN + "1,5"), -1.5); + } + + @Test + void testFinnishMinusStrict() { + // Should throw a ParseException + var nf = NumberFormat.getInstance(FINNISH); + nf.setStrict(true); + assertThrows(ParseException.class, () -> nf.parse(MINUS_PATTERN + "1,5")); + } + + @Test + void testReadObject() throws IOException, ClassNotFoundException, ParseException { + // check if deserialized NF works with lenient minus. Using the Finnish example + var nf = NumberFormat.getInstance(FINNISH); + NumberFormat nfDeser; + byte[] serialized; + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos)) { + out.writeObject(nf); + out.flush(); + serialized = bos.toByteArray(); + } + try (ByteArrayInputStream bis = new ByteArrayInputStream(serialized); + ObjectInputStream in = new ObjectInputStream(bis)) { + nfDeser = (NumberFormat) in.readObject(); + } + assertEquals(nfDeser.parse(MINUS_PATTERN + "1,5"), -1.5); + } + + // White box test. modifies the private `lenientMinusSigns` field in the DFS + @Test + void testSupplementary() throws IllegalAccessException, NoSuchFieldException, ParseException { + var dfs = new DecimalFormatSymbols(Locale.ROOT); + MethodHandles.privateLookupIn(DecimalFormatSymbols.class, MethodHandles.lookup()) + .findVarHandle(DecimalFormatSymbols.class, "lenientMinusSigns", String.class) + .set(dfs, "-🙂"); + // Direct match. Should succeed + var df = new DecimalFormat("#.#;🙂#.#", dfs); + assertEquals(df.parse("🙂1.5"), -1.5); + + // Fail if the lengths of negative prefixes differ + assertThrows(ParseException.class, () -> df.parse("-1.5")); + var df2= new DecimalFormat("#.#;-#.#", dfs); + assertThrows(ParseException.class, () -> df2.parse("🙂1.5")); + } + + @Nested + class DecimalFormatTest { + private static final String PREFIX = "+#;-#"; + private static final String SUFFIX = "#+;#-"; + private static final String LONG_PREFIX = "pos#;-neg#"; + private static final String LONG_SUFFIX = "#pos;#neg-"; + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientPrefix(String sign) throws ParseException { + var df = new DecimalFormat(PREFIX, DFS); + df.setStrict(false); + assertEquals(MINUS_PATTERN + "1", df.format(df.parse(sign + "1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientSuffix(String sign) throws ParseException { + var df = new DecimalFormat(SUFFIX, DFS); + df.setStrict(false); + assertEquals("1" + MINUS_PATTERN, df.format(df.parse("1" + sign))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictPrefix(String sign) throws ParseException { + var df = new DecimalFormat(PREFIX, DFS); + df.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals(MINUS_PATTERN + "1", df.format(df.parse(sign + "1"))); + } else { + assertThrows(ParseException.class, () -> df.parse(sign + "1")); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictSuffix(String sign) throws ParseException { + var df = new DecimalFormat(SUFFIX, DFS); + df.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals("1" + MINUS_PATTERN, df.format(df.parse("1" + sign))); + } else { + assertThrows(ParseException.class, () -> df.parse("1" + sign)); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongPrefix(String sign) throws ParseException { + var df = new DecimalFormat(LONG_PREFIX, DFS); + assertEquals(MINUS_PATTERN + "neg1", df.format(df.parse(sign + "neg1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongSuffix(String sign) throws ParseException { + var df = new DecimalFormat(LONG_SUFFIX, DFS); + assertEquals("1neg" + MINUS_PATTERN, df.format(df.parse("1neg" + sign))); + } + } + + @Nested + class CompactNumberFormatTest { + private static final String[] PREFIX = {"+0;-0"}; + private static final String[] SUFFIX = {"0+;0-"}; + private static final String[] LONG_PREFIX = {"pos0;-neg0"}; + private static final String[] LONG_SUFFIX = {"0pos;0neg-"}; + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientPrefix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, PREFIX); + cnf.setStrict(false); + assertEquals(MINUS_PATTERN + "1", cnf.format(cnf.parse(sign + "1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientSuffix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, SUFFIX); + cnf.setStrict(false); + assertEquals("1" + MINUS_PATTERN, cnf.format(cnf.parse("1" + sign))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictPrefix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, PREFIX); + cnf.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals(MINUS_PATTERN + "1", cnf.format(cnf.parse(sign + "1"))); + } else { + assertThrows(ParseException.class, () -> cnf.parse(sign + "1")); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictSuffix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, SUFFIX); + cnf.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals("1" + MINUS_PATTERN, cnf.format(cnf.parse("1" + sign))); + } else { + assertThrows(ParseException.class, () -> cnf.parse("1" + sign)); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongPrefix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, LONG_PREFIX); + assertEquals(MINUS_PATTERN + "neg1", cnf.format(cnf.parse(sign + "neg1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongSuffix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, LONG_SUFFIX); + assertEquals("1neg" + MINUS_PATTERN, cnf.format(cnf.parse( "1neg" + sign))); + } + } +} From 69645fd4ba5c0a7e20727f5d85d87cefc40e8c70 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 26 Aug 2025 21:51:32 +0000 Subject: [PATCH 005/295] 8361972: Clarify the condition of System.console() about standard input/output Reviewed-by: smarks, jlu, joehw --- .../share/classes/java/io/Console.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 838334a0901..2878de79718 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -38,20 +38,20 @@ import sun.nio.cs.UTF_8; * Methods to access the character-based console device, if any, associated * with the current Java virtual machine. * - *

    Whether a virtual machine has a console is dependent upon the + *

    Whether a virtual machine's console exists is dependent upon the * underlying platform and also upon the manner in which the virtual * machine is invoked. If the virtual machine is started from an * interactive command line without redirecting the standard input and - * output streams then its console will exist and will typically be + * output streams, then its console will generally exist and will be * connected to the keyboard and display from which the virtual machine - * was launched. If the virtual machine is started automatically, for - * example by a background job scheduler, then it may not - * have a console. + * was launched. If the standard input or standard output have been + * redirected (for example, to a file or to a pipe), or if the virtual + * machine was started from a background job scheduler, the console + * will not exist. *

    - * If this virtual machine has a console then it is represented by a - * unique instance of this class which can be obtained by invoking the - * {@link java.lang.System#console()} method. If no console device is - * available then an invocation of that method will return {@code null}. + * If the console exists, then it is represented by a unique instance of this + * class which can be obtained by invoking the {@link System#console()} method. + * If the console does not exist, that method will return {@code null}. *

    * Read and write operations are synchronized to guarantee the atomic * completion of critical operations; therefore invoking methods @@ -535,18 +535,14 @@ public sealed class Console implements Flushable permits ProxyingConsole { /** * {@return {@code true} if the {@code Console} instance is a terminal} *

    - * This method returns {@code true} if the console device, associated with the current - * Java virtual machine, is a terminal, typically an interactive command line - * connected to a keyboard and display. - * - * @implNote The default implementation returns the value equivalent to calling - * {@code isatty(stdin/stdout)} on POSIX platforms, or whether standard in/out file - * descriptors are character devices or not on Windows. + * This method always returns {@code true}, since {@link System#console()} + * provides a {@code Console} instance only when both standard input and + * output are unredirected, that is, when running in an interactive terminal. * * @since 22 */ public boolean isTerminal() { - return istty; + return true; } private static UnsupportedOperationException newUnsupportedOperationException() { From 1ff73cb2ec41612d316921e852f29e7fa4dc9109 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 26 Aug 2025 21:51:53 +0000 Subject: [PATCH 006/295] 8364752: java.time.Instant should be able to parse ISO 8601 offsets of the form HH:mm:ss Reviewed-by: rriggs, vyazici, scolebourne --- .../java/time/format/DateTimeFormatter.java | 8 ++- .../time/format/DateTimeFormatterBuilder.java | 11 ++-- .../java/time/test/java/time/TestInstant.java | 61 ++++++++++++++++++- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 7127e277294..108f1e1eef8 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1199,8 +1199,10 @@ public final class DateTimeFormatter { * When formatting, the instant will always be suffixed by 'Z' to indicate UTC. * The second-of-minute is always output. * The nano-of-second outputs zero, three, six or nine digits as necessary. - * When parsing, the behaviour of {@link DateTimeFormatterBuilder#appendOffsetId()} - * will be used to parse the offset, converting the instant to UTC as necessary. + * When parsing, the lenient mode behavior of + * {@link DateTimeFormatterBuilder#appendOffset(String, String) + * appendOffset("+HH", "Z")} will be used to parse the offset, + * converting the instant to UTC as necessary. * The time to at least the seconds field is required. * Fractional seconds from zero to nine are parsed. * The localized decimal style is not used. diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index f5eeeec563c..43a79cd85ee 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -894,8 +894,10 @@ public final class DateTimeFormatterBuilder { * {@link DateTimeFormatter#parsedLeapSecond()} for full details. *

    * When formatting, the instant will always be suffixed by 'Z' to indicate UTC. - * When parsing, the behaviour of {@link DateTimeFormatterBuilder#appendOffsetId()} - * will be used to parse the offset, converting the instant to UTC as necessary. + * When parsing, the lenient mode behaviour of + * {@link DateTimeFormatterBuilder#appendOffset(String, String) + * appendOffset("+HH", "Z")} will be used to parse the offset, + * converting the instant to UTC as necessary. *

    * An alternative to this method is to format/parse the instant as a single * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}. @@ -956,7 +958,7 @@ public final class DateTimeFormatterBuilder { * Appends the zone offset, such as '+01:00', to the formatter. *

    * This appends an instruction to format/parse the offset ID to the builder. - * This is equivalent to calling {@code appendOffset("+HH:mm:ss", "Z")}. + * This is equivalent to calling {@code appendOffset("+HH:MM:ss", "Z")}. * See {@link #appendOffset(String, String)} for details on formatting * and parsing. * @@ -3887,7 +3889,8 @@ public final class DateTimeFormatterBuilder { .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true) - .appendOffsetId() + .parseLenient() + .appendOffset("+HH", "Z") .toFormatter().toPrinterParser(false); DateTimeParseContext newContext = context.copy(); int pos = parser.parse(newContext, text, position); diff --git a/test/jdk/java/time/test/java/time/TestInstant.java b/test/jdk/java/time/test/java/time/TestInstant.java index 1879334cb2a..8dbd951bde1 100644 --- a/test/jdk/java/time/test/java/time/TestInstant.java +++ b/test/jdk/java/time/test/java/time/TestInstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +61,9 @@ package test.java.time; import java.time.Duration; import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import org.testng.annotations.Test; @@ -70,7 +73,7 @@ import static org.testng.Assert.assertThrows; /** * Test Instant. - * @bug 8273369 8331202 + * @bug 8273369 8331202 8364752 */ @Test public class TestInstant extends AbstractTest { @@ -151,4 +154,58 @@ public class TestInstant extends AbstractTest { Instant.now().until(null); }); } + + @DataProvider + private Object[][] valid_instants() { + var I1 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("+02")).toInstant(); + var I2 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("+02:02")).toInstant(); + var I3 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("+02:02:02")).toInstant(); + var I4 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("Z")).toInstant(); + return new Object[][] { + {"2017-01-01T00:00:00.000+02", I1}, + {"2017-01-01T00:00:00.000+0200", I1}, + {"2017-01-01T00:00:00.000+02:00", I1}, + {"2017-01-01T00:00:00.000+020000", I1}, + {"2017-01-01T00:00:00.000+02:00:00", I1}, + + {"2017-01-01T00:00:00.000+0202", I2}, + {"2017-01-01T00:00:00.000+02:02", I2}, + + {"2017-01-01T00:00:00.000+020202", I3}, + {"2017-01-01T00:00:00.000+02:02:02", I3}, + + {"2017-01-01T00:00:00.000Z", I4}, + }; + } + + @Test(dataProvider = "valid_instants") + public void test_parse_valid(String instant, Instant expected) { + assertEquals(Instant.parse(instant), expected); + } + + @DataProvider + private Object[][] invalid_instants() { + return new Object[][] { + {"2017-01-01T00:00:00.000"}, + {"2017-01-01T00:00:00.000+0"}, + {"2017-01-01T00:00:00.000+0:"}, + {"2017-01-01T00:00:00.000+02:"}, + {"2017-01-01T00:00:00.000+020"}, + {"2017-01-01T00:00:00.000+02:0"}, + {"2017-01-01T00:00:00.000+02:0:"}, + {"2017-01-01T00:00:00.000+02:00:"}, + {"2017-01-01T00:00:00.000+02:000"}, + {"2017-01-01T00:00:00.000+02:00:0"}, + {"2017-01-01T00:00:00.000+02:00:0:"}, + {"2017-01-01T00:00:00.000+0200000"}, + {"2017-01-01T00:00:00.000+02:00:000"}, + {"2017-01-01T00:00:00.000+02:00:00:"}, + {"2017-01-01T00:00:00.000UTC"}, + }; + } + + @Test(dataProvider = "invalid_instants") + public void test_parse_invalid(String instant) { + assertThrows(DateTimeParseException.class, () -> Instant.parse(instant)); + } } From 82289f6559cc083ee306b3175fef3ae9f87d6b1c Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 26 Aug 2025 22:30:32 +0000 Subject: [PATCH 007/295] 8365611: Use lookup table for JfrEventThrottler Reviewed-by: mgronlun --- .../recorder/service/jfrEventThrottler.cpp | 104 ++++++++++-------- .../recorder/service/jfrEventThrottler.hpp | 6 +- 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp index f660a01c04c..787b2d7456b 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp @@ -25,7 +25,10 @@ #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/utilities/jfrSpinlockHelper.hpp" +#include "jfrfiles/jfrEventIds.hpp" #include "logging/log.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" constexpr static const JfrSamplerParams _disabled_params = { 0, // sample points per window @@ -34,9 +37,44 @@ constexpr static const JfrSamplerParams _disabled_params = { false // reconfigure }; -static JfrEventThrottler* _disabled_cpu_time_sample_throttler = nullptr; -static JfrEventThrottler* _object_allocation_throttler = nullptr; -static JfrEventThrottler* _safepoint_latency_throttler = nullptr; +constexpr static const JfrEventId throttleble_events[] = { + JfrCPUTimeSampleEvent, JfrObjectAllocationSampleEvent, JfrSafepointLatencyEvent +}; +constexpr static int num_throttled_events = sizeof(throttleble_events) / sizeof(throttleble_events[0]); + +// Throttler-by-ID lookup table +class ThrottlerLookupTable { + static constexpr int max = (int)LAST_EVENT_ID; + STATIC_ASSERT(max < 1000); // should this ever get unreasonably large, we rethink this table. + JfrEventThrottler* _table[max]; +public: + ThrottlerLookupTable() { memset(_table, 0, sizeof(_table)); } + + bool initialize() { + for (int i = 0; i < num_throttled_events; i++) { + const JfrEventId id = throttleble_events[i]; + JfrEventThrottler* p = JfrEventThrottler::create_throttler(id); + _table[(int)id] = p; + if (p == nullptr) { + return false; + } + } + return true; + } + + void destroy() { + for (int i = 0; i < max; i++) { + delete _table[i]; + _table[i] = nullptr; + } + } + + JfrEventThrottler* at(JfrEventId id) const { + return _table[(int)id]; + } +}; + +static ThrottlerLookupTable _throttler_table; JfrEventThrottler::JfrEventThrottler(JfrEventId event_id) : JfrAdaptiveSampler(), @@ -49,58 +87,36 @@ JfrEventThrottler::JfrEventThrottler(JfrEventId event_id) : _update(false) {} bool JfrEventThrottler::create() { - assert(_disabled_cpu_time_sample_throttler == nullptr, "invariant"); - _disabled_cpu_time_sample_throttler = new JfrEventThrottler(JfrCPUTimeSampleEvent); - _disabled_cpu_time_sample_throttler->_disabled = true; - assert(_object_allocation_throttler == nullptr, "invariant"); - _object_allocation_throttler = new JfrEventThrottler(JfrObjectAllocationSampleEvent); - if (_object_allocation_throttler == nullptr || !_object_allocation_throttler->initialize()) { - return false; + bool rc = _throttler_table.initialize(); + if (rc) { + _throttler_table.at(JfrCPUTimeSampleEvent)->_disabled = true; // CPU time sampler disabled } - assert(_safepoint_latency_throttler == nullptr, "invariant"); - _safepoint_latency_throttler = new JfrEventThrottler(JfrSafepointLatencyEvent); - return _safepoint_latency_throttler != nullptr && _safepoint_latency_throttler->initialize(); + return rc; } void JfrEventThrottler::destroy() { - delete _disabled_cpu_time_sample_throttler; - _disabled_cpu_time_sample_throttler = nullptr; - delete _object_allocation_throttler; - _object_allocation_throttler = nullptr; - delete _safepoint_latency_throttler; - _safepoint_latency_throttler = nullptr; + _throttler_table.destroy(); } -// There is currently only two throttler instances, one for the jdk.ObjectAllocationSample event -// and another for the SamplingLatency event. -// When introducing many more throttlers, consider adding a lookup map keyed by event id. JfrEventThrottler* JfrEventThrottler::for_event(JfrEventId event_id) { - assert(_disabled_cpu_time_sample_throttler != nullptr, "Disabled CPU time throttler has not been properly initialized"); - assert(_object_allocation_throttler != nullptr, "ObjectAllocation throttler has not been properly initialized"); - assert(_safepoint_latency_throttler != nullptr, "SafepointLatency throttler has not been properly initialized"); - assert(event_id == JfrObjectAllocationSampleEvent || event_id == JfrSafepointLatencyEvent || event_id == JfrCPUTimeSampleEvent, "Event type has an unconfigured throttler"); - if (event_id == JfrObjectAllocationSampleEvent) { - return _object_allocation_throttler; - } - if (event_id == JfrSafepointLatencyEvent) { - return _safepoint_latency_throttler; - } - if (event_id == JfrCPUTimeSampleEvent) { - return _disabled_cpu_time_sample_throttler; - } - return nullptr; + JfrEventThrottler* const throttler = _throttler_table.at(event_id); + assert(throttler != nullptr, "Event type %d has an unconfigured throttler", (int)event_id); + return throttler; } void JfrEventThrottler::configure(JfrEventId event_id, int64_t sample_size, int64_t period_ms) { - if (event_id == JfrObjectAllocationSampleEvent) { - assert(_object_allocation_throttler != nullptr, "ObjectAllocation throttler has not been properly initialized"); - _object_allocation_throttler->configure(sample_size, period_ms); - return; - } - if (event_id == JfrSafepointLatencyEvent) { - assert(_safepoint_latency_throttler != nullptr, "SafepointLatency throttler has not been properly initialized"); - _safepoint_latency_throttler->configure(sample_size, period_ms); + JfrEventThrottler* const throttler = _throttler_table.at(event_id); + assert(throttler != nullptr, "Event type %d has an unconfigured throttler", (int)event_id); + throttler->configure(sample_size, period_ms); +} + +JfrEventThrottler* JfrEventThrottler::create_throttler(JfrEventId id) { + JfrEventThrottler* p = new JfrEventThrottler(id); + if (p != nullptr && p->initialize() == false) { + delete p; + p = nullptr; } + return p; } /* diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp index be6f8127205..d6e123ecbe6 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Datadog, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,8 +29,11 @@ #include "jfr/support/jfrAdaptiveSampler.hpp" #include "jfrfiles/jfrEventIds.hpp" +class ThrottlerLookupTable; + class JfrEventThrottler : public JfrAdaptiveSampler { friend class JfrRecorder; + friend class ThrottlerLookupTable; private: JfrSamplerParams _last_params; int64_t _sample_size; @@ -43,6 +46,7 @@ class JfrEventThrottler : public JfrAdaptiveSampler { static bool create(); static void destroy(); JfrEventThrottler(JfrEventId event_id); + static JfrEventThrottler* create_throttler(JfrEventId event_id); void configure(int64_t event_sample_size, int64_t period_ms); const JfrSamplerParams& update_params(const JfrSamplerWindow* expired); From 1aca920f5987399dbd114fd5e62b26b363363e64 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 26 Aug 2025 23:57:20 +0000 Subject: [PATCH 008/295] 8365673: Incorrect number of cores are reported on Ryzen CPU Reviewed-by: dholmes, kvn --- src/hotspot/cpu/x86/vm_version_x86.cpp | 5 ++++- src/hotspot/cpu/x86/vm_version_x86.hpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 266fe5abb99..1c9f8ed2e40 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -3148,7 +3148,10 @@ uint VM_Version::cores_per_cpu() { result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); } } else if (is_amd_family()) { - result = (_cpuid_info.ext_cpuid8_ecx.bits.cores_per_cpu + 1); + result = _cpuid_info.ext_cpuid8_ecx.bits.threads_per_cpu + 1; + if (cpu_family() >= 0x17) { // Zen or later + result /= _cpuid_info.ext_cpuid1E_ebx.bits.threads_per_core + 1; + } } else if (is_zx()) { bool supports_topology = supports_processor_topology(); if (supports_topology) { diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 573d4ed27dc..54b3a93d64b 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -199,8 +199,8 @@ class VM_Version : public Abstract_VM_Version { union ExtCpuid8Ecx { uint32_t value; struct { - uint32_t cores_per_cpu : 8, - : 24; + uint32_t threads_per_cpu : 8, + : 24; } bits; }; From 0d543293045d0037791774a1414ef279a1f6768b Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 27 Aug 2025 02:15:02 +0000 Subject: [PATCH 009/295] 8366127: RISC-V: compiler/intrinsics/TestVerifyIntrinsicChecks.java fails when running without RVV Reviewed-by: fyang, fjiang --- .../jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java b/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java index 392ca35e2fd..c482a73affd 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java @@ -34,6 +34,7 @@ * @comment `vm.debug == true` is required since `VerifyIntrinsicChecks` is a * development flag * @requires vm.debug == true & vm.flavor == "server" & !vm.graal.enabled + * @requires (os.arch != "riscv64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*")) * @run main/othervm compiler.intrinsics.TestVerifyIntrinsicChecks verify */ From aaff9dec241e4d8eebefd6beaf287582621f315c Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 27 Aug 2025 04:27:43 +0000 Subject: [PATCH 010/295] 8362566: Use -Xlog:aot+map to print contents of existing AOT cache Reviewed-by: vlivanov, kvn --- src/hotspot/share/cds/aotMapLogger.cpp | 930 ++++++++++++++++++ src/hotspot/share/cds/aotMapLogger.hpp | 126 +++ src/hotspot/share/cds/archiveBuilder.cpp | 424 +------- src/hotspot/share/cds/archiveBuilder.hpp | 10 +- src/hotspot/share/cds/archiveHeapWriter.cpp | 59 +- src/hotspot/share/cds/archiveHeapWriter.hpp | 4 +- src/hotspot/share/cds/cdsConfig.cpp | 3 + src/hotspot/share/cds/metaspaceShared.cpp | 28 +- .../classfile/systemDictionaryShared.cpp | 6 + .../classfile/systemDictionaryShared.hpp | 3 + src/hotspot/share/oops/cpCache.hpp | 1 + src/hotspot/share/oops/objArrayOop.hpp | 3 +- .../hotspot/jtreg/runtime/cds/CDSMapTest.java | 40 +- .../cds/appcds/aotCache/AOTMapTest.java | 139 +++ 14 files changed, 1313 insertions(+), 463 deletions(-) create mode 100644 src/hotspot/share/cds/aotMapLogger.cpp create mode 100644 src/hotspot/share/cds/aotMapLogger.hpp create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp new file mode 100644 index 00000000000..712901a71ca --- /dev/null +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 "cds/aotMapLogger.hpp" +#include "cds/archiveHeapWriter.hpp" +#include "cds/cdsConfig.hpp" +#include "cds/filemap.hpp" +#include "classfile/systemDictionaryShared.hpp" +#include "classfile/vmClasses.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/metaspaceClosure.hpp" +#include "memory/resourceArea.hpp" +#include "oops/method.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/globals_extension.hpp" +#include "utilities/growableArray.hpp" + +bool AOTMapLogger::_is_logging_at_bootstrap; +bool AOTMapLogger::_is_runtime_logging; +intx AOTMapLogger::_buffer_to_requested_delta; +intx AOTMapLogger::_requested_to_mapped_metadata_delta; +size_t AOTMapLogger::_num_root_segments; +size_t AOTMapLogger::_num_obj_arrays_logged; +GrowableArrayCHeap* AOTMapLogger::_roots; +ArchiveHeapInfo* AOTMapLogger::_dumptime_heap_info; + +class AOTMapLogger::RequestedMetadataAddr { + address _raw_addr; + +public: + RequestedMetadataAddr(address raw_addr) : _raw_addr(raw_addr) {} + + address raw_addr() const { return _raw_addr; } + + Klass* to_real_klass() const { + if (_raw_addr == nullptr) { + return nullptr; + } + + if (_is_runtime_logging) { + return (Klass*)(_raw_addr + _requested_to_mapped_metadata_delta); + } else { + ArchiveBuilder* builder = ArchiveBuilder::current(); + address buffered_addr = builder->requested_to_buffered(_raw_addr); + address klass = builder->get_source_addr(buffered_addr); + return (Klass*)klass; + } + } +}; // AOTMapLogger::RequestedMetadataAddr + +void AOTMapLogger::ergo_initialize() { + if (!CDSConfig::is_dumping_archive() && CDSConfig::is_using_archive() && log_is_enabled(Info, aot, map)) { + _is_logging_at_bootstrap = true; + if (FLAG_IS_DEFAULT(ArchiveRelocationMode)) { + FLAG_SET_ERGO(ArchiveRelocationMode, 0); + } else if (ArchiveRelocationMode != 0) { + log_warning(aot, map)("Addresses in the AOT map may be incorrect for -XX:ArchiveRelocationMode=%d.", ArchiveRelocationMode); + } + } +} + +void AOTMapLogger::dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo, + ArchiveHeapInfo* heap_info, + char* bitmap, size_t bitmap_size_in_bytes) { + _is_runtime_logging = false; + _buffer_to_requested_delta = ArchiveBuilder::current()->buffer_to_requested_delta(); + _num_root_segments = mapinfo->heap_root_segments().count(); + _dumptime_heap_info = heap_info; + + log_file_header(mapinfo); + + DumpRegion* rw_region = &builder->_rw_region; + DumpRegion* ro_region = &builder->_ro_region; + + dumptime_log_metaspace_region("rw region", rw_region, &builder->_rw_src_objs); + dumptime_log_metaspace_region("ro region", ro_region, &builder->_ro_src_objs); + + address bitmap_end = address(bitmap + bitmap_size_in_bytes); + log_region_range("bitmap", address(bitmap), bitmap_end, nullptr); + log_as_hex((address)bitmap, bitmap_end, nullptr); + +#if INCLUDE_CDS_JAVA_HEAP + if (heap_info->is_used()) { + dumptime_log_heap_region(heap_info); + } +#endif + + log_info(aot, map)("[End of AOT cache map]"); +} + +// This class is used to find the location and type of all the +// archived metaspace objects. +class AOTMapLogger::RuntimeGatherArchivedMetaspaceObjs : public UniqueMetaspaceClosure { + GrowableArrayCHeap _objs; + + static int compare_objs_by_addr(ArchivedObjInfo* a, ArchivedObjInfo* b) { + intx diff = a->_src_addr - b->_src_addr; + if (diff < 0) { + return -1; + } else if (diff == 0) { + return 0; + } else { + return 1; + } + } + +public: + GrowableArrayCHeap* objs() { return &_objs; } + + virtual bool do_unique_ref(Ref* ref, bool read_only) { + ArchivedObjInfo info; + info._src_addr = ref->obj(); + info._buffered_addr = ref->obj(); + info._requested_addr = ref->obj(); + info._bytes = ref->size() * BytesPerWord; + info._type = ref->msotype(); + _objs.append(info); + + return true; // keep iterating + } + + void finish() { + UniqueMetaspaceClosure::finish(); + _objs.sort(compare_objs_by_addr); + } +}; // AOTMapLogger::RuntimeGatherArchivedMetaspaceObjs + +void AOTMapLogger::runtime_log(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo) { + _is_runtime_logging = true; + _requested_to_mapped_metadata_delta = static_mapinfo->relocation_delta(); + + ResourceMark rm; + RuntimeGatherArchivedMetaspaceObjs gatherer; + + if (log_is_enabled(Debug, aot, map)) { + // The metaspace objects in the AOT cache are stored as a stream of bytes. For space + // saving, we don't store a complete index that tells us where one object ends and + // another object starts. There's also no type information. + // + // However, we can rebuild our index by iterating over all the objects using + // MetaspaceClosure, starting from the dictionary of Klasses in SystemDictionaryShared. + GrowableArray klasses; + SystemDictionaryShared::get_all_archived_classes(/*is_static*/true, &klasses); + if (dynamic_mapinfo != nullptr) { + SystemDictionaryShared::get_all_archived_classes(/*is_static*/false, &klasses); + } + + for (int i = 0; i < klasses.length(); i++) { + gatherer.push(klasses.adr_at(i)); + } + gatherer.finish(); + } + + runtime_log(static_mapinfo, gatherer.objs()); + if (dynamic_mapinfo != nullptr) { + runtime_log(dynamic_mapinfo, gatherer.objs()); + } +} + +void AOTMapLogger::runtime_log(FileMapInfo* mapinfo, GrowableArrayCHeap* objs) { + log_file_header(mapinfo); + + runtime_log_metaspace_regions(mapinfo, objs); + +#if INCLUDE_CDS_JAVA_HEAP + if (mapinfo->has_heap_region() && CDSConfig::is_loading_heap()) { + _num_root_segments = mapinfo->heap_root_segments().count(); + runtime_log_heap_region(mapinfo); + } +#endif + + log_info(aot, map)("[End of map]"); +} + +void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* region, + const ArchiveBuilder::SourceObjList* src_objs) { + address region_base = address(region->base()); + address region_top = address(region->top()); + log_region_range(name, region_base, region_top, region_base + _buffer_to_requested_delta); + if (log_is_enabled(Debug, aot, map)) { + GrowableArrayCHeap objs; + for (int i = 0; i < src_objs->objs()->length(); i++) { + ArchiveBuilder::SourceObjInfo* src_info = src_objs->at(i); + ArchivedObjInfo info; + info._src_addr = src_info->source_addr(); + info._buffered_addr = src_info->buffered_addr(); + info._requested_addr = info._buffered_addr + _buffer_to_requested_delta; + info._bytes = src_info->size_in_bytes(); + info._type = src_info->msotype(); + objs.append(info); + } + + log_metaspace_objects_impl(address(region->base()), address(region->end()), &objs, 0, objs.length()); + } +} + +void AOTMapLogger::runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap* objs) { + FileMapRegion* rw = mapinfo->region_at(MetaspaceShared::rw); + FileMapRegion* ro = mapinfo->region_at(MetaspaceShared::ro); + + address rw_base = address(rw->mapped_base()); + address rw_end = address(rw->mapped_end()); + address ro_base = address(ro->mapped_base()); + address ro_end = address(ro->mapped_end()); + + int first_rw_index = -1; + int first_ro_index = -1; + int last_ro_index = -1; + + if (log_is_enabled(Debug, aot, map)) { + int i = 0; + for (; i < objs->length(); i++) { + address p = objs->at(i)._src_addr; + if (p < rw_base) { + // We are printing the dynamic archive but found an object in the static archive + precond(!mapinfo->is_static()); + continue; + } + if (first_rw_index < 0) { + first_rw_index = i; + continue; + } + if (p < ro_base) { + continue; + } + if (first_ro_index < 0) { + first_ro_index = i; + continue; + } + if (p < ro_end) { + continue; + } else { + last_ro_index = i; + break; + } + } + } + + if (last_ro_index < 0) { + last_ro_index = objs->length(); + } + + log_region_range("rw", rw_base, rw_end, rw_base - _requested_to_mapped_metadata_delta); + if (log_is_enabled(Debug, aot, map)) { + log_metaspace_objects_impl(rw_base, rw_end, objs, first_rw_index, first_ro_index); + } + + log_region_range("ro", ro_base, ro_end, ro_base - _requested_to_mapped_metadata_delta); + if (log_is_enabled(Debug, aot, map)) { + log_metaspace_objects_impl(ro_base, ro_end, objs, first_ro_index, last_ro_index); + } +} + +void AOTMapLogger::log_file_header(FileMapInfo* mapinfo) { + const char* type; + if (mapinfo->is_static()) { + if (CDSConfig::new_aot_flags_used()) { + type = "AOT cache"; + } else { + type = "Static CDS archive"; + } + } else { + type = "Dynamic CDS archive"; + } + + log_info(aot, map)("%s map for %s", type, mapinfo->full_path()); + + address header = address(mapinfo->header()); + address header_end = header + mapinfo->header()->header_size(); + + log_region_range("header", header, header_end, nullptr); + LogStreamHandle(Info, aot, map) lsh; + mapinfo->print(&lsh); + log_as_hex(header, header_end, nullptr); +} + +// Log information about a region, whose address at dump time is [base .. top). At +// runtime, this region will be mapped to requested_base. requested_base is nullptr if this +// region will be mapped at os-selected addresses (such as the bitmap region), or will +// be accessed with os::read (the header). +void AOTMapLogger::log_region_range(const char* name, address base, address top, address requested_base) { + size_t size = top - base; + base = requested_base; + if (requested_base == nullptr) { + top = (address)size; + } else { + top = requested_base + size; + } + log_info(aot, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", + name, p2i(base), p2i(top), size); +} + +#define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d" + +void AOTMapLogger::log_metaspace_objects_impl(address region_base, address region_end, GrowableArrayCHeap* objs, + int start_idx, int end_idx) { + address last_obj_base = region_base; + address last_obj_end = region_base; + Thread* current = Thread::current(); + + for (int i = start_idx; i < end_idx; i++) { + ArchivedObjInfo& info = objs->at(i); + address src = info._src_addr; + address buffered_addr = info._buffered_addr; + address requested_addr = info._requested_addr; + int bytes = info._bytes; + MetaspaceObj::Type type = info._type; + const char* type_name = MetaspaceObj::type_name(type); + + log_as_hex(last_obj_base, buffered_addr, last_obj_base + _buffer_to_requested_delta); + + switch (type) { + case MetaspaceObj::ClassType: + log_klass((Klass*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::ConstantPoolType: + log_constant_pool((ConstantPool*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::ConstantPoolCacheType: + log_constant_pool_cache((ConstantPoolCache*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::ConstMethodType: + log_const_method((ConstMethod*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::MethodType: + log_method((Method*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::SymbolType: + log_symbol((Symbol*)src, requested_addr, type_name, bytes, current); + break; + default: + log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes); + break; + } + + last_obj_base = buffered_addr; + last_obj_end = buffered_addr + bytes; + } + + log_as_hex(last_obj_base, last_obj_end, last_obj_base + _buffer_to_requested_delta); + if (last_obj_end < region_end) { + log_debug(aot, map)(PTR_FORMAT ": @@ Misc data %zu bytes", + p2i(last_obj_end + _buffer_to_requested_delta), + size_t(region_end - last_obj_end)); + log_as_hex(last_obj_end, region_end, last_obj_end + _buffer_to_requested_delta); + } +} + +void AOTMapLogger::log_constant_pool(ConstantPool* cp, address requested_addr, + const char* type_name, int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + cp->pool_holder()->external_name()); +} + +void AOTMapLogger::log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr, + const char* type_name, int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + cpc->constant_pool()->pool_holder()->external_name()); +} + +void AOTMapLogger::log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, cm->method()->external_name()); +} + +void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, k->external_name()); +} + +void AOTMapLogger::log_method(Method* m, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, m->external_name()); +} + +void AOTMapLogger::log_symbol(Symbol* s, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + s->as_quoted_ascii()); +} + +#undef _LOG_PREFIX + +// Log all the data [base...top). Pretend that the base address +// will be mapped to requested_base at run-time. +void AOTMapLogger::log_as_hex(address base, address top, address requested_base, bool is_heap) { + assert(top >= base, "must be"); + + LogStreamHandle(Trace, aot, map) lsh; + if (lsh.is_enabled()) { + int unitsize = sizeof(address); + if (is_heap && UseCompressedOops) { + // This makes the compressed oop pointers easier to read, but + // longs and doubles will be split into two words. + unitsize = sizeof(narrowOop); + } + os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base); + } +} + +#if INCLUDE_CDS_JAVA_HEAP +// FakeOop (and subclasses FakeMirror, FakeString, FakeObjArray, FakeTypeArray) are used to traverse +// and print the (image of) heap objects stored in the AOT cache. These objects are different than regular oops: +// - They do not reside inside the range of the heap. +// - For +UseCompressedOops: pointers may use a different narrowOop encoding: see FakeOop::read_oop_at(narrowOop*) +// - For -UseCompressedOops: pointers are not direct: see FakeOop::read_oop_at(oop*) +// +// Hence, in general, we cannot use regular oop API (such as oopDesc::obj_field()) on these objects. There +// are a few rare case where regular oop API work, but these are all guarded with the raw_oop() method and +// should be used with care. +class AOTMapLogger::FakeOop { + static int _requested_shift; + static intx _buffer_to_requested_delta; + static address _buffer_start; + static address _buffer_end; + static uint64_t _buffer_start_narrow_oop; // The encoded narrow oop for the objects at _buffer_start + + address _buffer_addr; + + static void assert_range(address buffer_addr) { + assert(_buffer_start <= buffer_addr && buffer_addr < _buffer_end, "range check"); + } + + address* field_addr(int field_offset) { + return (address*)(_buffer_addr + field_offset); + } + +protected: + RequestedMetadataAddr metadata_field(int field_offset) { + return RequestedMetadataAddr(*(address*)(field_addr(field_offset))); + } + + // Return an "oop" pointer so we can use APIs that accept regular oops. This + // must be used with care, as only a limited number of APIs can work with oops that + // live outside of the range of the heap. + oop raw_oop() { return cast_to_oop(_buffer_addr); } + +public: + static void init_globals(address requested_base, address requested_start, int requested_shift, + address buffer_start, address buffer_end) { + _requested_shift = requested_shift; + _buffer_to_requested_delta = requested_start - buffer_start; + _buffer_start = buffer_start; + _buffer_end = buffer_end; + + precond(requested_start >= requested_base); + if (UseCompressedOops) { + _buffer_start_narrow_oop = (uint64_t)(pointer_delta(requested_start, requested_base, 1)) >> _requested_shift; + assert(_buffer_start_narrow_oop < 0xffffffff, "sanity"); + } else { + _buffer_start_narrow_oop = 0xdeadbeed; + } + } + + FakeOop() : _buffer_addr(nullptr) {} + + FakeOop(address buffer_addr) : _buffer_addr(buffer_addr) { + if (_buffer_addr != nullptr) { + assert_range(_buffer_addr); + } + } + + FakeMirror& as_mirror(); + FakeObjArray& as_obj_array(); + FakeString& as_string(); + FakeTypeArray& as_type_array(); + + RequestedMetadataAddr klass() { + address rk = (address)real_klass(); + if (_is_runtime_logging) { + return RequestedMetadataAddr(rk - _requested_to_mapped_metadata_delta); + } else { + ArchiveBuilder* builder = ArchiveBuilder::current(); + return builder->to_requested(builder->get_buffered_addr(rk)); + } + } + + Klass* real_klass() { + assert(UseCompressedClassPointers, "heap archiving requires UseCompressedClassPointers"); + if (_is_runtime_logging) { + return raw_oop()->klass(); + } else { + return ArchiveHeapWriter::real_klass_of_buffered_oop(_buffer_addr); + } + } + + // in heap words + size_t size() { + if (_is_runtime_logging) { + return raw_oop()->size_given_klass(real_klass()); + } else { + return ArchiveHeapWriter::size_of_buffered_oop(_buffer_addr); + } + } + + bool is_array() { return real_klass()->is_array_klass(); } + bool is_null() { return _buffer_addr == nullptr; } + + int array_length() { + precond(is_array()); + return arrayOop(raw_oop())->length(); + } + + address requested_addr() { + return _buffer_addr + _buffer_to_requested_delta; + } + + uint32_t as_narrow_oop_value() { + precond(UseCompressedOops); + if (_buffer_addr == nullptr) { + return 0; + } + uint64_t pd = (uint64_t)(pointer_delta(_buffer_addr, _buffer_start, 1)); + return checked_cast(_buffer_start_narrow_oop + (pd >> _requested_shift)); + } + + FakeOop read_oop_at(narrowOop* addr) { // +UseCompressedOops + uint64_t n = (uint64_t)(*addr); + if (n == 0) { + return FakeOop(nullptr); + } else { + precond(n >= _buffer_start_narrow_oop); + address value = _buffer_start + ((n - _buffer_start_narrow_oop) << _requested_shift); + return FakeOop(value); + } + } + + FakeOop read_oop_at(oop* addr) { // -UseCompressedOops + address requested_value = cast_from_oop

    (*addr); + if (requested_value == nullptr) { + return FakeOop(nullptr); + } else { + return FakeOop(requested_value - _buffer_to_requested_delta); + } + } + + FakeOop obj_field(int field_offset) { + if (UseCompressedOops) { + return read_oop_at(raw_oop()->field_addr(field_offset)); + } else { + return read_oop_at(raw_oop()->field_addr(field_offset)); + } + } + + void print_non_oop_field(outputStream* st, fieldDescriptor* fd) { + // fd->print_on_for() works for non-oop fields in fake oops + precond(fd->field_type() != T_ARRAY && fd->field_type() != T_OBJECT); + fd->print_on_for(st, raw_oop()); + } +}; // AOTMapLogger::FakeOop + +class AOTMapLogger::FakeMirror : public AOTMapLogger::FakeOop { +public: + void print_class_signature_on(outputStream* st); + + Klass* real_mirrored_klass() { + RequestedMetadataAddr mirrored_klass = metadata_field(java_lang_Class::klass_offset()); + return mirrored_klass.to_real_klass(); + } + + int static_oop_field_count() { + return java_lang_Class::static_oop_field_count(raw_oop()); + } +}; // AOTMapLogger::FakeMirror + +class AOTMapLogger::FakeObjArray : public AOTMapLogger::FakeOop { + objArrayOop raw_objArrayOop() { + return (objArrayOop)raw_oop(); + } + +public: + int length() { + return raw_objArrayOop()->length(); + } + FakeOop obj_at(int i) { + if (UseCompressedOops) { + return read_oop_at(raw_objArrayOop()->obj_at_addr(i)); + } else { + return read_oop_at(raw_objArrayOop()->obj_at_addr(i)); + } + } +}; // AOTMapLogger::FakeObjArray + +class AOTMapLogger::FakeString : public AOTMapLogger::FakeOop { +public: + bool is_latin1() { + jbyte coder = raw_oop()->byte_field(java_lang_String::coder_offset()); + assert(CompactStrings || coder == java_lang_String::CODER_UTF16, "Must be UTF16 without CompactStrings"); + return coder == java_lang_String::CODER_LATIN1; + } + + FakeTypeArray value(); + + int length(); + void print_on(outputStream* st, int max_length = MaxStringPrintSize); +}; // AOTMapLogger::FakeString + +class AOTMapLogger::FakeTypeArray : public AOTMapLogger::FakeOop { + typeArrayOop raw_typeArrayOop() { + return (typeArrayOop)raw_oop(); + } + +public: + void print_elements_on(outputStream* st) { + TypeArrayKlass::cast(real_klass())->oop_print_elements_on(raw_typeArrayOop(), st); + } + + int length() { return raw_typeArrayOop()->length(); } + jbyte byte_at(int i) { return raw_typeArrayOop()->byte_at(i); } + jchar char_at(int i) { return raw_typeArrayOop()->char_at(i); } +}; // AOTMapLogger::FakeTypeArray + +AOTMapLogger::FakeMirror& AOTMapLogger::FakeOop::as_mirror() { + precond(real_klass() == vmClasses::Class_klass()); + return (FakeMirror&)*this; +} + +AOTMapLogger::FakeObjArray& AOTMapLogger::FakeOop::as_obj_array() { + precond(real_klass()->is_objArray_klass()); + return (FakeObjArray&)*this; +} + +AOTMapLogger::FakeTypeArray& AOTMapLogger::FakeOop::as_type_array() { + precond(real_klass()->is_typeArray_klass()); + return (FakeTypeArray&)*this; +} + +AOTMapLogger::FakeString& AOTMapLogger::FakeOop::as_string() { + precond(real_klass() == vmClasses::String_klass()); + return (FakeString&)*this; +} + +void AOTMapLogger::FakeMirror::print_class_signature_on(outputStream* st) { + ResourceMark rm; + RequestedMetadataAddr requested_klass = metadata_field(java_lang_Class::klass_offset()); + Klass* real_klass = requested_klass.to_real_klass(); + + if (real_klass == nullptr) { + // This is a primitive mirror (Java expressions of int.class, long.class, void.class, etc); + RequestedMetadataAddr requested_array_klass = metadata_field(java_lang_Class::array_klass_offset()); + Klass* real_array_klass = requested_array_klass.to_real_klass(); + if (real_array_klass == nullptr) { + st->print(" V"); // The special mirror for void.class that doesn't have any representation in C++ + } else { + precond(real_array_klass->is_typeArray_klass()); + st->print(" %c", real_array_klass->name()->char_at(1)); + } + } else { + const char* class_name = real_klass->name()->as_C_string(); + if (real_klass->is_instance_klass()) { + st->print(" L%s;", class_name); + } else { + st->print(" %s", class_name); + } + if (real_klass->has_aot_initialized_mirror()) { + st->print(" (aot-inited)"); + } + } +} + +AOTMapLogger::FakeTypeArray AOTMapLogger::FakeString::value() { + return obj_field(java_lang_String::value_offset()).as_type_array(); +} + +int AOTMapLogger::FakeString::length() { + FakeTypeArray v = value(); + if (v.is_null()) { + return 0; + } + int arr_length = v.length(); + if (!is_latin1()) { + assert((arr_length & 1) == 0, "should be even for UTF16 string"); + arr_length >>= 1; // convert number of bytes to number of elements + } + return arr_length; +} + +void AOTMapLogger::FakeString::print_on(outputStream* st, int max_length) { + FakeTypeArray v = value(); + int length = this->length(); + bool is_latin1 = this->is_latin1(); + bool abridge = length > max_length; + + st->print("\""); + for (int index = 0; index < length; index++) { + // If we need to abridge and we've printed half the allowed characters + // then jump to the tail of the string. + if (abridge && index >= max_length / 2) { + st->print(" ... (%d characters ommitted) ... ", length - 2 * (max_length / 2)); + index = length - (max_length / 2); + abridge = false; // only do this once + } + jchar c = (!is_latin1) ? v.char_at(index) : + ((jchar) v.byte_at(index)) & 0xff; + if (c < ' ') { + st->print("\\x%02X", c); // print control characters e.g. \x0A + } else { + st->print("%c", c); + } + } + st->print("\""); + + if (length > max_length) { + st->print(" (abridged) "); + } +} + +class AOTMapLogger::ArchivedFieldPrinter : public FieldClosure { + FakeOop _fake_oop; + outputStream* _st; +public: + ArchivedFieldPrinter(FakeOop fake_oop, outputStream* st) : _fake_oop(fake_oop), _st(st) {} + + void do_field(fieldDescriptor* fd) { + _st->print(" - "); + BasicType ft = fd->field_type(); + switch (ft) { + case T_ARRAY: + case T_OBJECT: + { + fd->print_on(_st); // print just the name and offset + FakeOop field_value = _fake_oop.obj_field(fd->offset()); + print_oop_info_cr(_st, field_value); + } + break; + default: + _fake_oop.print_non_oop_field(_st, fd); // name, offset, value + _st->cr(); + } + } +}; // AOTMapLogger::ArchivedFieldPrinter + +int AOTMapLogger::FakeOop::_requested_shift; +intx AOTMapLogger::FakeOop::_buffer_to_requested_delta; +address AOTMapLogger::FakeOop::_buffer_start; +address AOTMapLogger::FakeOop::_buffer_end; +uint64_t AOTMapLogger::FakeOop::_buffer_start_narrow_oop; + +void AOTMapLogger::dumptime_log_heap_region(ArchiveHeapInfo* heap_info) { + MemRegion r = heap_info->buffer_region(); + address buffer_start = address(r.start()); // start of the current oop inside the buffer + address buffer_end = address(r.end()); + + address requested_base = UseCompressedOops ? (address)CompressedOops::base() : (address)ArchiveHeapWriter::NOCOOPS_REQUESTED_BASE; + address requested_start = UseCompressedOops ? ArchiveHeapWriter::buffered_addr_to_requested_addr(buffer_start) : requested_base; + int requested_shift = CompressedOops::shift(); + + FakeOop::init_globals(requested_base, requested_start, requested_shift, buffer_start, buffer_end); + + log_region_range("heap", buffer_start, buffer_end, requested_start); + log_oops(buffer_start, buffer_end); +} + +void AOTMapLogger::runtime_log_heap_region(FileMapInfo* mapinfo) { + ResourceMark rm; + int heap_region_index = MetaspaceShared::hp; + FileMapRegion* r = mapinfo->region_at(heap_region_index); + size_t alignment = ObjectAlignmentInBytes; + + // Allocate a buffer and read the image of the archived heap region. This buffer is outside + // of the real Java heap, so we must use FakeOop to access the contents of the archived heap objects. + char* buffer = resource_allocate_bytes(r->used() + alignment); + address buffer_start = (address)align_up(buffer, alignment); + address buffer_end = buffer_start + r->used(); + if (!mapinfo->read_region(heap_region_index, (char*)buffer_start, r->used(), /* do_commit = */ false)) { + log_error(aot)("Cannot read heap region; AOT map logging of heap objects failed"); + return; + } + + address requested_base = UseCompressedOops ? (address)mapinfo->narrow_oop_base() : mapinfo->heap_region_requested_address(); + address requested_start = requested_base + r->mapping_offset(); + int requested_shift = mapinfo->narrow_oop_shift(); + + FakeOop::init_globals(requested_base, requested_start, requested_shift, buffer_start, buffer_end); + + log_region_range("heap", buffer_start, buffer_end, requested_start); + log_oops(buffer_start, buffer_end); +} + +void AOTMapLogger::log_oops(address buffer_start, address buffer_end) { + LogStreamHandle(Debug, aot, map) st; + if (!st.is_enabled()) { + return; + } + + _roots = new GrowableArrayCHeap(); + _num_obj_arrays_logged = 0; + + for (address fop = buffer_start; fop < buffer_end; ) { + FakeOop fake_oop(fop); + st.print(PTR_FORMAT ": @@ Object ", p2i(fake_oop.requested_addr())); + print_oop_info_cr(&st, fake_oop, /*print_requested_addr=*/false); + + LogStreamHandle(Trace, aot, map, oops) trace_st; + if (trace_st.is_enabled()) { + print_oop_details(fake_oop, &trace_st); + } + + address next_fop = fop + fake_oop.size() * BytesPerWord; + log_as_hex(fop, next_fop, fake_oop.requested_addr(), /*is_heap=*/true); + + fop = next_fop; + } + + delete _roots; +} + +void AOTMapLogger::print_oop_info_cr(outputStream* st, FakeOop fake_oop, bool print_requested_addr) { + if (fake_oop.is_null()) { + st->print_cr("null"); + } else { + ResourceMark rm; + Klass* real_klass = fake_oop.real_klass(); + address requested_addr = fake_oop.requested_addr(); + if (print_requested_addr) { + st->print(PTR_FORMAT " ", p2i(requested_addr)); + } + if (UseCompressedOops) { + st->print("(0x%08x) ", fake_oop.as_narrow_oop_value()); + } + if (fake_oop.is_array()) { + int array_len = fake_oop.array_length(); + st->print_cr("%s length: %d", real_klass->external_name(), array_len); + } else { + st->print("%s", real_klass->external_name()); + + if (real_klass == vmClasses::String_klass()) { + st->print(" "); + fake_oop.as_string().print_on(st); + } else if (real_klass == vmClasses::Class_klass()) { + fake_oop.as_mirror().print_class_signature_on(st); + } + + st->cr(); + } + } +} + +// Print the fields of instanceOops, or the elements of arrayOops +void AOTMapLogger::print_oop_details(FakeOop fake_oop, outputStream* st) { + Klass* real_klass = fake_oop.real_klass(); + + st->print(" - klass: "); + real_klass->print_value_on(st); + st->print(" " PTR_FORMAT, p2i(fake_oop.klass().raw_addr())); + st->cr(); + + if (real_klass->is_typeArray_klass()) { + fake_oop.as_type_array().print_elements_on(st); + } else if (real_klass->is_objArray_klass()) { + FakeObjArray fake_obj_array = fake_oop.as_obj_array(); + bool is_logging_root_segment = _num_obj_arrays_logged < _num_root_segments; + + for (int i = 0; i < fake_obj_array.length(); i++) { + FakeOop elm = fake_obj_array.obj_at(i); + if (is_logging_root_segment) { + st->print(" root[%4d]: ", _roots->length()); + _roots->append(elm); + } else { + st->print(" -%4d: ", i); + } + print_oop_info_cr(st, elm); + } + _num_obj_arrays_logged ++; + } else { + st->print_cr(" - fields (%zu words):", fake_oop.size()); + + ArchivedFieldPrinter print_field(fake_oop, st); + InstanceKlass::cast(real_klass)->print_nonstatic_fields(&print_field); + + if (real_klass == vmClasses::Class_klass()) { + FakeMirror fake_mirror = fake_oop.as_mirror(); + + st->print(" - signature: "); + fake_mirror.print_class_signature_on(st); + st->cr(); + + Klass* real_mirrored_klass = fake_mirror.real_mirrored_klass(); + if (real_mirrored_klass != nullptr && real_mirrored_klass->is_instance_klass()) { + InstanceKlass* real_mirrored_ik = InstanceKlass::cast(real_mirrored_klass); + + ConstantPoolCache* cp_cache = real_mirrored_ik->constants()->cache(); + if (!_is_runtime_logging) { + cp_cache = ArchiveBuilder::current()->get_buffered_addr(cp_cache); + } + int rr_root_index = cp_cache->archived_references_index(); + st->print(" - resolved_references: "); + if (rr_root_index >= 0) { + FakeOop resolved_references = _roots->at(rr_root_index); + print_oop_info_cr(st, resolved_references); + } else { + st->print("null"); + } + + st->print_cr("- ---- static fields (%d):", fake_mirror.static_oop_field_count()); + real_mirrored_ik->do_local_static_fields(&print_field); + } + } + } +} +#endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/aotMapLogger.hpp b/src/hotspot/share/cds/aotMapLogger.hpp new file mode 100644 index 00000000000..9cd67fb7ff6 --- /dev/null +++ b/src/hotspot/share/cds/aotMapLogger.hpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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_AOTMAPLOGGER_HPP +#define SHARE_CDS_AOTMAPLOGGER_HPP + +#include "cds/archiveBuilder.hpp" +#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" + +class ArchiveHeapInfo; +class DumpRegion; +class FileMapInfo; +class outputStream; + +// Write detailed info to a mapfile to analyze contents of the AOT cache/CDS archive. +// -Xlog:aot+map* can be used both when creating an AOT cache, or when using an AOT cache. +// +// Creating cache: +// java -XX:AOTCacheOutput=app.aot -Xlog:aot+map*=trace -cp app.jar App +// +// Using cache: +// java -XX:AOTCache=app.aot -Xlog:aot+map*=trace -cp app.jar App +// +// You can also print the map of a cache without executing the application by using the +// --version flag: +// java -XX:AOTCache=app.aot -Xlog:aot+map*=trace --version +// +// Because the output can be large, it's best to save it to a file +// java -XX:AOTCache=app.aot -Xlog:aot+map*=trace:file=aot.map:none:filesize=0 --version +class AOTMapLogger : AllStatic { + struct ArchivedObjInfo { + address _src_addr; + address _buffered_addr; + address _requested_addr; + int _bytes; + MetaspaceObj::Type _type; + }; + + // FakeOop and subtypes + class FakeOop; + class FakeMirror; + class FakeObjArray; + class FakeString; + class FakeTypeArray; + + class RequestedMetadataAddr; + class RuntimeGatherArchivedMetaspaceObjs; + + static bool _is_logging_at_bootstrap; + static bool _is_runtime_logging; + static size_t _num_root_segments; + static size_t _num_obj_arrays_logged; + static GrowableArrayCHeap* _roots; + static ArchiveHeapInfo* _dumptime_heap_info; + + static intx _buffer_to_requested_delta; + static intx _requested_to_mapped_metadata_delta; + + static void runtime_log(FileMapInfo* mapinfo, GrowableArrayCHeap* objs); + static void runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap* objs); + static void dumptime_log_metaspace_region(const char* name, DumpRegion* region, + const ArchiveBuilder::SourceObjList* src_objs); + + // Common code for dumptime/runtime + static void log_file_header(FileMapInfo* mapinfo); + static void log_region_range(const char* name, address base, address top, address requested_base); + static void log_metaspace_objects_impl(address region_base, address region_end, + GrowableArrayCHeap* objs, int start_idx, int end_idx); + static void log_as_hex(address base, address top, address requested_base, bool is_heap = false); + + // Metaspace object: type-specific logging + static void log_constant_pool(ConstantPool* cp, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr, + const char* type_name, int bytes, Thread* current); + static void log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current); + + +#if INCLUDE_CDS_JAVA_HEAP + static void dumptime_log_heap_region(ArchiveHeapInfo* heap_info); + static void runtime_log_heap_region(FileMapInfo* mapinfo); + + static void print_oop_info_cr(outputStream* st, FakeOop fake_oop, bool print_requested_addr = true); + static void print_oop_details(FakeOop fake_oop, outputStream* st); + static void log_oops(address buf_start, address buf_end); + class ArchivedFieldPrinter; // to be replaced by ArchivedFieldPrinter2 +#endif + +public: + static void ergo_initialize(); + static bool is_logging_at_bootstrap() { return _is_logging_at_bootstrap; } + + static void dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo, + ArchiveHeapInfo* heap_info, + char* bitmap, size_t bitmap_size_in_bytes); + static void runtime_log(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo); +}; + +#endif // SHARE_CDS_AOTMAPLOGGER_HPP diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 1d054561c76..1c807776e3c 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassLinker.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMapLogger.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" @@ -46,7 +47,6 @@ #include "interpreter/abstractInterpreter.hpp" #include "jvm.h" #include "logging/log.hpp" -#include "logging/logStream.hpp" #include "memory/allStatic.hpp" #include "memory/memoryReserver.hpp" #include "memory/memRegion.hpp" @@ -60,7 +60,6 @@ #include "oops/oopHandle.inline.hpp" #include "oops/trainingData.hpp" #include "runtime/arguments.hpp" -#include "runtime/fieldDescriptor.inline.hpp" #include "runtime/globals_extension.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -1188,424 +1187,6 @@ void ArchiveBuilder::relocate_to_requested() { } } -// Write detailed info to a mapfile to analyze contents of the archive. -// static dump: -// java -Xshare:dump -Xlog:cds+map=trace:file=cds.map:none:filesize=0 -// dynamic dump: -// java -cp MyApp.jar -XX:ArchiveClassesAtExit=MyApp.jsa \ -// -Xlog:cds+map=trace:file=cds.map:none:filesize=0 MyApp -// -// We need to do some address translation because the buffers used at dump time may be mapped to -// a different location at runtime. At dump time, the buffers may be at arbitrary locations -// picked by the OS. At runtime, we try to map at a fixed location (SharedBaseAddress). For -// consistency, we log everything using runtime addresses. -class ArchiveBuilder::CDSMapLogger : AllStatic { - static intx buffer_to_runtime_delta() { - // Translate the buffers used by the RW/RO regions to their eventual (requested) locations - // at runtime. - return ArchiveBuilder::current()->buffer_to_requested_delta(); - } - - // rw/ro regions only - static void log_metaspace_region(const char* name, DumpRegion* region, - const ArchiveBuilder::SourceObjList* src_objs) { - address region_base = address(region->base()); - address region_top = address(region->top()); - log_region(name, region_base, region_top, region_base + buffer_to_runtime_delta()); - log_metaspace_objects(region, src_objs); - } - -#define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d" - - static void log_klass(Klass* k, address runtime_dest, const char* type_name, int bytes, Thread* current) { - ResourceMark rm(current); - log_debug(aot, map)(_LOG_PREFIX " %s", - p2i(runtime_dest), type_name, bytes, k->external_name()); - } - static void log_method(Method* m, address runtime_dest, const char* type_name, int bytes, Thread* current) { - ResourceMark rm(current); - log_debug(aot, map)(_LOG_PREFIX " %s", - p2i(runtime_dest), type_name, bytes, m->external_name()); - } - - // rw/ro regions only - static void log_metaspace_objects(DumpRegion* region, const ArchiveBuilder::SourceObjList* src_objs) { - address last_obj_base = address(region->base()); - address last_obj_end = address(region->base()); - address region_end = address(region->end()); - Thread* current = Thread::current(); - for (int i = 0; i < src_objs->objs()->length(); i++) { - SourceObjInfo* src_info = src_objs->at(i); - address src = src_info->source_addr(); - address dest = src_info->buffered_addr(); - log_as_hex(last_obj_base, dest, last_obj_base + buffer_to_runtime_delta()); - address runtime_dest = dest + buffer_to_runtime_delta(); - int bytes = src_info->size_in_bytes(); - - MetaspaceObj::Type type = src_info->msotype(); - const char* type_name = MetaspaceObj::type_name(type); - - switch (type) { - case MetaspaceObj::ClassType: - log_klass((Klass*)src, runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::ConstantPoolType: - log_klass(((ConstantPool*)src)->pool_holder(), - runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::ConstantPoolCacheType: - log_klass(((ConstantPoolCache*)src)->constant_pool()->pool_holder(), - runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::MethodType: - log_method((Method*)src, runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::ConstMethodType: - log_method(((ConstMethod*)src)->method(), runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::SymbolType: - { - ResourceMark rm(current); - Symbol* s = (Symbol*)src; - log_debug(aot, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes, - s->as_quoted_ascii()); - } - break; - default: - log_debug(aot, map)(_LOG_PREFIX, p2i(runtime_dest), type_name, bytes); - break; - } - - last_obj_base = dest; - last_obj_end = dest + bytes; - } - - log_as_hex(last_obj_base, last_obj_end, last_obj_base + buffer_to_runtime_delta()); - if (last_obj_end < region_end) { - log_debug(aot, map)(PTR_FORMAT ": @@ Misc data %zu bytes", - p2i(last_obj_end + buffer_to_runtime_delta()), - size_t(region_end - last_obj_end)); - log_as_hex(last_obj_end, region_end, last_obj_end + buffer_to_runtime_delta()); - } - } - -#undef _LOG_PREFIX - - // Log information about a region, whose address at dump time is [base .. top). At - // runtime, this region will be mapped to requested_base. requested_base is nullptr if this - // region will be mapped at os-selected addresses (such as the bitmap region), or will - // be accessed with os::read (the header). - // - // Note: across -Xshare:dump runs, base may be different, but requested_base should - // be the same as the archive contents should be deterministic. - static void log_region(const char* name, address base, address top, address requested_base) { - size_t size = top - base; - base = requested_base; - if (requested_base == nullptr) { - top = (address)size; - } else { - top = requested_base + size; - } - log_info(aot, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", - name, p2i(base), p2i(top), size); - } - -#if INCLUDE_CDS_JAVA_HEAP - static void log_heap_region(ArchiveHeapInfo* heap_info) { - MemRegion r = heap_info->buffer_region(); - address start = address(r.start()); // start of the current oop inside the buffer - address end = address(r.end()); - log_region("heap", start, end, ArchiveHeapWriter::buffered_addr_to_requested_addr(start)); - - LogStreamHandle(Info, aot, map) st; - - HeapRootSegments segments = heap_info->heap_root_segments(); - assert(segments.base_offset() == 0, "Sanity"); - - for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) { - address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start); - st.print_cr(PTR_FORMAT ": Heap roots segment [%d]", - p2i(requested_start), segments.size_in_elems(seg_idx)); - start += segments.size_in_bytes(seg_idx); - } - log_heap_roots(); - - while (start < end) { - size_t byte_size; - oop source_oop = ArchiveHeapWriter::buffered_addr_to_source_obj(start); - address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start); - st.print(PTR_FORMAT ": @@ Object ", p2i(requested_start)); - - if (source_oop != nullptr) { - // This is a regular oop that got archived. - // Don't print the requested addr again as we have just printed it at the beginning of the line. - // Example: - // 0x00000007ffd27938: @@ Object (0xfffa4f27) java.util.HashMap - print_oop_info_cr(&st, source_oop, /*print_requested_addr=*/false); - byte_size = source_oop->size() * BytesPerWord; - } else if ((byte_size = ArchiveHeapWriter::get_filler_size_at(start)) > 0) { - // We have a filler oop, which also does not exist in BufferOffsetToSourceObjectTable. - // Example: - // 0x00000007ffc3ffd8: @@ Object filler 40 bytes - st.print_cr("filler %zu bytes", byte_size); - } else { - ShouldNotReachHere(); - } - - address oop_end = start + byte_size; - log_as_hex(start, oop_end, requested_start, /*is_heap=*/true); - - if (source_oop != nullptr) { - log_oop_details(heap_info, source_oop, /*buffered_addr=*/start); - } - start = oop_end; - } - } - - // ArchivedFieldPrinter is used to print the fields of archived objects. We can't - // use _source_obj->print_on(), because we want to print the oop fields - // in _source_obj with their requested addresses using print_oop_info_cr(). - class ArchivedFieldPrinter : public FieldClosure { - ArchiveHeapInfo* _heap_info; - outputStream* _st; - oop _source_obj; - address _buffered_addr; - public: - ArchivedFieldPrinter(ArchiveHeapInfo* heap_info, outputStream* st, oop src_obj, address buffered_addr) : - _heap_info(heap_info), _st(st), _source_obj(src_obj), _buffered_addr(buffered_addr) {} - - void do_field(fieldDescriptor* fd) { - _st->print(" - "); - BasicType ft = fd->field_type(); - switch (ft) { - case T_ARRAY: - case T_OBJECT: - { - fd->print_on(_st); // print just the name and offset - oop obj = _source_obj->obj_field(fd->offset()); - if (java_lang_Class::is_instance(obj)) { - obj = HeapShared::scratch_java_mirror(obj); - } - print_oop_info_cr(_st, obj); - } - break; - default: - if (ArchiveHeapWriter::is_marked_as_native_pointer(_heap_info, _source_obj, fd->offset())) { - print_as_native_pointer(fd); - } else { - fd->print_on_for(_st, cast_to_oop(_buffered_addr)); // name, offset, value - _st->cr(); - } - } - } - - void print_as_native_pointer(fieldDescriptor* fd) { - LP64_ONLY(assert(fd->field_type() == T_LONG, "must be")); - NOT_LP64 (assert(fd->field_type() == T_INT, "must be")); - - // We have a field that looks like an integer, but it's actually a pointer to a MetaspaceObj. - address source_native_ptr = (address) - LP64_ONLY(_source_obj->long_field(fd->offset())) - NOT_LP64( _source_obj->int_field (fd->offset())); - ArchiveBuilder* builder = ArchiveBuilder::current(); - - // The value of the native pointer at runtime. - address requested_native_ptr = builder->to_requested(builder->get_buffered_addr(source_native_ptr)); - - // The address of _source_obj at runtime - oop requested_obj = ArchiveHeapWriter::source_obj_to_requested_obj(_source_obj); - // The address of this field in the requested space - assert(requested_obj != nullptr, "Attempting to load field from null oop"); - address requested_field_addr = cast_from_oop
    (requested_obj) + fd->offset(); - - fd->print_on(_st); - _st->print_cr(PTR_FORMAT " (marked metadata pointer @" PTR_FORMAT " )", - p2i(requested_native_ptr), p2i(requested_field_addr)); - } - }; - - // Print the fields of instanceOops, or the elements of arrayOops - static void log_oop_details(ArchiveHeapInfo* heap_info, oop source_oop, address buffered_addr) { - LogStreamHandle(Trace, aot, map, oops) st; - if (st.is_enabled()) { - Klass* source_klass = source_oop->klass(); - ArchiveBuilder* builder = ArchiveBuilder::current(); - Klass* requested_klass = builder->to_requested(builder->get_buffered_addr(source_klass)); - - st.print(" - klass: "); - source_klass->print_value_on(&st); - st.print(" " PTR_FORMAT, p2i(requested_klass)); - st.cr(); - - if (source_oop->is_typeArray()) { - TypeArrayKlass::cast(source_klass)->oop_print_elements_on(typeArrayOop(source_oop), &st); - } else if (source_oop->is_objArray()) { - objArrayOop source_obj_array = objArrayOop(source_oop); - for (int i = 0; i < source_obj_array->length(); i++) { - st.print(" -%4d: ", i); - oop obj = source_obj_array->obj_at(i); - if (java_lang_Class::is_instance(obj)) { - obj = HeapShared::scratch_java_mirror(obj); - } - print_oop_info_cr(&st, obj); - } - } else { - st.print_cr(" - fields (%zu words):", source_oop->size()); - ArchivedFieldPrinter print_field(heap_info, &st, source_oop, buffered_addr); - InstanceKlass::cast(source_klass)->print_nonstatic_fields(&print_field); - - if (java_lang_Class::is_instance(source_oop)) { - oop scratch_mirror = source_oop; - st.print(" - signature: "); - print_class_signature_for_mirror(&st, scratch_mirror); - st.cr(); - - Klass* src_klass = java_lang_Class::as_Klass(scratch_mirror); - if (src_klass != nullptr && src_klass->is_instance_klass()) { - oop rr = HeapShared::scratch_resolved_references(InstanceKlass::cast(src_klass)->constants()); - st.print(" - archived_resolved_references: "); - print_oop_info_cr(&st, rr); - - // We need to print the fields in the scratch_mirror, not the original mirror. - // (if a class is not aot-initialized, static fields in its scratch mirror will be cleared). - assert(scratch_mirror == HeapShared::scratch_java_mirror(src_klass->java_mirror()), "sanity"); - st.print_cr("- ---- static fields (%d):", java_lang_Class::static_oop_field_count(scratch_mirror)); - InstanceKlass::cast(src_klass)->do_local_static_fields(&print_field); - } - } - } - } - } - - static void print_class_signature_for_mirror(outputStream* st, oop scratch_mirror) { - assert(java_lang_Class::is_instance(scratch_mirror), "sanity"); - if (java_lang_Class::is_primitive(scratch_mirror)) { - for (int i = T_BOOLEAN; i < T_VOID+1; i++) { - BasicType bt = (BasicType)i; - if (!is_reference_type(bt) && scratch_mirror == HeapShared::scratch_java_mirror(bt)) { - oop orig_mirror = Universe::java_mirror(bt); - java_lang_Class::print_signature(orig_mirror, st); - return; - } - } - ShouldNotReachHere(); - } - java_lang_Class::print_signature(scratch_mirror, st); - } - - static void log_heap_roots() { - LogStreamHandle(Trace, aot, map, oops) st; - if (st.is_enabled()) { - for (int i = 0; i < HeapShared::pending_roots()->length(); i++) { - st.print("roots[%4d]: ", i); - print_oop_info_cr(&st, HeapShared::pending_roots()->at(i)); - } - } - } - - // Example output: - // - The first number is the requested address (if print_requested_addr == true) - // - The second number is the narrowOop version of the requested address (if UseCompressedOops == true) - // 0x00000007ffc7e840 (0xfff8fd08) java.lang.Class Ljava/util/Array; - // 0x00000007ffc000f8 (0xfff8001f) [B length: 11 - static void print_oop_info_cr(outputStream* st, oop source_oop, bool print_requested_addr = true) { - if (source_oop == nullptr) { - st->print_cr("null"); - } else { - ResourceMark rm; - oop requested_obj = ArchiveHeapWriter::source_obj_to_requested_obj(source_oop); - if (print_requested_addr) { - st->print(PTR_FORMAT " ", p2i(requested_obj)); - } - if (UseCompressedOops) { - st->print("(0x%08x) ", CompressedOops::narrow_oop_value(requested_obj)); - } - if (source_oop->is_array()) { - int array_len = arrayOop(source_oop)->length(); - st->print_cr("%s length: %d", source_oop->klass()->external_name(), array_len); - } else { - st->print("%s", source_oop->klass()->external_name()); - - if (java_lang_String::is_instance(source_oop)) { - st->print(" "); - java_lang_String::print(source_oop, st); - } else if (java_lang_Class::is_instance(source_oop)) { - oop scratch_mirror = source_oop; - - st->print(" "); - print_class_signature_for_mirror(st, scratch_mirror); - - Klass* src_klass = java_lang_Class::as_Klass(scratch_mirror); - if (src_klass != nullptr && src_klass->is_instance_klass()) { - InstanceKlass* buffered_klass = - ArchiveBuilder::current()->get_buffered_addr(InstanceKlass::cast(src_klass)); - if (buffered_klass->has_aot_initialized_mirror()) { - st->print(" (aot-inited)"); - } - } - } - st->cr(); - } - } - } -#endif // INCLUDE_CDS_JAVA_HEAP - - // Log all the data [base...top). Pretend that the base address - // will be mapped to requested_base at run-time. - static void log_as_hex(address base, address top, address requested_base, bool is_heap = false) { - assert(top >= base, "must be"); - - LogStreamHandle(Trace, aot, map) lsh; - if (lsh.is_enabled()) { - int unitsize = sizeof(address); - if (is_heap && UseCompressedOops) { - // This makes the compressed oop pointers easier to read, but - // longs and doubles will be split into two words. - unitsize = sizeof(narrowOop); - } - os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base); - } - } - - static void log_header(FileMapInfo* mapinfo) { - LogStreamHandle(Info, aot, map) lsh; - if (lsh.is_enabled()) { - mapinfo->print(&lsh); - } - } - -public: - static void log(ArchiveBuilder* builder, FileMapInfo* mapinfo, - ArchiveHeapInfo* heap_info, - char* bitmap, size_t bitmap_size_in_bytes) { - log_info(aot, map)("%s CDS archive map for %s", CDSConfig::is_dumping_static_archive() ? "Static" : "Dynamic", mapinfo->full_path()); - - address header = address(mapinfo->header()); - address header_end = header + mapinfo->header()->header_size(); - log_region("header", header, header_end, nullptr); - log_header(mapinfo); - log_as_hex(header, header_end, nullptr); - - DumpRegion* rw_region = &builder->_rw_region; - DumpRegion* ro_region = &builder->_ro_region; - - log_metaspace_region("rw region", rw_region, &builder->_rw_src_objs); - log_metaspace_region("ro region", ro_region, &builder->_ro_src_objs); - - address bitmap_end = address(bitmap + bitmap_size_in_bytes); - log_region("bitmap", address(bitmap), bitmap_end, nullptr); - log_as_hex((address)bitmap, bitmap_end, nullptr); - -#if INCLUDE_CDS_JAVA_HEAP - if (heap_info->is_used()) { - log_heap_region(heap_info); - } -#endif - - log_info(aot, map)("[End of CDS archive map]"); - } -}; // end ArchiveBuilder::CDSMapLogger - void ArchiveBuilder::print_stats() { _alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used())); } @@ -1645,8 +1226,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i } if (log_is_enabled(Info, aot, map)) { - CDSMapLogger::log(this, mapinfo, heap_info, - bitmap, bitmap_size_in_bytes); + AOTMapLogger::dumptime_log(this, mapinfo, heap_info, bitmap, bitmap_size_in_bytes); } CDS_JAVA_HEAP_ONLY(HeapShared::destroy_archived_object_cache()); FREE_C_HEAP_ARRAY(char, bitmap); diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index 39cc1c1eb8c..170e61beba8 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -93,6 +93,8 @@ constexpr size_t SharedSpaceObjectAlignment = Metaspace::min_allocation_alignmen // buffered_address + _buffer_to_requested_delta == requested_address // class ArchiveBuilder : public StackObj { + friend class AOTMapLogger; + protected: DumpRegion* _current_dump_region; address _buffer_bottom; // for writing the contents of rw/ro regions @@ -202,8 +204,6 @@ private: SourceObjInfo* at(int i) const { return objs()->at(i); } }; - class CDSMapLogger; - static const int INITIAL_TABLE_SIZE = 15889; static const int MAX_TABLE_SIZE = 1000000; @@ -316,6 +316,12 @@ public: return (T)(address(obj) + _buffer_to_requested_delta); } + template T requested_to_buffered(T obj) const { + T b = (T)(address(obj) - _buffer_to_requested_delta); + assert(is_in_buffer_space(b), "must be"); + return b; + } + static intx get_buffer_to_requested_delta() { return current()->buffer_to_requested_delta(); } diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 9c55b71a1b2..c7750c70f1b 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -162,6 +162,44 @@ oop ArchiveHeapWriter::buffered_addr_to_source_obj(address buffered_addr) { } } +Klass* ArchiveHeapWriter::real_klass_of_buffered_oop(address buffered_addr) { + oop p = buffered_addr_to_source_obj(buffered_addr); + if (p != nullptr) { + return p->klass(); + } else if (get_filler_size_at(buffered_addr) > 0) { + return Universe::fillerArrayKlass(); + } else { + // This is one of the root segments + return Universe::objectArrayKlass(); + } +} + +size_t ArchiveHeapWriter::size_of_buffered_oop(address buffered_addr) { + oop p = buffered_addr_to_source_obj(buffered_addr); + if (p != nullptr) { + return p->size(); + } + + size_t nbytes = get_filler_size_at(buffered_addr); + if (nbytes > 0) { + assert((nbytes % BytesPerWord) == 0, "should be aligned"); + return nbytes / BytesPerWord; + } + + address hrs = buffer_bottom(); + for (size_t seg_idx = 0; seg_idx < _heap_root_segments.count(); seg_idx++) { + nbytes = _heap_root_segments.size_in_bytes(seg_idx); + if (hrs == buffered_addr) { + assert((nbytes % BytesPerWord) == 0, "should be aligned"); + return nbytes / BytesPerWord; + } + hrs += nbytes; + } + + ShouldNotReachHere(); + return 0; +} + address ArchiveHeapWriter::buffered_addr_to_requested_addr(address buffered_addr) { return _requested_bottom + buffered_address_to_offset(buffered_addr); } @@ -709,27 +747,6 @@ void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) { } } -// Do we have a jlong/jint field that's actually a pointer to a MetaspaceObj? -bool ArchiveHeapWriter::is_marked_as_native_pointer(ArchiveHeapInfo* heap_info, oop src_obj, int field_offset) { - HeapShared::CachedOopInfo* p = HeapShared::archived_object_cache()->get(src_obj); - assert(p != nullptr, "must be"); - - // requested_field_addr = the address of this field in the requested space - oop requested_obj = requested_obj_from_buffer_offset(p->buffer_offset()); - Metadata** requested_field_addr = (Metadata**)(cast_from_oop
    (requested_obj) + field_offset); - assert((Metadata**)_requested_bottom <= requested_field_addr && requested_field_addr < (Metadata**) _requested_top, "range check"); - - BitMap::idx_t idx = requested_field_addr - (Metadata**) _requested_bottom; - // Leading zeros have been removed so some addresses may not be in the ptrmap - size_t start_pos = FileMapInfo::current_info()->heap_ptrmap_start_pos(); - if (idx < start_pos) { - return false; - } else { - idx -= start_pos; - } - return (idx < heap_info->ptrmap()->size()) && (heap_info->ptrmap()->at(idx) == true); -} - void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) { int num_non_null_ptrs = 0; Metadata** bottom = (Metadata**) _requested_bottom; diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index f8f55a745ee..18e647912f1 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -236,11 +236,11 @@ public: static size_t get_filler_size_at(address buffered_addr); static void mark_native_pointer(oop src_obj, int offset); - static bool is_marked_as_native_pointer(ArchiveHeapInfo* heap_info, oop src_obj, int field_offset); static oop source_obj_to_requested_obj(oop src_obj); static oop buffered_addr_to_source_obj(address buffered_addr); static address buffered_addr_to_requested_addr(address buffered_addr); - + static Klass* real_klass_of_buffered_oop(address buffered_addr); + static size_t size_of_buffered_oop(address buffered_addr); }; #endif // INCLUDE_CDS_JAVA_HEAP #endif // SHARE_CDS_ARCHIVEHEAPWRITER_HPP diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 51899490a12..6922b66d7cd 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotLogging.hpp" +#include "cds/aotMapLogger.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" @@ -104,6 +105,8 @@ void CDSConfig::ergo_initialize() { if (!is_dumping_heap()) { _is_dumping_full_module_graph = false; } + + AOTMapLogger::ergo_initialize(); } const char* CDSConfig::default_archive_path() { diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 5c55dea52c8..4d8f2b50017 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -29,6 +29,7 @@ #include "cds/aotConstantPoolResolver.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMapLogger.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" @@ -325,6 +326,24 @@ void MetaspaceShared::initialize_for_static_dump() { // Called by universe_post_init() void MetaspaceShared::post_initialize(TRAPS) { if (CDSConfig::is_using_archive()) { + FileMapInfo *static_mapinfo = FileMapInfo::current_info(); + FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); + + if (AOTMapLogger::is_logging_at_bootstrap()) { + // The map logging needs to be done here, as it requires some stubs on Windows, + // which are not generated until the end of init_globals(). + AOTMapLogger::runtime_log(static_mapinfo, dynamic_mapinfo); + } + + // Close any open file descriptors. However, mmap'ed pages will remain in memory. + static_mapinfo->close(); + static_mapinfo->unmap_region(MetaspaceShared::bm); + + if (dynamic_mapinfo != nullptr) { + dynamic_mapinfo->close(); + dynamic_mapinfo->unmap_region(MetaspaceShared::bm); + } + int size = AOTClassLocationConfig::runtime()->length(); if (size > 0) { CDSProtectionDomain::allocate_shared_data_arrays(size, CHECK); @@ -1954,6 +1973,7 @@ class CountSharedSymbols : public SymbolClosure { void MetaspaceShared::initialize_shared_spaces() { FileMapInfo *static_mapinfo = FileMapInfo::current_info(); + FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); // Verify various attributes of the archive, plus initialize the // shared string/symbol tables. @@ -1969,19 +1989,11 @@ void MetaspaceShared::initialize_shared_spaces() { Universe::load_archived_object_instances(); AOTCodeCache::initialize(); - // Close the mapinfo file - static_mapinfo->close(); - - static_mapinfo->unmap_region(MetaspaceShared::bm); - - FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); if (dynamic_mapinfo != nullptr) { intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data(); ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress); ArchiveBuilder::serialize_dynamic_archivable_items(&rc); DynamicArchive::setup_array_klasses(); - dynamic_mapinfo->close(); - dynamic_mapinfo->unmap_region(MetaspaceShared::bm); } LogStreamHandle(Info, aot) lsh; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 1845c28d819..1be7a6db662 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1179,6 +1179,12 @@ const char* SystemDictionaryShared::loader_type_for_shared_class(Klass* k) { } } +void SystemDictionaryShared::get_all_archived_classes(bool is_static_archive, GrowableArray* classes) { + get_archive(is_static_archive)->_builtin_dictionary.iterate([&] (const RunTimeClassInfo* record) { + classes->append(record->klass()); + }); +} + class SharedDictionaryPrinter : StackObj { outputStream* _st; int _index; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 5f6dd055fd6..e3c22ee11a0 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -115,6 +115,8 @@ class DumpTimeSharedClassTable; class RunTimeClassInfo; class RunTimeSharedDictionary; +template class GrowableArray; + class SharedClassLoadingMark { private: Thread* THREAD; @@ -269,6 +271,7 @@ public: bool is_static_archive = true); static void serialize_vm_classes(class SerializeClosure* soc); static const char* loader_type_for_shared_class(Klass* k); + static void get_all_archived_classes(bool is_static_archive, GrowableArray* classes); static void print() { return print_on(tty); } static void print_on(outputStream* st) NOT_CDS_RETURN; static void print_shared_archive(outputStream* st, bool is_static = true) NOT_CDS_RETURN; diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 83af4b88e32..e9e4f9a40e5 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -111,6 +111,7 @@ class ConstantPoolCache: public MetaspaceObj { oop archived_references() NOT_CDS_JAVA_HEAP_RETURN_(nullptr); void clear_archived_references() NOT_CDS_JAVA_HEAP_RETURN; + CDS_JAVA_HEAP_ONLY(int archived_references_index() { return _archived_references_index; }) inline objArrayOop resolved_references(); void set_resolved_references(OopHandle s) { _resolved_references = s; } diff --git a/src/hotspot/share/oops/objArrayOop.hpp b/src/hotspot/share/oops/objArrayOop.hpp index 8e39b897018..0539171f1ab 100644 --- a/src/hotspot/share/oops/objArrayOop.hpp +++ b/src/hotspot/share/oops/objArrayOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ class objArrayOopDesc : public arrayOopDesc { friend class Continuation; template friend class RawOopWriter; + friend class AOTMapLogger; template T* obj_at_addr(int index) const; diff --git a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java index 5a5978a8633..c93b16c68b8 100644 --- a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java @@ -25,6 +25,7 @@ * @test * @bug 8308903 * @summary Test the contents of -Xlog:aot+map + * @requires vm.flagless * @requires vm.cds * @library /test/lib * @run driver CDSMapTest @@ -33,6 +34,8 @@ import jdk.test.lib.cds.CDSOptions; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; import java.util.ArrayList; public class CDSMapTest { @@ -46,34 +49,57 @@ public class CDSMapTest { } public static void doTest(boolean compressed) throws Exception { - ArrayList dumpArgs = new ArrayList<>(); + ArrayList vmArgs = new ArrayList<>(); // Use the same heap size as make/Images.gmk - dumpArgs.add("-Xmx128M"); + vmArgs.add("-Xmx128M"); if (Platform.is64bit()) { // These options are available only on 64-bit. String sign = (compressed) ? "+" : "-"; - dumpArgs.add("-XX:" + sign + "UseCompressedOops"); + vmArgs.add("-XX:" + sign + "UseCompressedOops"); } - dump(dumpArgs); + String archiveFile = dump(vmArgs); + exec(vmArgs, archiveFile); + } static int id = 0; - static void dump(ArrayList args, String... more) throws Exception { + + // Create a map file when creating the archive + static String dump(ArrayList args) throws Exception { String logName = "SharedArchiveFile" + (id++); String archiveName = logName + ".jsa"; String mapName = logName + ".map"; CDSOptions opts = (new CDSOptions()) .addPrefix("-Xlog:cds=debug") + // filesize=0 ensures that a large map file not broken up in multiple files. .addPrefix("-Xlog:aot+map=debug,aot+map+oops=trace:file=" + mapName + ":none:filesize=0") .setArchiveName(archiveName) - .addSuffix(args) - .addSuffix(more); + .addSuffix(args); CDSTestUtils.createArchiveAndCheck(opts); CDSMapReader.MapFile mapFile = CDSMapReader.read(mapName); CDSMapReader.validate(mapFile); + + return archiveName; + } + + // Create a map file when using the archive + static void exec(ArrayList vmArgs, String archiveFile) throws Exception { + String mapName = archiveFile + ".exec.map"; + vmArgs.add("-XX:SharedArchiveFile=" + archiveFile); + vmArgs.add("-Xlog:cds=debug"); + vmArgs.add("-Xshare:on"); + vmArgs.add("-Xlog:aot+map=debug,aot+map+oops=trace:file=" + mapName + ":none:filesize=0"); + vmArgs.add("--version"); + String[] cmdLine = vmArgs.toArray(new String[vmArgs.size()]); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(cmdLine); + OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "exec"); + out.shouldHaveExitValue(0); + + CDSMapReader.MapFile mapFile = CDSMapReader.read(mapName); + CDSMapReader.validate(mapFile); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java new file mode 100644 index 00000000000..f544b5653b7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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=aot + * @bug 8362566 + * @summary Test the contents of -Xlog:aot+map with AOT workflow + * @requires vm.flagless + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib /test/hotspot/jtreg/runtime/cds + * @build AOTMapTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar AOTMapTestApp + * @run driver AOTMapTest AOT --two-step-training + */ + +/** + * @test id=dynamic + * @bug 8362566 + * @summary Test the contents of -Xlog:aot+map with AOT workflow + * @requires vm.flagless + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib /test/hotspot/jtreg/runtime/cds + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @build AOTMapTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar AOTMapTestApp + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. AOTMapTest DYNAMIC + */ + + +import java.util.ArrayList; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.Platform; + +public class AOTMapTest { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "AOTMapTestApp"; + + public static void main(String[] args) throws Exception { + doTest(args, false); + + if (Platform.is64bit()) { + // There's no oop/klass compression on 32-bit. + doTest(args, true); + } + } + + public static void doTest(String[] args, boolean compressed) throws Exception { + Tester tester = new Tester(compressed); + tester.run(args); + + validate(tester.dumpMapFile); + validate(tester.runMapFile); + } + + static void validate(String mapFileName) { + CDSMapReader.MapFile mapFile = CDSMapReader.read(mapFileName); + CDSMapReader.validate(mapFile); + } + + static class Tester extends CDSAppTester { + boolean compressed; + String dumpMapFile; + String runMapFile; + + public Tester(boolean compressed) { + super(mainClass); + this.compressed = compressed; + + dumpMapFile = "test" + (compressed ? "0" : "1") + ".dump.aotmap"; + runMapFile = "test" + (compressed ? "0" : "1") + ".run.aotmap"; + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + ArrayList vmArgs = new ArrayList<>(); + + vmArgs.add("-Xmx128M"); + vmArgs.add("-Xlog:aot=debug"); + + if (Platform.is64bit()) { + // These options are available only on 64-bit. + String sign = (compressed) ? "+" : "-"; + vmArgs.add("-XX:" + sign + "UseCompressedOops"); + } + + // filesize=0 ensures that a large map file not broken up in multiple files. + String logMapPrefix = "-Xlog:aot+map=debug,aot+map+oops=trace:file="; + String logMapSuffix = ":none:filesize=0"; + + if (runMode == RunMode.ASSEMBLY || runMode == RunMode.DUMP_DYNAMIC) { + vmArgs.add(logMapPrefix + dumpMapFile + logMapSuffix); + } else if (runMode == RunMode.PRODUCTION) { + vmArgs.add(logMapPrefix + runMapFile + logMapSuffix); + } + + return vmArgs.toArray(new String[vmArgs.size()]); + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + }; + } + } +} + +class AOTMapTestApp { + public static void main(String[] args) { + System.out.println("Hello AOTMapTestApp"); + } +} From 88c39793670f2d36490530993feb60e138f43a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Wed, 27 Aug 2025 07:55:57 +0000 Subject: [PATCH 011/295] 8365256: RelocIterator should use indexes instead of pointers Reviewed-by: kvn, dlong --- src/hotspot/share/code/codeBlob.cpp | 30 ++++++--------- src/hotspot/share/code/nmethod.cpp | 20 +++++----- src/hotspot/share/code/relocInfo.cpp | 55 +++++++++++++++------------- src/hotspot/share/code/relocInfo.hpp | 28 +++++++------- 4 files changed, 64 insertions(+), 69 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 9ec5478a071..6d34204d074 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -128,7 +128,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size int mutable_data_size) : _oop_maps(nullptr), // will be set by set_oop_maps() call _name(name), - _mutable_data(header_begin() + size), // default value is blob_end() + _mutable_data(nullptr), _size(size), _relocation_size(align_up(cb->total_relocation_size(), oopSize)), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -158,10 +158,8 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } - } else { - // We need unique and valid not null address - assert(_mutable_data == blob_end(), "sanity"); } + assert(_mutable_data != nullptr || _mutable_data_size == 0, "No mutable data => mutable data size is 0"); set_oop_maps(oop_maps); } @@ -170,7 +168,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size) : _oop_maps(nullptr), _name(name), - _mutable_data(header_begin() + size), // default value is blob_end() + _mutable_data(nullptr), _size(size), _relocation_size(0), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -184,9 +182,9 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade _kind(kind), _caller_must_gc_arguments(false) { + assert(_mutable_data == nullptr && _mutable_data_size == 0, "invariant"); assert(is_aligned(size, oopSize), "unaligned size"); assert(is_aligned(header_size, oopSize), "unaligned size"); - assert(_mutable_data == blob_end(), "sanity"); } void CodeBlob::restore_mutable_data(address reloc_data) { @@ -197,7 +195,7 @@ void CodeBlob::restore_mutable_data(address reloc_data) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } } else { - _mutable_data = blob_end(); // default value + _mutable_data = nullptr; } if (_relocation_size > 0) { assert(_mutable_data_size > 0, "relocation is part of mutable data section"); @@ -206,17 +204,13 @@ void CodeBlob::restore_mutable_data(address reloc_data) { } void CodeBlob::purge() { - assert(_mutable_data != nullptr, "should never be null"); - if (_mutable_data != blob_end()) { - os::free(_mutable_data); - _mutable_data = blob_end(); // Valid not null address - _mutable_data_size = 0; - _relocation_size = 0; - } - if (_oop_maps != nullptr) { - delete _oop_maps; - _oop_maps = nullptr; - } + os::free(_mutable_data); + _mutable_data = nullptr; + _mutable_data_size = 0; + delete _oop_maps; + _oop_maps = nullptr; + _relocation_size = 0; + NOT_PRODUCT(_asm_remarks.clear()); NOT_PRODUCT(_dbg_strings.clear()); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index b8b3a70bf58..a45ca141455 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1327,8 +1327,8 @@ nmethod::nmethod( "wrong mutable data size: %d != %d + %d", _mutable_data_size, _relocation_size, metadata_size); - // native wrapper does not have read-only data but we need unique not null address - _immutable_data = blob_end(); + // native wrapper does not have read-only data + _immutable_data = nullptr; _immutable_data_size = 0; _nul_chk_table_offset = 0; _handler_table_offset = 0; @@ -1510,8 +1510,7 @@ nmethod::nmethod( assert(immutable_data != nullptr, "required"); _immutable_data = immutable_data; } else { - // We need unique not null address - _immutable_data = blob_end(); + _immutable_data = nullptr; } CHECKED_CAST(_nul_chk_table_offset, uint16_t, (align_up((int)dependencies->size_in_bytes(), oopSize))); CHECKED_CAST(_handler_table_offset, uint16_t, (_nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize))); @@ -2147,15 +2146,14 @@ void nmethod::purge(bool unregister_nmethod) { delete ec; ec = next; } - if (_pc_desc_container != nullptr) { - delete _pc_desc_container; - } + + delete _pc_desc_container; delete[] _compiled_ic_data; - if (_immutable_data != blob_end()) { - os::free(_immutable_data); - _immutable_data = blob_end(); // Valid not null address - } + os::free(_immutable_data); + _immutable_data = nullptr; + _immutable_data_size = 0; + if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 8fc22596d01..fb24844000d 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -116,9 +116,6 @@ void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, re // ---------------------------------------------------------------------------------------------------- // Implementation of RelocIterator -// A static dummy to serve as a safe pointer when there is no relocation info. -static relocInfo dummy_relocInfo = relocInfo(relocInfo::none, 0); - void RelocIterator::initialize(nmethod* nm, address begin, address limit) { initialize_misc(); @@ -130,14 +127,9 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { guarantee(nm != nullptr, "must be able to deduce nmethod from other arguments"); _code = nm; - if (nm->relocation_size() == 0) { - _current = &dummy_relocInfo - 1; - _end = &dummy_relocInfo; - } else { - assert(((nm->relocation_begin() != nullptr) && (nm->relocation_end() != nullptr)), "valid start and end pointer"); - _current = nm->relocation_begin() - 1; - _end = nm->relocation_end(); - } + _base = nm->relocation_begin(); + _current = -1; + _len = nm->relocation_end() - _base; _addr = nm->content_begin(); // Initialize code sections. @@ -156,11 +148,21 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { } +RelocIterator::RelocIterator(relocInfo& ri) { + initialize_misc(); + _base = &ri; + _len = 1; + _current = -1; + _limit = nullptr; + _addr = 0; +} + RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { initialize_misc(); assert(((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr)), "valid start and end pointer"); - _current = cs->locs_start() - 1; - _end = cs->locs_end(); + _base = cs->locs_start(); + _len = cs->locs_end() - _base; + _current = -1; _addr = cs->start(); _code = nullptr; // Not cb->blob(); @@ -186,8 +188,9 @@ RelocIterator::RelocIterator(CodeBlob* cb) { } else { _code = nullptr; } - _current = cb->relocation_begin() - 1; - _end = cb->relocation_end(); + _base = cb->relocation_begin(); + _len = cb->relocation_end() - _base; + _current = -1; _addr = cb->content_begin(); _section_start[CodeBuffer::SECT_CONSTS] = cb->content_begin(); @@ -216,7 +219,7 @@ void RelocIterator::set_limits(address begin, address limit) { // the limit affects this next stuff: if (begin != nullptr) { - relocInfo* backup; + int backup; address backup_addr; while (true) { backup = _current; @@ -238,12 +241,12 @@ void RelocIterator::set_limits(address begin, address limit) { // very efficiently (a single extra halfword). Larger chunks of // relocation data need a halfword header to hold their size. void RelocIterator::advance_over_prefix() { - if (_current->is_datalen()) { - _data = (short*) _current->data(); - _datalen = _current->datalen(); + if (current()->is_datalen()) { + _data = (short*) current()->data(); + _datalen = current()->datalen(); _current += _datalen + 1; // skip the embedded data & header } else { - _databuf = _current->immediate(); + _databuf = current()->immediate(); _data = &_databuf; _datalen = 1; _current++; // skip the header @@ -350,9 +353,9 @@ void Relocation::const_verify_data_value(address x) { RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; - relocInfo ri = relocInfo(rtype, 0); - RelocIterator itr; - itr.set_current(ri); + relocInfo ri(rtype, 0); + RelocIterator itr(ri); + itr.next(); itr.reloc(); return itr._rh; } @@ -839,7 +842,7 @@ void RelocIterator::print_current_on(outputStream* st) { return; } st->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - p2i(_current), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); + p2i(current()), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), current()->addr_offset()); if (current()->format() != 0) st->print(" format=%d", current()->format()); if (datalen() == 1) { @@ -990,7 +993,7 @@ void RelocIterator::print_current_on(outputStream* st) { void RelocIterator::print_on(outputStream* st) { RelocIterator save_this = (*this); - relocInfo* scan = _current; + relocInfo* scan = current_no_check(); if (!has_current()) scan += 1; // nothing to scan here! bool skip_next = has_current(); @@ -1000,7 +1003,7 @@ void RelocIterator::print_on(outputStream* st) { skip_next = false; st->print(" @" INTPTR_FORMAT ": ", p2i(scan)); - relocInfo* newscan = _current+1; + relocInfo* newscan = current_no_check()+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { st->print("%04x", *(short*)scan & 0xFFFF); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 714a964b28d..58dbf61abbe 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -562,12 +562,13 @@ class RelocIterator : public StackObj { private: address _limit; // stop producing relocations after this _addr - relocInfo* _current; // the current relocation information - relocInfo* _end; // end marker; we're done iterating when _current == _end + relocInfo* _base; // base pointer into relocInfo array + int _current; // current index + int _len; // length nmethod* _code; // compiled method containing _addr address _addr; // instruction to which the relocation applies - short _databuf; // spare buffer for compressed data short* _data; // pointer to the relocation's data + short _databuf; // spare buffer for compressed data short _datalen; // number of halfwords in _data // Base addresses needed to compute targets of section_word_type relocs. @@ -578,15 +579,14 @@ class RelocIterator : public StackObj { _datalen = !b ? -1 : 0; DEBUG_ONLY(_data = nullptr); } - void set_current(relocInfo& ri) { - _current = &ri; - set_has_current(true); - } RelocationHolder _rh; // where the current relocation is allocated - relocInfo* current() const { assert(has_current(), "must have current"); - return _current; } + relocInfo* current_no_check() const { return &_base[_current]; } + relocInfo* current() const { + assert(has_current(), "must have current"); + return current_no_check(); + } void set_limits(address begin, address limit); @@ -597,6 +597,7 @@ class RelocIterator : public StackObj { void initialize(nmethod* nm, address begin, address limit); RelocIterator() { initialize_misc(); } + RelocIterator(relocInfo& ri); public: // constructor @@ -607,25 +608,24 @@ class RelocIterator : public StackObj { // get next reloc info, return !eos bool next() { _current++; - assert(_current <= _end, "must not overrun relocInfo"); - if (_current == _end) { + assert(_current <= _len, "must not overrun relocInfo"); + if (_current == _len) { set_has_current(false); return false; } set_has_current(true); - if (_current->is_prefix()) { + if (current()->is_prefix()) { advance_over_prefix(); assert(!current()->is_prefix(), "only one prefix at a time"); } - _addr += _current->addr_offset(); + _addr += current()->addr_offset(); if (_limit != nullptr && _addr >= _limit) { set_has_current(false); return false; } - return true; } From b39c73696d0421b218e301403d589af5a91b037f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 27 Aug 2025 09:08:13 +0000 Subject: [PATCH 012/295] 8359683: ZGC: NUMA-Aware Relocation Reviewed-by: aboldtch, sjohanss --- src/hotspot/share/gc/z/zArray.hpp | 4 + src/hotspot/share/gc/z/zArray.inline.hpp | 14 ++ src/hotspot/share/gc/z/zForwarding.hpp | 5 +- src/hotspot/share/gc/z/zForwarding.inline.hpp | 7 +- src/hotspot/share/gc/z/zHeap.cpp | 4 +- src/hotspot/share/gc/z/zHeap.hpp | 2 +- src/hotspot/share/gc/z/zHeuristics.cpp | 9 +- src/hotspot/share/gc/z/zObjectAllocator.cpp | 2 +- src/hotspot/share/gc/z/zPage.inline.hpp | 1 + src/hotspot/share/gc/z/zPageAllocator.cpp | 30 ++- src/hotspot/share/gc/z/zPageAllocator.hpp | 3 +- src/hotspot/share/gc/z/zRelocate.cpp | 218 ++++++++++++------ src/hotspot/share/gc/z/zRelocate.hpp | 28 ++- src/hotspot/share/gc/z/zRelocationSet.hpp | 5 +- .../share/gc/z/zRelocationSet.inline.hpp | 10 +- 15 files changed, 244 insertions(+), 98 deletions(-) diff --git a/src/hotspot/share/gc/z/zArray.hpp b/src/hotspot/share/gc/z/zArray.hpp index 1b7e99b3ace..9ef911bb1b5 100644 --- a/src/hotspot/share/gc/z/zArray.hpp +++ b/src/hotspot/share/gc/z/zArray.hpp @@ -91,6 +91,10 @@ public: ZArrayIteratorImpl(const ZArray* array); bool next(T* elem); + + template + bool next_if(T* elem, Function predicate, Args&&... args); + bool next_index(size_t* index); T index_to_elem(size_t index); diff --git a/src/hotspot/share/gc/z/zArray.inline.hpp b/src/hotspot/share/gc/z/zArray.inline.hpp index 547a73ffc0d..bf606a88e68 100644 --- a/src/hotspot/share/gc/z/zArray.inline.hpp +++ b/src/hotspot/share/gc/z/zArray.inline.hpp @@ -161,6 +161,20 @@ inline bool ZArrayIteratorImpl::next(T* elem) { return false; } +template +template +inline bool ZArrayIteratorImpl::next_if(T* elem, Function predicate, Args&&... args) { + size_t index; + while (next_index(&index)) { + if (predicate(index_to_elem(index), args...)) { + *elem = index_to_elem(index); + return true; + } + } + + return false; +} + template inline bool ZArrayIteratorImpl::next_index(size_t* index) { if (Parallel) { diff --git a/src/hotspot/share/gc/z/zForwarding.hpp b/src/hotspot/share/gc/z/zForwarding.hpp index c58c479984f..29b5cf4aabe 100644 --- a/src/hotspot/share/gc/z/zForwarding.hpp +++ b/src/hotspot/share/gc/z/zForwarding.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +59,7 @@ private: const size_t _object_alignment_shift; const AttachedArray _entries; ZPage* const _page; + const uint32_t _partition_id; const ZPageAge _from_age; const ZPageAge _to_age; volatile bool _claimed; @@ -108,6 +109,8 @@ public: size_t size() const; size_t object_alignment_shift() const; + uint32_t partition_id() const; + bool is_promotion() const; // Visit from-objects diff --git a/src/hotspot/share/gc/z/zForwarding.inline.hpp b/src/hotspot/share/gc/z/zForwarding.inline.hpp index eb5f4a36161..43558018793 100644 --- a/src/hotspot/share/gc/z/zForwarding.inline.hpp +++ b/src/hotspot/share/gc/z/zForwarding.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +61,7 @@ inline ZForwarding::ZForwarding(ZPage* page, ZPageAge to_age, size_t nentries) _object_alignment_shift(page->object_alignment_shift()), _entries(nentries), _page(page), + _partition_id(page->single_partition_id()), _from_age(page->age()), _to_age(to_age), _claimed(false), @@ -102,6 +103,10 @@ inline size_t ZForwarding::object_alignment_shift() const { return _object_alignment_shift; } +inline uint32_t ZForwarding::partition_id() const { + return _partition_id; +} + inline bool ZForwarding::is_promotion() const { return _from_age != ZPageAge::old && _to_age == ZPageAge::old; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index e43336c8ea3..44e5974993e 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -250,8 +250,8 @@ void ZHeap::account_undo_alloc_page(ZPage* page) { p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); } -ZPage* ZHeap::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { - ZPage* const page = _page_allocator.alloc_page(type, size, flags, age); +ZPage* ZHeap::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition) { + ZPage* const page = _page_allocator.alloc_page(type, size, flags, age, preferred_partition); if (page != nullptr) { // Insert page table entry _page_table.insert(page); diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index f7d606fc260..64ebc253b26 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -108,7 +108,7 @@ public: void mark_flush(Thread* thread); // Page allocation - ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); + ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition); void undo_alloc_page(ZPage* page); void free_page(ZPage* page); size_t free_empty_pages(ZGenerationId id, const ZArray* pages); diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp index fac5fca080d..ccd31ee1749 100644 --- a/src/hotspot/share/gc/z/zHeuristics.cpp +++ b/src/hotspot/share/gc/z/zHeuristics.cpp @@ -26,6 +26,7 @@ #include "gc/z/zCPU.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zHeuristics.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" @@ -58,9 +59,11 @@ void ZHeuristics::set_medium_page_size() { } size_t ZHeuristics::relocation_headroom() { - // Calculate headroom needed to avoid in-place relocation. Each worker will try - // to allocate a small page, and all workers will share a single medium page. - return (ConcGCThreads * ZPageSizeSmall) + ZPageSizeMediumMax; + // Calculate headroom needed to avoid in-place relocation. For each NUMA node, + // each worker will try to allocate a small page, and all workers will share a + // single medium page. + const size_t per_numa_headroom = (ConcGCThreads * ZPageSizeSmall) + ZPageSizeMediumMax; + return per_numa_headroom * ZNUMA::count(); } bool ZHeuristics::use_per_cpu_shared_small_pages() { diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index c6dd0a1a152..63e7f2b4ae9 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -53,7 +53,7 @@ ZPage* const* ZObjectAllocator::PerAge::shared_small_page_addr() const { } ZPage* ZObjectAllocator::PerAge::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags) { - return ZHeap::heap()->alloc_page(type, size, flags, _age); + return ZHeap::heap()->alloc_page(type, size, flags, _age, ZNUMA::id()); } void ZObjectAllocator::PerAge::undo_alloc_page(ZPage* page) { diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index f6c2029ac06..f9a0dbf328d 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -157,6 +157,7 @@ inline const ZVirtualMemory& ZPage::virtual_memory() const { } inline uint32_t ZPage::single_partition_id() const { + assert(!is_multi_partition(), "Don't fetch single partition id if page is multi-partition"); return _single_partition_id; } diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 52d5d775757..ba0ab923e11 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -412,7 +412,7 @@ private: const Ticks _start_timestamp; const uint32_t _young_seqnum; const uint32_t _old_seqnum; - const uint32_t _initiating_numa_id; + const uint32_t _preferred_partition; bool _is_multi_partition; ZSinglePartitionAllocation _single_partition_allocation; ZMultiPartitionAllocation _multi_partition_allocation; @@ -420,7 +420,7 @@ private: ZFuture _stall_result; public: - ZPageAllocation(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) + ZPageAllocation(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition) : _type(type), _requested_size(size), _flags(flags), @@ -428,12 +428,14 @@ public: _start_timestamp(Ticks::now()), _young_seqnum(ZGeneration::young()->seqnum()), _old_seqnum(ZGeneration::old()->seqnum()), - _initiating_numa_id(ZNUMA::id()), + _preferred_partition(preferred_partition), _is_multi_partition(false), _single_partition_allocation(size), _multi_partition_allocation(size), _node(), - _stall_result() {} + _stall_result() { + assert(_preferred_partition < ZNUMA::count(), "Preferred partition out-of-bounds (0 <= %d < %d)", _preferred_partition, ZNUMA::count()); + } void reset_for_retry() { _is_multi_partition = false; @@ -474,8 +476,8 @@ public: return _old_seqnum; } - uint32_t initiating_numa_id() const { - return _initiating_numa_id; + uint32_t preferred_partition() const { + return _preferred_partition; } bool is_multi_partition() const { @@ -1397,10 +1399,10 @@ static void check_out_of_memory_during_initialization() { } } -ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { +ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition) { EventZPageAllocation event; - ZPageAllocation allocation(type, size, flags, age); + ZPageAllocation allocation(type, size, flags, age, preferred_partition); // Allocate the page ZPage* const page = alloc_page_inner(&allocation); @@ -1548,7 +1550,7 @@ bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { } // Round robin single-partition claiming - const uint32_t start_numa_id = allocation->initiating_numa_id(); + const uint32_t start_numa_id = allocation->preferred_partition(); const uint32_t start_partition = start_numa_id; const uint32_t num_partitions = _partitions.count(); @@ -1560,7 +1562,7 @@ bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { } } - if (!is_multi_partition_enabled() || sum_available() < allocation->size()) { + if (!is_multi_partition_allowed(allocation)) { // Multi-partition claiming is not possible return false; } @@ -1578,7 +1580,7 @@ bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { } bool ZPageAllocator::claim_capacity_fast_medium(ZPageAllocation* allocation) { - const uint32_t start_node = allocation->initiating_numa_id(); + const uint32_t start_node = allocation->preferred_partition(); const uint32_t numa_nodes = ZNUMA::count(); for (uint32_t i = 0; i < numa_nodes; ++i) { @@ -2191,6 +2193,12 @@ bool ZPageAllocator::is_multi_partition_enabled() const { return _virtual.is_multi_partition_enabled(); } +bool ZPageAllocator::is_multi_partition_allowed(const ZPageAllocation* allocation) const { + return is_multi_partition_enabled() && + allocation->type() == ZPageType::large && + allocation->size() <= sum_available(); +} + const ZPartition& ZPageAllocator::partition_from_partition_id(uint32_t numa_id) const { return _partitions.get(numa_id); } diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index c5d1bedd863..a2f4c94e8d4 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -220,6 +220,7 @@ private: void satisfy_stalled(); bool is_multi_partition_enabled() const; + bool is_multi_partition_allowed(const ZPageAllocation* allocation) const; const ZPartition& partition_from_partition_id(uint32_t partition_id) const; ZPartition& partition_from_partition_id(uint32_t partition_id); @@ -263,7 +264,7 @@ public: ZPageAllocatorStats stats(ZGeneration* generation) const; ZPageAllocatorStats update_and_stats(ZGeneration* generation); - ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); + ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition); void safe_destroy_page(ZPage* page); void free_page(ZPage* page); void free_pages(ZGenerationId id, const ZArray* pages); diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 95e22cf4c69..556f413348b 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -32,6 +32,7 @@ #include "gc/z/zHeap.inline.hpp" #include "gc/z/zIndexDistributor.inline.hpp" #include "gc/z/zIterator.inline.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "gc/z/zObjectAllocator.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageAge.inline.hpp" @@ -43,6 +44,7 @@ #include "gc/z/zStringDedup.inline.hpp" #include "gc/z/zTask.hpp" #include "gc/z/zUncoloredRoot.inline.hpp" +#include "gc/z/zValue.inline.hpp" #include "gc/z/zVerify.hpp" #include "gc/z/zWorkers.hpp" #include "prims/jvmtiTagMap.hpp" @@ -304,9 +306,38 @@ void ZRelocateQueue::desynchronize() { _lock.notify_all(); } +ZRelocationTargets::ZRelocationTargets() + : _targets() {} + +ZPage* ZRelocationTargets::get(uint32_t partition_id, ZPageAge age) { + return _targets.get(partition_id)[untype(age) - 1]; +} + +void ZRelocationTargets::set(uint32_t partition_id, ZPageAge age, ZPage* page) { + _targets.get(partition_id)[untype(age) - 1] = page; +} + +template +void ZRelocationTargets::apply_and_clear_targets(Function function) { + ZPerNUMAIterator iter(&_targets); + for (TargetArray* targets; iter.next(&targets);) { + for (size_t i = 0; i < ZNumRelocationAges; i++) { + // Apply function + function((*targets)[i]); + + // Clear target + (*targets)[i] = nullptr; + } + } +} + ZRelocate::ZRelocate(ZGeneration* generation) : _generation(generation), - _queue() {} + _queue(), + _iters(), + _small_targets(), + _medium_targets(), + _shared_medium_targets() {} ZWorkers* ZRelocate::workers() const { return _generation->workers(); @@ -394,12 +425,13 @@ static ZPage* alloc_page(ZForwarding* forwarding) { const ZPageType type = forwarding->type(); const size_t size = forwarding->size(); const ZPageAge age = forwarding->to_age(); + const uint32_t preferred_partition = forwarding->partition_id(); ZAllocationFlags flags; flags.set_non_blocking(); flags.set_gc_relocation(); - return ZHeap::heap()->alloc_page(type, size, flags, age); + return ZHeap::heap()->alloc_page(type, size, flags, age, preferred_partition); } static void retire_target_page(ZGeneration* generation, ZPage* page) { @@ -442,7 +474,7 @@ public: return page; } - void share_target_page(ZPage* page) { + void share_target_page(ZPage* page, uint32_t partition_id) { // Does nothing } @@ -467,34 +499,26 @@ public: class ZRelocateMediumAllocator { private: - ZGeneration* const _generation; - ZConditionLock _lock; - ZPage* _shared[ZNumRelocationAges]; - bool _in_place; - volatile size_t _in_place_count; + ZGeneration* const _generation; + ZConditionLock _lock; + ZRelocationTargets* _shared_targets; + bool _in_place; + volatile size_t _in_place_count; public: - ZRelocateMediumAllocator(ZGeneration* generation) + ZRelocateMediumAllocator(ZGeneration* generation, ZRelocationTargets* shared_targets) : _generation(generation), _lock(), - _shared(), + _shared_targets(shared_targets), _in_place(false), _in_place_count(0) {} ~ZRelocateMediumAllocator() { - for (uint i = 0; i < ZNumRelocationAges; ++i) { - if (_shared[i] != nullptr) { - retire_target_page(_generation, _shared[i]); + _shared_targets->apply_and_clear_targets([&](ZPage* page) { + if (page != nullptr) { + retire_target_page(_generation, page); } - } - } - - ZPage* shared(ZPageAge age) { - return _shared[untype(age - 1)]; - } - - void set_shared(ZPageAge age, ZPage* page) { - _shared[untype(age - 1)] = page; + }); } ZPage* alloc_and_retire_target_page(ZForwarding* forwarding, ZPage* target) { @@ -510,9 +534,10 @@ public: // current target page if another thread shared a page, or allocated // a new page. const ZPageAge to_age = forwarding->to_age(); - if (shared(to_age) == target) { + const uint32_t partition_id = forwarding->partition_id(); + if (_shared_targets->get(partition_id, to_age) == target) { ZPage* const to_page = alloc_page(forwarding); - set_shared(to_age, to_page); + _shared_targets->set(partition_id, to_age, to_page); if (to_page == nullptr) { Atomic::inc(&_in_place_count); _in_place = true; @@ -524,18 +549,18 @@ public: } } - return shared(to_age); + return _shared_targets->get(partition_id, to_age); } - void share_target_page(ZPage* page) { + void share_target_page(ZPage* page, uint32_t partition_id) { const ZPageAge age = page->age(); ZLocker locker(&_lock); assert(_in_place, "Invalid state"); - assert(shared(age) == nullptr, "Invalid state"); + assert(_shared_targets->get(partition_id, age) == nullptr, "Invalid state"); assert(page != nullptr, "Invalid page"); - set_shared(age, page); + _shared_targets->set(partition_id, age, page); _in_place = false; _lock.notify_all(); @@ -563,21 +588,12 @@ class ZRelocateWork : public StackObj { private: Allocator* const _allocator; ZForwarding* _forwarding; - ZPage* _target[ZNumRelocationAges]; + ZRelocationTargets* _targets; ZGeneration* const _generation; size_t _other_promoted; size_t _other_compacted; ZStringDedupContext _string_dedup_context; - - ZPage* target(ZPageAge age) { - return _target[untype(age - 1)]; - } - - void set_target(ZPageAge age, ZPage* page) { - _target[untype(age - 1)] = page; - } - size_t object_alignment() const { return (size_t)1 << _forwarding->object_alignment_shift(); } @@ -591,11 +607,11 @@ private: } } - zaddress try_relocate_object_inner(zaddress from_addr) { + zaddress try_relocate_object_inner(zaddress from_addr, uint32_t partition_id) { ZForwardingCursor cursor; const size_t size = ZUtils::object_size(from_addr); - ZPage* const to_page = target(_forwarding->to_age()); + ZPage* const to_page = _targets->get(partition_id, _forwarding->to_age()); // Lookup forwarding { @@ -806,8 +822,8 @@ private: } } - bool try_relocate_object(zaddress from_addr) { - const zaddress to_addr = try_relocate_object_inner(from_addr); + bool try_relocate_object(zaddress from_addr, uint32_t partition_id) { + const zaddress to_addr = try_relocate_object_inner(from_addr, partition_id); if (is_null(to_addr)) { return false; @@ -888,13 +904,18 @@ private: const zaddress addr = to_zaddress(obj); assert(ZHeap::heap()->is_object_live(addr), "Should be live"); - while (!try_relocate_object(addr)) { - // Allocate a new target page, or if that fails, use the page being - // relocated as the new target, which will cause it to be relocated - // in-place. - const ZPageAge to_age = _forwarding->to_age(); - ZPage* to_page = _allocator->alloc_and_retire_target_page(_forwarding, target(to_age)); - set_target(to_age, to_page); + const ZPageAge to_age = _forwarding->to_age(); + const uint32_t partition_id = _forwarding->partition_id(); + + while (!try_relocate_object(addr, partition_id)) { + // Failed to relocate object, try to allocate a new target page, + // or if that fails, use the page being relocated as the new target, + // which will cause it to be relocated in-place. + ZPage* const target_page = _targets->get(partition_id, to_age); + ZPage* to_page = _allocator->alloc_and_retire_target_page(_forwarding, target_page); + _targets->set(partition_id, to_age, to_page); + + // We got a new page, retry relocation if (to_page != nullptr) { continue; } @@ -903,23 +924,24 @@ private: // the page, or its forwarding table, until it has been released // (relocation completed). to_page = start_in_place_relocation(ZAddress::offset(addr)); - set_target(to_age, to_page); + _targets->set(partition_id, to_age, to_page); } } public: - ZRelocateWork(Allocator* allocator, ZGeneration* generation) + ZRelocateWork(Allocator* allocator, ZRelocationTargets* targets, ZGeneration* generation) : _allocator(allocator), _forwarding(nullptr), - _target(), + _targets(targets), _generation(generation), _other_promoted(0), _other_compacted(0) {} ~ZRelocateWork() { - for (uint i = 0; i < ZNumRelocationAges; ++i) { - _allocator->free_target_page(_target[i]); - } + _targets->apply_and_clear_targets([&](ZPage* page) { + _allocator->free_target_page(page); + }); + // Report statistics on-behalf of non-worker threads _generation->increase_promoted(_other_promoted); _generation->increase_compacted(_other_compacted); @@ -1012,8 +1034,9 @@ public: page->log_msg(" (relocate page done in-place)"); // Different pages when promoting - ZPage* const target_page = target(_forwarding->to_age()); - _allocator->share_target_page(target_page); + const uint32_t target_partition = _forwarding->partition_id(); + ZPage* const target_page = _targets->get(target_partition, _forwarding->to_age()); + _allocator->share_target_page(target_page, target_partition); } else { // Wait for all other threads to call release_page @@ -1057,31 +1080,63 @@ public: class ZRelocateTask : public ZRestartableTask { private: - ZRelocationSetParallelIterator _iter; - ZGeneration* const _generation; - ZRelocateQueue* const _queue; - ZRelocateSmallAllocator _small_allocator; - ZRelocateMediumAllocator _medium_allocator; + ZGeneration* const _generation; + ZRelocateQueue* const _queue; + ZPerNUMA* _iters; + ZPerWorker* _small_targets; + ZPerWorker* _medium_targets; + ZRelocateSmallAllocator _small_allocator; + ZRelocateMediumAllocator _medium_allocator; + const size_t _total_forwardings; + volatile size_t _numa_local_forwardings; public: - ZRelocateTask(ZRelocationSet* relocation_set, ZRelocateQueue* queue) + ZRelocateTask(ZRelocationSet* relocation_set, + ZRelocateQueue* queue, + ZPerNUMA* iters, + ZPerWorker* small_targets, + ZPerWorker* medium_targets, + ZRelocationTargets* shared_medium_targets) : ZRestartableTask("ZRelocateTask"), - _iter(relocation_set), _generation(relocation_set->generation()), _queue(queue), + _iters(iters), + _small_targets(small_targets), + _medium_targets(medium_targets), _small_allocator(_generation), - _medium_allocator(_generation) {} + _medium_allocator(_generation, shared_medium_targets), + _total_forwardings(relocation_set->nforwardings()), + _numa_local_forwardings(0) { + + for (uint32_t i = 0; i < ZNUMA::count(); i++) { + ZRelocationSetParallelIterator* const iter = _iters->addr(i); + + // Destruct the iterator from the previous GC-cycle, which is a temporary + // iterator if this is the first GC-cycle. + iter->~ZRelocationSetParallelIterator(); + + // In-place construct the iterator with the current relocation set + ::new (iter) ZRelocationSetParallelIterator(relocation_set); + } + } ~ZRelocateTask() { _generation->stat_relocation()->at_relocate_end(_small_allocator.in_place_count(), _medium_allocator.in_place_count()); // Signal that we're not using the queue anymore. Used mostly for asserts. _queue->deactivate(); + + if (ZNUMA::is_enabled()) { + log_debug(gc, reloc, numa)("Forwardings relocated NUMA-locally: %zu / %zu (%.0f%%)", + _numa_local_forwardings, _total_forwardings, percent_of(_numa_local_forwardings, _total_forwardings)); + } } virtual void work() { - ZRelocateWork small(&_small_allocator, _generation); - ZRelocateWork medium(&_medium_allocator, _generation); + ZRelocateWork small(&_small_allocator, _small_targets->addr(), _generation); + ZRelocateWork medium(&_medium_allocator, _medium_targets->addr(), _generation); + const uint32_t num_nodes = ZNUMA::count(); + uint32_t numa_local_forwardings_worker = 0; const auto do_forwarding = [&](ZForwarding* forwarding) { ZPage* const page = forwarding->page(); @@ -1107,12 +1162,29 @@ public: } }; + const auto check_numa_local = [&](ZForwarding* forwarding, uint32_t numa_id) { + return forwarding->partition_id() == numa_id; + }; + const auto do_forwarding_one_from_iter = [&]() { ZForwarding* forwarding; + const uint32_t start_node = ZNUMA::id(); + uint32_t current_node = start_node; - if (_iter.next(&forwarding)) { - claim_and_do_forwarding(forwarding); - return true; + for (uint32_t i = 0; i < num_nodes; i++) { + if (_iters->get(current_node).next_if(&forwarding, check_numa_local, current_node)) { + claim_and_do_forwarding(forwarding); + + if (current_node == start_node) { + // Track if this forwarding was relocated on the local NUMA node + numa_local_forwardings_worker++; + } + + return true; + } + + // Check next node. + current_node = (current_node + 1) % num_nodes; } return false; @@ -1138,6 +1210,10 @@ public: } } + if (ZNUMA::is_enabled()) { + Atomic::add(&_numa_local_forwardings, numa_local_forwardings_worker, memory_order_relaxed); + } + _queue->leave(); } @@ -1218,7 +1294,7 @@ void ZRelocate::relocate(ZRelocationSet* relocation_set) { } { - ZRelocateTask relocate_task(relocation_set, &_queue); + ZRelocateTask relocate_task(relocation_set, &_queue, &_iters, &_small_targets, &_medium_targets, &_shared_medium_targets); workers()->run(&relocate_task); } diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index 400fc61b055..d0ddf7deecf 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include "gc/z/zAddress.hpp" #include "gc/z/zPageAge.hpp" #include "gc/z/zRelocationSet.hpp" +#include "gc/z/zValue.hpp" class ZForwarding; class ZGeneration; @@ -74,15 +75,34 @@ public: void desynchronize(); }; +class ZRelocationTargets { +private: + using TargetArray = ZPage*[ZNumRelocationAges]; + + ZPerNUMA _targets; + +public: + ZRelocationTargets(); + + ZPage* get(uint32_t partition_id, ZPageAge age); + void set(uint32_t partition_id, ZPageAge age, ZPage* page); + + template + void apply_and_clear_targets(Function function); +}; + class ZRelocate { friend class ZRelocateTask; private: - ZGeneration* const _generation; - ZRelocateQueue _queue; + ZGeneration* const _generation; + ZRelocateQueue _queue; + ZPerNUMA _iters; + ZPerWorker _small_targets; + ZPerWorker _medium_targets; + ZRelocationTargets _shared_medium_targets; ZWorkers* workers() const; - void work(ZRelocationSetParallelIterator* iter); public: ZRelocate(ZGeneration* generation); diff --git a/src/hotspot/share/gc/z/zRelocationSet.hpp b/src/hotspot/share/gc/z/zRelocationSet.hpp index 2052f3c7bf1..ee1a9447617 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +52,8 @@ private: public: ZRelocationSet(ZGeneration* generation); + size_t nforwardings() const; + void install(const ZRelocationSetSelector* selector); void reset(ZPageAllocator* page_allocator); ZGeneration* generation() const; @@ -64,6 +66,7 @@ public: template class ZRelocationSetIteratorImpl : public ZArrayIteratorImpl { public: + ZRelocationSetIteratorImpl(); ZRelocationSetIteratorImpl(ZRelocationSet* relocation_set); }; diff --git a/src/hotspot/share/gc/z/zRelocationSet.inline.hpp b/src/hotspot/share/gc/z/zRelocationSet.inline.hpp index 9c093936d4c..b501021bc26 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.inline.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ #include "gc/z/zArray.inline.hpp" +inline size_t ZRelocationSet::nforwardings() const { + return _nforwardings; +} + +template +inline ZRelocationSetIteratorImpl::ZRelocationSetIteratorImpl() + : ZArrayIteratorImpl(nullptr, 0) {} + template inline ZRelocationSetIteratorImpl::ZRelocationSetIteratorImpl(ZRelocationSet* relocation_set) : ZArrayIteratorImpl(relocation_set->_forwardings, relocation_set->_nforwardings) {} From 0ca38bdc4d503158fda57bbc8bc9adc420628079 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 27 Aug 2025 09:30:48 +0000 Subject: [PATCH 013/295] 8365919: Replace currentTimeMillis with nanoTime in Stresser.java Reviewed-by: tschatzl, phh --- .../vmTestbase/nsk/share/test/Stresser.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java index 83e8baa2836..c2851267911 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java @@ -58,9 +58,12 @@ public class Stresser implements ExecutionController { private String name; private long maxIterations; private long iterations; + + // In nanoseconds private long startTime; - private long finishTime; private long currentTime; + private long stressTime; + private PrintStream defaultOutput = System.out; /* @@ -179,15 +182,15 @@ public class Stresser implements ExecutionController { */ public void printExecutionInfo(PrintStream out) { println(out, "Completed iterations: " + iterations); - println(out, "Execution time: " + (currentTime - startTime) + " seconds"); + println(out, "Execution time: " + (currentTime - startTime) / 1_000_000_000.0 + " seconds"); if (!finished) { println(out, "Execution is not finished yet"); } else if (forceFinish) { println(out, "Execution was forced to finish"); } else if (maxIterations != 0 && iterations >= maxIterations) { println(out, "Execution finished because number of iterations was exceeded: " + iterations + " >= " + maxIterations); - } else if (finishTime != 0 && currentTime >= finishTime) { - println(out, "Execution finished because time was exceeded: " + (currentTime - startTime) + " >= " + (finishTime - startTime)); + } else if (stressTime != 0 && (currentTime - startTime) >= stressTime) { + println(out, "Execution finished because time has exceeded stress time: " + stressTime / 1_000_000_000 + " seconds"); } } @@ -208,13 +211,8 @@ public class Stresser implements ExecutionController { public void start(long stdIterations) { maxIterations = stdIterations * options.getIterationsFactor(); iterations = 0; - long stressTime = options.getTime(); - startTime = System.currentTimeMillis(); - if (stressTime == 0) { - finishTime = 0; - } else { - finishTime = startTime + stressTime * 1000; - } + stressTime = options.getTime() * 1_000_000_000; + startTime = System.nanoTime(); finished = false; forceFinish = false; if (options.isDebugEnabled()) { @@ -232,7 +230,7 @@ public class Stresser implements ExecutionController { * finally {} block. */ public void finish() { - currentTime = System.currentTimeMillis(); + currentTime = System.nanoTime(); finished = true; if (options.isDebugEnabled()) { printExecutionInfo(defaultOutput); @@ -255,10 +253,12 @@ public class Stresser implements ExecutionController { */ public boolean iteration() { ++iterations; + boolean result = continueExecution(); + // Call print at the end to show the most up-to-date info. if (options.isDebugDetailed()) { printExecutionInfo(defaultOutput); } - return continueExecution(); + return result; } /** @@ -267,14 +267,14 @@ public class Stresser implements ExecutionController { * @return true if execution needs to continue */ public boolean continueExecution() { - currentTime = System.currentTimeMillis(); + currentTime = System.nanoTime(); if (startTime == 0) { throw new TestBug("Stresser is not started."); } return !forceFinish && !finished && (maxIterations == 0 || iterations < maxIterations) - && (finishTime == 0 || currentTime < finishTime); + && (stressTime == 0 || (currentTime - startTime) < stressTime); } /** @@ -309,7 +309,7 @@ public class Stresser implements ExecutionController { * @return time */ public long getExecutionTime() { - return System.currentTimeMillis() - startTime; + return (System.nanoTime() - startTime) / 1_000_000; } /** @@ -318,11 +318,11 @@ public class Stresser implements ExecutionController { * @return time */ public long getTimeLeft() { - long current = System.currentTimeMillis(); - if (current >= finishTime) { + long elapsedTime = System.nanoTime() - startTime; + if (elapsedTime >= stressTime) { return 0; } else { - return finishTime - current; + return (stressTime - elapsedTime) / 1_000_000; } } From 19f0755c48e998b5b136ca58ea21eb3b54bc7b33 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 27 Aug 2025 09:41:12 +0000 Subject: [PATCH 014/295] 8365203: defineClass with direct buffer can cause use-after-free Reviewed-by: jpai --- .../share/classes/java/lang/ClassLoader.java | 17 +++- .../defineClass/TestGuardByteBuffer.java | 79 +++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 6082bc53297..511785a5ac8 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -52,6 +52,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.access.SharedSecrets; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.ClassLoaders; @@ -1049,14 +1050,22 @@ public abstract class ClassLoader { protectionDomain = preDefineClass(name, protectionDomain); String source = defineClassSourceLocation(protectionDomain); - Class c = defineClass2(this, name, b, b.position(), len, protectionDomain, source); - postDefineClass(c, protectionDomain); - return c; + + SharedSecrets.getJavaNioAccess().acquireSession(b); + try { + Class c = defineClass2(this, name, b, b.position(), len, protectionDomain, source); + postDefineClass(c, protectionDomain); + return c; + } finally { + SharedSecrets.getJavaNioAccess().releaseSession(b); + } } static native Class defineClass1(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd, String source); + // Warning: Before calling this method, the provided ByteBuffer must be guarded + // via JavaNioAccess::(acquire|release)Session static native Class defineClass2(ClassLoader loader, String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source); diff --git a/test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java b/test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java new file mode 100644 index 00000000000..6c12004ee4c --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8365203 + * @summary Tests guarding of ByteBuffers in ClassLoader::defineClass + * @run junit TestGuardByteBuffer + */ + +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; +import java.util.HexFormat; + +import static org.junit.jupiter.api.Assertions.*; + +final class TestGuardByteBuffer { + + @Test + void guardCrash() { + final byte[] classBytes = getClassBytes(); // get bytes of a valid class + final var cl = new ClassLoader() { + void tryCrash() { + var arena = Arena.ofConfined(); + var byteBuffer = arena.allocate(classBytes.length).asByteBuffer(); + // Close the arena underneath + arena.close(); + // expected to always fail because the arena + // from which the ByteBuffer was constructed + // has been closed + assertThrows(IllegalStateException.class, + () -> defineClass(null, byteBuffer, null)); + } + }; + for (int i = 0; i < 10_000; i++) { + cl.tryCrash(); + } + } + + private static byte[] getClassBytes() { + // unused. this is here just for reference + final String source = """ + public class NoOp {} + """; + // (externally) compiled content of the above "source", represented as hex + final String classBytesHex = """ + cafebabe00000044000d0a000200030700040c000500060100106a6176612f + 6c616e672f4f626a6563740100063c696e69743e0100032829560700080100 + 044e6f4f70010004436f646501000f4c696e654e756d6265725461626c6501 + 000a536f7572636546696c650100094e6f4f702e6a61766100210007000200 + 0000000001000100050006000100090000001d00010001000000052ab70001 + b100000001000a000000060001000000010001000b00000002000c + """; + + return HexFormat.of().parseHex(classBytesHex.replaceAll("\n", "")); + } + +} From 32df2d17f3c0407ad7e90eacfdc0fd7a65f67551 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 27 Aug 2025 10:15:25 +0000 Subject: [PATCH 015/295] 8365772: RISC-V: correctly prereserve NaN payload when converting from float to float16 in vector way Reviewed-by: fyang, rehn --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 1 + .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 67 +++++++++++++++---- .../TestFloatConversionsVectorNaN.java | 14 ++-- 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 3317ccc3b53..c267cb669ac 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1988,6 +1988,7 @@ enum VectorMask { // Vector Narrowing Integer Right Shift Instructions INSN(vnsra_wi, 0b1010111, 0b011, 0b101101); + INSN(vnsrl_wi, 0b1010111, 0b011, 0b101100); #undef INSN diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 0420d83ac41..1bdb7bc2f7c 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2248,41 +2248,80 @@ static void float_to_float16_v_slow_path(C2_MacroAssembler& masm, #define __ masm. VectorRegister dst = stub.data<0>(); VectorRegister src = stub.data<1>(); - VectorRegister tmp = stub.data<2>(); + VectorRegister vtmp = stub.data<2>(); + assert_different_registers(dst, src, vtmp); + __ bind(stub.entry()); + // Active elements (NaNs) are marked in v0 mask register. // mul is already set to mf2 in float_to_float16_v. - // preserve the payloads of non-canonical NaNs. - __ vnsra_wi(dst, src, 13, Assembler::v0_t); + // Float (32 bits) + // Bit: 31 30 to 23 22 to 0 + // +---+------------------+-----------------------------+ + // | S | Exponent | Mantissa (Fraction) | + // +---+------------------+-----------------------------+ + // 1 bit 8 bits 23 bits + // + // Float (16 bits) + // Bit: 15 14 to 10 9 to 0 + // +---+----------------+------------------+ + // | S | Exponent | Mantissa | + // +---+----------------+------------------+ + // 1 bit 5 bits 10 bits + const int fp_sign_bits = 1; + const int fp32_bits = 32; + const int fp32_mantissa_2nd_part_bits = 9; + const int fp32_mantissa_3rd_part_bits = 4; + const int fp16_exponent_bits = 5; + const int fp16_mantissa_bits = 10; - // preserve the sign bit. - __ vnsra_wi(tmp, src, 26, Assembler::v0_t); - __ vsll_vi(tmp, tmp, 10, Assembler::v0_t); - __ mv(t0, 0x3ff); - __ vor_vx(tmp, tmp, t0, Assembler::v0_t); + // preserve the sign bit and exponent, clear mantissa. + __ vnsra_wi(dst, src, fp32_bits - fp_sign_bits - fp16_exponent_bits, Assembler::v0_t); + __ vsll_vi(dst, dst, fp16_mantissa_bits, Assembler::v0_t); - // get the result by merging sign bit and payloads of preserved non-canonical NaNs. - __ vand_vv(dst, dst, tmp, Assembler::v0_t); + // Preserve high order bit of float NaN in the + // binary16 result NaN (tenth bit); OR in remaining + // bits into lower 9 bits of binary 16 significand. + // | (doppel & 0x007f_e000) >> 13 // 10 bits + // | (doppel & 0x0000_1ff0) >> 4 // 9 bits + // | (doppel & 0x0000_000f)); // 4 bits + // + // Check j.l.Float.floatToFloat16 for more information. + // 10 bits + __ vnsrl_wi(vtmp, src, fp32_mantissa_2nd_part_bits + fp32_mantissa_3rd_part_bits, Assembler::v0_t); + __ mv(t0, 0x3ff); // retain first part of mantissa in a float 32 + __ vand_vx(vtmp, vtmp, t0, Assembler::v0_t); + __ vor_vv(dst, dst, vtmp, Assembler::v0_t); + // 9 bits + __ vnsrl_wi(vtmp, src, fp32_mantissa_3rd_part_bits, Assembler::v0_t); + __ mv(t0, 0x1ff); // retain second part of mantissa in a float 32 + __ vand_vx(vtmp, vtmp, t0, Assembler::v0_t); + __ vor_vv(dst, dst, vtmp, Assembler::v0_t); + // 4 bits + // Narrow shift is necessary to move data from 32 bits element to 16 bits element in vector register. + __ vnsrl_wi(vtmp, src, 0, Assembler::v0_t); + __ vand_vi(vtmp, vtmp, 0xf, Assembler::v0_t); + __ vor_vv(dst, dst, vtmp, Assembler::v0_t); __ j(stub.continuation()); #undef __ } // j.l.Float.float16ToFloat -void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src, VectorRegister vtmp, - Register tmp, uint vector_length) { +void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src, + VectorRegister vtmp, Register tmp, uint vector_length) { assert_different_registers(dst, src, vtmp); auto stub = C2CodeStub::make - (dst, src, vtmp, 28, float_to_float16_v_slow_path); + (dst, src, vtmp, 56, float_to_float16_v_slow_path); // On riscv, NaN needs a special process as vfncvt_f_f_w does not work in that case. vsetvli_helper(BasicType::T_FLOAT, vector_length, Assembler::m1); // check whether there is a NaN. - // replace v_fclass with vmseq_vv as performance optimization. + // replace v_fclass with vmfne_vv as performance optimization. vmfne_vv(v0, src, src); vcpop_m(t0, v0); diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java index 6f76defa279..dad6e51f2ec 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java @@ -23,6 +23,7 @@ /** * @test + * @key randomness * @bug 8320646 * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs, with NaN * @requires vm.compiler2.enabled @@ -37,9 +38,11 @@ package compiler.vectorization; import java.util.HexFormat; +import java.util.Random; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestFloatConversionsVectorNaN { private static final int ARRLEN = 1024; @@ -79,14 +82,16 @@ public class TestFloatConversionsVectorNaN { @Run(test = {"test_float_float16"}, mode = RunMode.STANDALONE) public void kernel_test_float_float16() { + Random rand = Utils.getRandomInstance(); int errno = 0; finp = new float[ARRLEN]; sout = new short[ARRLEN]; // Setup for (int i = 0; i < ARRLEN; i++) { - if (i%39 == 0) { - int x = 0x7f800000 + ((i/39) << 13); + if (i%3 == 0) { + int shift = rand.nextInt(13+1); + int x = 0x7f800000 + ((i/39) << shift); x = (i%2 == 0) ? x : (x | 0x80000000); finp[i] = Float.intBitsToFloat(x); } else { @@ -128,7 +133,8 @@ public class TestFloatConversionsVectorNaN { static int assertEquals(int idx, float f, short expected, short actual) { HexFormat hf = HexFormat.of(); - String msg = "floatToFloat16 wrong result: idx: " + idx + ", \t" + f + + String msg = "floatToFloat16 wrong result: idx: " + idx + + ", \t" + f + ", hex: " + Integer.toHexString(Float.floatToRawIntBits(f)) + ",\t expected: " + hf.toHexDigits(expected) + ",\t actual: " + hf.toHexDigits(actual); if ((expected & 0x7c00) != 0x7c00) { @@ -167,7 +173,7 @@ public class TestFloatConversionsVectorNaN { // Setup for (int i = 0; i < ARRLEN; i++) { - if (i%39 == 0) { + if (i%3 == 0) { int x = 0x7c00 + i; x = (i%2 == 0) ? x : (x | 0x8000); sinp[i] = (short)x; From 124575b4c2b52328a8efddb40e67057a53b44a04 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 27 Aug 2025 11:45:43 +0000 Subject: [PATCH 016/295] 8359348: G1: Improve cpu usage measurements for heap sizing Reviewed-by: tschatzl, ayang, manc --- src/hotspot/share/gc/g1/g1Analytics.cpp | 39 +++++++++++----- src/hotspot/share/gc/g1/g1Analytics.hpp | 44 ++++++++++++++----- .../share/gc/g1/g1HeapSizingPolicy.cpp | 4 +- src/hotspot/share/gc/g1/g1Policy.cpp | 12 ++++- test/hotspot/gtest/gc/g1/test_g1Analytics.cpp | 4 +- 5 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Analytics.cpp b/src/hotspot/share/gc/g1/g1Analytics.cpp index 59d1a48cd85..686554ffaa4 100644 --- a/src/hotspot/share/gc/g1/g1Analytics.cpp +++ b/src/hotspot/share/gc/g1/g1Analytics.cpp @@ -28,6 +28,7 @@ #include "gc/shared/gc_globals.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" +#include "services/cpuTimeUsage.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/numberSeq.hpp" @@ -73,6 +74,8 @@ G1Analytics::G1Analytics(const G1Predictions* predictor) : _concurrent_mark_cleanup_times_ms(NumPrevPausesForHeuristics), _alloc_rate_ms_seq(TruncatedSeqLength), _prev_collection_pause_end_ms(0.0), + _gc_cpu_time_at_pause_end_ms(), + _concurrent_gc_cpu_time_ms(), _concurrent_refine_rate_ms_seq(TruncatedSeqLength), _dirtied_cards_rate_ms_seq(TruncatedSeqLength), _dirtied_cards_in_thread_buffers_seq(TruncatedSeqLength), @@ -88,8 +91,8 @@ G1Analytics::G1Analytics(const G1Predictions* predictor) : _young_other_cost_per_region_ms_seq(TruncatedSeqLength), _non_young_other_cost_per_region_ms_seq(TruncatedSeqLength), _recent_prev_end_times_for_all_gcs_sec(NumPrevPausesForHeuristics), - _long_term_pause_time_ratio(0.0), - _short_term_pause_time_ratio(0.0) { + _long_term_gc_time_ratio(0.0), + _short_term_gc_time_ratio(0.0) { // Seed sequences with initial values. _recent_prev_end_times_for_all_gcs_sec.add(os::elapsedTime()); @@ -149,6 +152,10 @@ int G1Analytics::num_alloc_rate_ms() const { return _alloc_rate_ms_seq.num(); } +double G1Analytics::gc_cpu_time_ms() const { + return (double)CPUTimeUsage::GC::gc_threads() / NANOSECS_PER_MILLISEC; +} + void G1Analytics::report_concurrent_mark_remark_times_ms(double ms) { _concurrent_mark_remark_times_ms.add(ms); } @@ -157,15 +164,27 @@ void G1Analytics::report_alloc_rate_ms(double alloc_rate) { _alloc_rate_ms_seq.add(alloc_rate); } -void G1Analytics::compute_pause_time_ratios(double end_time_sec, double pause_time_ms) { +void G1Analytics::update_gc_time_ratios(double end_time_sec, double pause_time_ms) { + // This estimates the wall-clock time "lost" by application mutator threads due to concurrent GC + // activity. We do not account for contention on other shared resources such as memory bandwidth and + // caches, therefore underestimate the impact of the concurrent GC activity on mutator threads. + uint num_cpus = (uint)os::active_processor_count(); + double concurrent_gc_impact_time = _concurrent_gc_cpu_time_ms / num_cpus; + + double gc_time_ms = pause_time_ms + concurrent_gc_impact_time; + double long_interval_ms = (end_time_sec - oldest_known_gc_end_time_sec()) * 1000.0; - double gc_pause_time_ms = _recent_gc_times_ms.sum() - _recent_gc_times_ms.oldest() + pause_time_ms; - _long_term_pause_time_ratio = gc_pause_time_ms / long_interval_ms; - _long_term_pause_time_ratio = clamp(_long_term_pause_time_ratio, 0.0, 1.0); + double long_term_gc_time_ms = _recent_gc_times_ms.sum() - _recent_gc_times_ms.oldest() + gc_time_ms; + + _long_term_gc_time_ratio = long_term_gc_time_ms / long_interval_ms; + _long_term_gc_time_ratio = clamp(_long_term_gc_time_ratio, 0.0, 1.0); double short_interval_ms = (end_time_sec - most_recent_gc_end_time_sec()) * 1000.0; - _short_term_pause_time_ratio = pause_time_ms / short_interval_ms; - _short_term_pause_time_ratio = clamp(_short_term_pause_time_ratio, 0.0, 1.0); + + _short_term_gc_time_ratio = gc_time_ms / short_interval_ms; + _short_term_gc_time_ratio = clamp(_short_term_gc_time_ratio, 0.0, 1.0); + + update_recent_gc_times(end_time_sec, gc_time_ms); } void G1Analytics::report_concurrent_refine_rate_ms(double cards_per_ms) { @@ -305,8 +324,8 @@ double G1Analytics::most_recent_gc_end_time_sec() const { } void G1Analytics::update_recent_gc_times(double end_time_sec, - double pause_time_ms) { - _recent_gc_times_ms.add(pause_time_ms); + double gc_time_ms) { + _recent_gc_times_ms.add(gc_time_ms); _recent_prev_end_times_for_all_gcs_sec.add(end_time_sec); } diff --git a/src/hotspot/share/gc/g1/g1Analytics.hpp b/src/hotspot/share/gc/g1/g1Analytics.hpp index 2fd3c78df27..e5e2dd74101 100644 --- a/src/hotspot/share/gc/g1/g1Analytics.hpp +++ b/src/hotspot/share/gc/g1/g1Analytics.hpp @@ -44,7 +44,15 @@ class G1Analytics: public CHeapObj { TruncatedSeq _concurrent_mark_cleanup_times_ms; TruncatedSeq _alloc_rate_ms_seq; - double _prev_collection_pause_end_ms; + double _prev_collection_pause_end_ms; + + // Records the total GC CPU time (in ms) at the end of the last GC pause. + // Used as a baseline to calculate CPU time spent in GC threads between pauses. + double _gc_cpu_time_at_pause_end_ms; + + // CPU time (ms) spent by GC threads between the end of the last pause + // and the start of the current pause; calculated at start of a GC pause. + double _concurrent_gc_cpu_time_ms; TruncatedSeq _concurrent_refine_rate_ms_seq; TruncatedSeq _dirtied_cards_rate_ms_seq; @@ -75,10 +83,10 @@ class G1Analytics: public CHeapObj { // Statistics kept per GC stoppage, pause or full. TruncatedSeq _recent_prev_end_times_for_all_gcs_sec; - // Cached values for long and short term pause time ratios. See - // compute_pause_time_ratios() for how they are computed. - double _long_term_pause_time_ratio; - double _short_term_pause_time_ratio; + // Cached values for long and short term gc time ratios. See + // update_gc_time_ratios() for how they are computed. + double _long_term_gc_time_ratio; + double _short_term_gc_time_ratio; double predict_in_unit_interval(TruncatedSeq const* seq) const; size_t predict_size(TruncatedSeq const* seq) const; @@ -102,12 +110,12 @@ public: return _prev_collection_pause_end_ms; } - double long_term_pause_time_ratio() const { - return _long_term_pause_time_ratio; + double long_term_gc_time_ratio() const { + return _long_term_gc_time_ratio; } - double short_term_pause_time_ratio() const { - return _short_term_pause_time_ratio; + double short_term_gc_time_ratio() const { + return _short_term_gc_time_ratio; } static constexpr uint max_num_of_recorded_pause_times() { @@ -122,6 +130,20 @@ public: _prev_collection_pause_end_ms = ms; } + void set_gc_cpu_time_at_pause_end_ms(double ms) { + _gc_cpu_time_at_pause_end_ms = ms; + } + + double gc_cpu_time_at_pause_end_ms() const { + return _gc_cpu_time_at_pause_end_ms; + } + + void set_concurrent_gc_cpu_time_ms(double ms) { + _concurrent_gc_cpu_time_ms = ms; + } + + double gc_cpu_time_ms() const; + void report_concurrent_mark_remark_times_ms(double ms); void report_concurrent_mark_cleanup_times_ms(double ms); void report_alloc_rate_ms(double alloc_rate); @@ -173,8 +195,8 @@ public: size_t predict_pending_cards(bool for_young_only_phase) const; // Add a new GC of the given duration and end time to the record. - void update_recent_gc_times(double end_time_sec, double elapsed_ms); - void compute_pause_time_ratios(double end_time_sec, double pause_time_ms); + void update_recent_gc_times(double end_time_sec, double gc_time_ms); + void update_gc_time_ratios(double end_time_sec, double pause_time_ms); }; #endif // SHARE_GC_G1_G1ANALYTICS_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp index 6f82d7cc284..03a1444f8e6 100644 --- a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp @@ -217,8 +217,8 @@ size_t G1HeapSizingPolicy::young_collection_resize_amount(bool& expand, size_t a assert(GCTimeRatio > 0, "must be"); expand = false; - const double long_term_gc_cpu_usage = _analytics->long_term_pause_time_ratio(); - const double short_term_gc_cpu_usage = _analytics->short_term_pause_time_ratio(); + const double long_term_gc_cpu_usage = _analytics->long_term_gc_time_ratio(); + const double short_term_gc_cpu_usage = _analytics->short_term_gc_time_ratio(); double gc_cpu_usage_target = 1.0 / (1.0 + GCTimeRatio); gc_cpu_usage_target = scale_with_heap(gc_cpu_usage_target); diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 53f0a7bf7a6..6141f1056fe 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -664,6 +664,12 @@ bool G1Policy::should_retain_evac_failed_region(uint index) const { void G1Policy::record_pause_start_time() { Ticks now = Ticks::now(); _cur_pause_start_sec = now.seconds(); + + double prev_gc_cpu_pause_end_ms = _analytics->gc_cpu_time_at_pause_end_ms(); + double cur_gc_cpu_time_ms = _analytics->gc_cpu_time_ms(); + + double concurrent_gc_cpu_time_ms = cur_gc_cpu_time_ms - prev_gc_cpu_pause_end_ms; + _analytics->set_concurrent_gc_cpu_time_ms(concurrent_gc_cpu_time_ms); } void G1Policy::record_young_collection_start() { @@ -1346,8 +1352,7 @@ void G1Policy::update_gc_pause_time_ratios(G1GCPauseType gc_type, double start_t double pause_time_sec = end_time_sec - start_time_sec; double pause_time_ms = pause_time_sec * 1000.0; - _analytics->compute_pause_time_ratios(end_time_sec, pause_time_ms); - _analytics->update_recent_gc_times(end_time_sec, pause_time_ms); + _analytics->update_gc_time_ratios(end_time_sec, pause_time_ms); if (gc_type == G1GCPauseType::Cleanup || gc_type == G1GCPauseType::Remark) { _analytics->append_prev_collection_pause_end_ms(pause_time_ms); @@ -1370,6 +1375,9 @@ void G1Policy::record_pause(G1GCPauseType gc_type, } update_time_to_mixed_tracking(gc_type, start, end); + + double elapsed_gc_cpu_time = _analytics->gc_cpu_time_ms(); + _analytics->set_gc_cpu_time_at_pause_end_ms(elapsed_gc_cpu_time); } void G1Policy::update_time_to_mixed_tracking(G1GCPauseType gc_type, diff --git a/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp b/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp index a4947774414..5a75051656c 100644 --- a/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp @@ -29,6 +29,6 @@ TEST_VM(G1Analytics, is_initialized) { G1Predictions p(0.888888); // the actual sigma value doesn't matter G1Analytics a(&p); - ASSERT_EQ(a.long_term_pause_time_ratio(), 0.0); - ASSERT_EQ(a.short_term_pause_time_ratio(), 0.0); + ASSERT_EQ(a.long_term_gc_time_ratio(), 0.0); + ASSERT_EQ(a.short_term_gc_time_ratio(), 0.0); } From 1d53ac30f1db88df9a97b63b3ff56d26975d3a57 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 27 Aug 2025 14:25:39 +0000 Subject: [PATCH 017/295] 8366028: MethodType::fromMethodDescriptorString should not throw UnsupportedOperationException for invalid descriptors Reviewed-by: jvernee --- .../sun/invoke/util/BytecodeDescriptor.java | 13 ++++++++--- test/jdk/java/lang/invoke/MethodTypeTest.java | 23 ++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java index 53fd6322758..76bbff2a610 100644 --- a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java +++ b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,8 +96,15 @@ public class BytecodeDescriptor { } } else if (c == '[') { Class t = parseSig(str, i, end, loader); - if (t != null) - t = t.arrayType(); + if (t != null) { + try { + t = t.arrayType(); + } catch (UnsupportedOperationException ex) { + // Bad arrays, such as [V or more than 255 dims + // We have a more informative IAE + return null; + } + } return t; } else { return Wrapper.forBasicType(c).primitiveType(); diff --git a/test/jdk/java/lang/invoke/MethodTypeTest.java b/test/jdk/java/lang/invoke/MethodTypeTest.java index c2ae4e0e84f..70949236066 100644 --- a/test/jdk/java/lang/invoke/MethodTypeTest.java +++ b/test/jdk/java/lang/invoke/MethodTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ /* @test + * @bug 8366028 * @summary unit tests for java.lang.invoke.MethodType * @compile MethodTypeTest.java * @run testng/othervm test.java.lang.invoke.MethodTypeTest @@ -35,6 +36,8 @@ import java.lang.reflect.Method; import java.util.*; import org.testng.*; + +import static org.testng.Assert.assertThrows; import static org.testng.AssertJUnit.*; import org.testng.annotations.*; @@ -218,6 +221,24 @@ public class MethodTypeTest { return sb.toString().replace('.', '/'); } + @DataProvider(name = "badMethodDescriptorStrings") + public String[] badMethodDescriptorStrings() { + return new String[] { + "(I)", + "(V)V", + "([V)V", + "(" + "[".repeat(256) + "J)I", + "(java/lang/Object)V", + "()java/lang/Object", + }; + } + + // JDK-8366028 + @Test(dataProvider = "badMethodDescriptorStrings", expectedExceptions = IllegalArgumentException.class) + public void testFromMethodDescriptorStringNegatives(String desc) { + MethodType.fromMethodDescriptorString(desc, null); + } + @Test public void testHasPrimitives() { System.out.println("hasPrimitives"); From 79cea6dd174c22f99b4cafc835e6c843c1b4ec38 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 27 Aug 2025 14:37:39 +0000 Subject: [PATCH 018/295] 8365975: Sort share/memory includes Reviewed-by: shade, ayang, jwaters --- src/hotspot/share/memory/allocation.cpp | 1 - src/hotspot/share/memory/arena.cpp | 1 - src/hotspot/share/memory/classLoaderMetaspace.cpp | 2 +- src/hotspot/share/memory/heapInspection.hpp | 2 +- src/hotspot/share/memory/iterator.inline.hpp | 4 ++-- src/hotspot/share/memory/memRegion.cpp | 1 - src/hotspot/share/memory/metadataFactory.hpp | 1 + src/hotspot/share/memory/metaspace/blockTree.cpp | 2 +- src/hotspot/share/memory/metaspace/metablock.inline.hpp | 5 +++-- src/hotspot/share/memory/metaspace/virtualSpaceList.cpp | 2 +- src/hotspot/share/memory/metaspaceClosure.hpp | 1 + src/hotspot/share/memory/resourceArea.inline.hpp | 1 + test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 13 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 0d99c1bea68..a7c0045eac3 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -22,7 +22,6 @@ * */ -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/arena.hpp" #include "memory/metaspace.hpp" diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index d29861c69bb..db0bb8add21 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -24,7 +24,6 @@ */ #include "compiler/compilationMemoryStatistic.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/arena.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/memory/classLoaderMetaspace.cpp b/src/hotspot/share/memory/classLoaderMetaspace.cpp index efa6adc7a7b..c1ff172071d 100644 --- a/src/hotspot/share/memory/classLoaderMetaspace.cpp +++ b/src/hotspot/share/memory/classLoaderMetaspace.cpp @@ -26,7 +26,6 @@ #include "logging/log.hpp" #include "memory/classLoaderMetaspace.hpp" #include "memory/metaspace.hpp" -#include "memory/metaspaceUtils.hpp" #include "memory/metaspace/chunkManager.hpp" #include "memory/metaspace/internalStats.hpp" #include "memory/metaspace/metablock.hpp" @@ -38,6 +37,7 @@ #include "memory/metaspace/metaspaceStatistics.hpp" #include "memory/metaspace/runningCounters.hpp" #include "memory/metaspaceTracer.hpp" +#include "memory/metaspaceUtils.hpp" #include "oops/klass.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index ca9a46c9140..58e91217a32 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -27,9 +27,9 @@ #include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" +#include "oops/annotations.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" -#include "oops/annotations.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index 7ed2b9b3faa..498c74fd1d2 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -32,12 +32,12 @@ #include "code/nmethod.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" -#include "oops/klass.hpp" +#include "oops/instanceClassLoaderKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" -#include "oops/instanceClassLoaderKlass.inline.hpp" #include "oops/instanceRefKlass.inline.hpp" #include "oops/instanceStackChunkKlass.inline.hpp" +#include "oops/klass.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/typeArrayKlass.inline.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/memory/memRegion.cpp b/src/hotspot/share/memory/memRegion.cpp index 4391e25aec3..3c481926025 100644 --- a/src/hotspot/share/memory/memRegion.cpp +++ b/src/hotspot/share/memory/memRegion.cpp @@ -22,7 +22,6 @@ * */ -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/memRegion.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/memory/metadataFactory.hpp b/src/hotspot/share/memory/metadataFactory.hpp index 355702f7980..f2542069f04 100644 --- a/src/hotspot/share/memory/metadataFactory.hpp +++ b/src/hotspot/share/memory/metadataFactory.hpp @@ -30,6 +30,7 @@ #include "oops/array.inline.hpp" #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" + #include class MetadataFactory : AllStatic { diff --git a/src/hotspot/share/memory/metaspace/blockTree.cpp b/src/hotspot/share/memory/metaspace/blockTree.cpp index 33237494b50..7ad24353c96 100644 --- a/src/hotspot/share/memory/metaspace/blockTree.cpp +++ b/src/hotspot/share/memory/metaspace/blockTree.cpp @@ -23,8 +23,8 @@ * */ -#include "memory/metaspace/chunklevel.hpp" #include "memory/metaspace/blockTree.hpp" +#include "memory/metaspace/chunklevel.hpp" #include "memory/resourceArea.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/memory/metaspace/metablock.inline.hpp b/src/hotspot/share/memory/metaspace/metablock.inline.hpp index 04eb6c22277..87dceceeb74 100644 --- a/src/hotspot/share/memory/metaspace/metablock.inline.hpp +++ b/src/hotspot/share/memory/metaspace/metablock.inline.hpp @@ -27,10 +27,11 @@ #define SHARE_MEMORY_METASPACE_METABLOCK_INLINE_HPP #include "memory/metaspace/metablock.hpp" -#include "utilities/globalDefinitions.hpp" + #include "utilities/align.hpp" -#include "utilities/ostream.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" class outputStream; diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp index 64a17fcbfa9..c4b112defb4 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp @@ -29,8 +29,8 @@ #include "memory/metaspace/commitLimiter.hpp" #include "memory/metaspace/counters.hpp" #include "memory/metaspace/freeChunkList.hpp" -#include "memory/metaspace/metaspaceContext.hpp" #include "memory/metaspace/metaspaceCommon.hpp" +#include "memory/metaspace/metaspaceContext.hpp" #include "memory/metaspace/virtualSpaceList.hpp" #include "memory/metaspace/virtualSpaceNode.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index c35363eb71f..beb7cdc6318 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -34,6 +34,7 @@ #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/resizableHashTable.hpp" + #include // The metadata hierarchy is separate from the oop hierarchy diff --git a/src/hotspot/share/memory/resourceArea.inline.hpp b/src/hotspot/share/memory/resourceArea.inline.hpp index d3e8364773a..cd8890c228d 100644 --- a/src/hotspot/share/memory/resourceArea.inline.hpp +++ b/src/hotspot/share/memory/resourceArea.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_MEMORY_RESOURCEAREA_INLINE_HPP #include "memory/resourceArea.hpp" + #include "nmt/memTracker.hpp" inline char* ResourceArea::allocate_bytes(size_t size, AllocFailType alloc_failmode) { diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 1a304a44944..74da9626bae 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -55,6 +55,7 @@ public class TestIncludesAreSorted { "share/jvmci", "share/libadt", "share/logging", + "share/memory", "share/metaprogramming", "share/oops", "share/opto", From b43c2c663567e59f8b5c84b1b45536078190605b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Wed, 27 Aug 2025 14:48:33 +0000 Subject: [PATCH 019/295] 8366225: Linux Alpine (fast)debug build fails after JDK-8365909 Reviewed-by: mbaesken, thartmann --- src/hotspot/os/linux/compilerThreadTimeout_linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp index 7ee741ff011..c19b3e64825 100644 --- a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp @@ -94,7 +94,7 @@ bool CompilerThreadTimeoutLinux::init_timeout() { JavaThread* thread = JavaThread::current(); // Create a POSIX timer sending SIGALRM to this thread only. - sigevent_t sev; + struct sigevent sev; sev.sigev_value.sival_ptr = nullptr; sev.sigev_signo = TIMEOUT_SIGNAL; sev.sigev_notify = SIGEV_THREAD_ID; From f1c0b4ed722bf4cc5f262e804cec26d59ceb6e8b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 27 Aug 2025 15:30:01 +0000 Subject: [PATCH 020/295] 8361495: (fc) Async close of streams connected to uninterruptible FileChannel doesn't throw AsynchronousCloseException in all cases Reviewed-by: alanb --- .../classes/sun/nio/ch/FileChannelImpl.java | 6 +- .../channels/Channels/AsyncCloseStreams.java | 158 ++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 7f37ad36452..a1ddcad94f5 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -178,7 +178,11 @@ public class FileChannelImpl } private void endBlocking(boolean completed) throws AsynchronousCloseException { - if (!uninterruptible) end(completed); + if (!uninterruptible) { + end(completed); + } else if (!completed && !isOpen()) { + throw new AsynchronousCloseException(); + } } // -- Standard channel operations -- diff --git a/test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java b/test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java new file mode 100644 index 00000000000..053cae0df7e --- /dev/null +++ b/test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8361495 + * @summary Test for AsynchronousCloseException from uninterruptible FileChannel + * @run junit AsyncCloseStreams + */ + +import java.io.Closeable; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.ClosedChannelException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.concurrent.LinkedTransferQueue; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.fail; + +public class AsyncCloseStreams { + private static final Closeable STOP = () -> { }; + + private static Thread startCloseThread(LinkedTransferQueue q) { + return Thread.ofPlatform().start(() -> { + try { + Closeable c; + while((c = q.take()) != STOP) { + try { + c.close(); + } catch (IOException ignored) { + } + } + } catch (InterruptedException ignored) { + } + }); + } + + @Test + public void available() throws InterruptedException, IOException { + var close = new LinkedTransferQueue(); + Thread closeThread = startCloseThread(close); + + try { + Path path = Files.createTempFile(Path.of("."), "foo", "bar"); + path.toFile().deleteOnExit(); + + do { + InputStream in = Files.newInputStream(path); + close.offer(in); + int available = 0; + try { + available = in.available(); + } catch (AsynchronousCloseException ace) { + System.err.println("AsynchronousCloseException caught"); + break; + } catch (ClosedChannelException ignored) { + continue; + } catch (Throwable t) { + fail("Unexpected error", t); + } + if (available < 0) { + fail("FAILED: available < 0"); + } + } while (true); + } finally { + close.offer(STOP); + closeThread.join(); + } + } + + @Test + public void read() throws InterruptedException, IOException { + var close = new LinkedTransferQueue(); + Thread closeThread = startCloseThread(close); + + try { + Path path = Files.createTempFile(Path.of("."), "foo", "bar"); + path.toFile().deleteOnExit(); + byte[] bytes = new byte[100_000]; + Arrays.fill(bytes, (byte)27); + Files.write(path, bytes); + + do { + InputStream in = Files.newInputStream(path); + close.offer(in); + int value = 0; + try { + value = in.read(); + } catch (AsynchronousCloseException ace) { + System.err.println("AsynchronousCloseException caught"); + break; + } catch (ClosedChannelException ignored) { + continue; + } catch (Throwable t) { + fail("Unexpected error", t); + } + if (value < 0) { + fail("FAILED: value < 0"); + } + } while (true); + } finally { + close.offer(STOP); + closeThread.join(); + } + } + + @Test + public void write() throws InterruptedException, IOException { + var close = new LinkedTransferQueue(); + Thread closeThread = startCloseThread(close); + + try { + Path path = Files.createTempFile(Path.of("."), "foo", "bar"); + path.toFile().deleteOnExit(); + + do { + OutputStream out = Files.newOutputStream(path); + close.offer(out); + try { + out.write(27); + } catch (AsynchronousCloseException ace) { + System.err.println("AsynchronousCloseException caught"); + break; + } catch (ClosedChannelException ignored) { + } catch (Throwable t) { + fail("Write error", t); + } + } while (true); + } finally { + close.offer(STOP); + closeThread.join(); + } + } +} From bd4c0f4a7da9122527dd25df74797c42deaced3c Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 27 Aug 2025 15:30:17 +0000 Subject: [PATCH 021/295] 8358618: UnsupportedOperationException constructors javadoc is not clear Reviewed-by: liach, aivanov, rriggs --- .../lang/UnsupportedOperationException.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/lang/UnsupportedOperationException.java b/src/java.base/share/classes/java/lang/UnsupportedOperationException.java index 8fd0ede6252..6e42dc43009 100644 --- a/src/java.base/share/classes/java/lang/UnsupportedOperationException.java +++ b/src/java.base/share/classes/java/lang/UnsupportedOperationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +37,17 @@ package java.lang; */ public class UnsupportedOperationException extends RuntimeException { /** - * Constructs an UnsupportedOperationException with no detail message. + * Constructs a new {@code UnsupportedOperationException} with {@code null} + * as its detail message. The cause is not initialized, and may subsequently + * be initialized by a call to {@link #initCause(Throwable)}. */ public UnsupportedOperationException() { } /** - * Constructs an UnsupportedOperationException with the specified - * detail message. + * Constructs a new {@code UnsupportedOperationException} with the specified + * detail message. The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable)}. * * @param message the detail message */ @@ -53,8 +56,8 @@ public class UnsupportedOperationException extends RuntimeException { } /** - * Constructs a new exception with the specified detail message and - * cause. + * Constructs a new {@code UnsupportedOperationException} with the specified + * detail message and cause. * *

    Note that the detail message associated with {@code cause} is * not automatically incorporated in this exception's detail @@ -73,8 +76,9 @@ public class UnsupportedOperationException extends RuntimeException { } /** - * Constructs a new exception with the specified cause and a detail - * message of {@code (cause==null ? null : cause.toString())} (which + * Constructs a new {@code UnsupportedOperationException} with the specified + * cause and a detail message of + * {@code (cause==null ? null : cause.toString())} (which * typically contains the class and detail message of {@code cause}). * This constructor is useful for exceptions that are little more than * wrappers for other throwables (for example, {@link From 075ddef831f059cad1639bb6834a0923e725e15f Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 27 Aug 2025 17:49:17 +0000 Subject: [PATCH 022/295] 8364039: Adding implNote to DOMSignContext and DOMValidateContext on JDK-specific properties Reviewed-by: mullan --- .../xml/crypto/dsig/dom/DOMSignContext.java | 6 ++- .../crypto/dsig/dom/DOMValidateContext.java | 38 ++++++++++++------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java index 46748166060..566217cbaed 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java @@ -33,6 +33,7 @@ import javax.xml.crypto.dsig.XMLSignContext; import javax.xml.crypto.dsig.XMLSignature; import java.security.Key; import java.security.PrivateKey; +import java.security.Provider; import java.security.SecureRandom; import java.security.Signature; @@ -51,9 +52,12 @@ import org.w3c.dom.Node; * instance to sign two different {@link XMLSignature} objects). * * @implNote - * The JDK implementation supports the following property that can be set + * The JDK implementation supports the following properties that can be set * using the {@link #setProperty setProperty} method. *

      + *
    • org.jcp.xml.dsig.internal.dom.SignatureProvider: value + * must be a {@link Provider}. If specified, the underlying {@code Signature} + * will be instantiated from this provider. *
    • jdk.xmldsig.SecureRandom: value must be a * {@link SecureRandom}. If specified, this object will be * used to initialize the underlying {@code Signature} during signing diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java index 8e63305d177..82e7f0ce24e 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.XMLValidateContext; import java.security.Key; +import java.security.Provider; + import org.w3c.dom.Node; /** @@ -52,18 +54,28 @@ import org.w3c.dom.Node; * instance to validate two different {@link XMLSignature} objects). * * @implNote - * By default, the JDK implementation enables a secure validation mode by - * setting the org.jcp.xml.dsig.secureValidation property to - * Boolean.TRUE (see the {@link #setProperty setProperty} - * method). When enabled, validation of XML signatures are subject to - * stricter checking of algorithms and other constraints as specified by the - * jdk.xml.dsig.secureValidationPolicy security property. - * The mode can be disabled by setting the property to {@code Boolean.FALSE}. - * The mode can also be enabled or disabled by setting the - * {@systemProperty org.jcp.xml.dsig.secureValidation} system property to - * "true" or "false". Any other value for the system property is also treated - * as "false". If the system property is set, it supersedes the - * {@code DOMValidateContext} property value. + * The JDK implementation supports the following properties that can be set + * using the {@link #setProperty setProperty} method. + *
        + *
      • org.jcp.xml.dsig.secureValidation: value must be a + * {@link Boolean}. When enabled, validation of XML signatures are subject + * to stricter checking of algorithms and other constraints as specified by the + * jdk.xml.dsig.secureValidationPolicy security property. + * The default value if not specified is Boolean.TRUE. + * The mode can be disabled by setting the property to {@code Boolean.FALSE}. + * The mode can also be enabled or disabled by setting the + * {@systemProperty org.jcp.xml.dsig.secureValidation} system property to + * "true" or "false". Any other value for the system property is also treated + * as "false". If the system property is set, it supersedes the + * {@code DOMValidateContext} property value. + *
      • org.jcp.xml.dsig.validateManifests: value + * must be a {@link Boolean}. If enabled, the references in manifest + * elements (if exist) are validated during signature validation. + * The default value if not specified is Boolean.FALSE. + *
      • org.jcp.xml.dsig.internal.dom.SignatureProvider: value + * must be a {@link Provider}. If specified, the underlying {@code Signature} + * will be instantiated from this provider. + *
      * * @author Sean Mullan * @author JSR 105 Expert Group From 501e6aed4407d63b000320168dc5d0553ce8a23b Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 28 Aug 2025 05:02:25 +0000 Subject: [PATCH 023/295] 8366223: ZGC: ZPageAllocator::cleanup_failed_commit_multi_partition is broken Reviewed-by: stefank, jsikstro --- src/hotspot/share/gc/z/zPageAllocator.cpp | 2 +- .../share/gc/z/zPhysicalMemoryManager.cpp | 13 ++- src/hotspot/share/gc/z/z_globals.hpp | 5 + .../hotspot/jtreg/gc/z/TestCommitFailure.java | 104 ++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/gc/z/TestCommitFailure.java diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index ba0ab923e11..d8f653cc7d0 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1941,7 +1941,7 @@ void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAlloca } const size_t committed = allocation->committed_capacity(); - const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested()); + const ZVirtualMemory non_harvested_vmem = partial_vmem.last_part(allocation->harvested()); const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed); const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed); diff --git a/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp b/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp index 2c2f9988d4b..54477d19a27 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp +++ b/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp @@ -214,9 +214,20 @@ void ZPhysicalMemoryManager::free(const ZVirtualMemory& vmem, uint32_t numa_id) }); } +static size_t inject_commit_limit(const ZVirtualMemory& vmem) { + // To facilitate easier interoperability with multi partition allocations we + // divide by ZNUMA::count(). Users of ZFailLargerCommits need to be aware of + // this when writing tests. In the future we could probe the VirtualMemoryManager + // and condition this division on whether the vmem is in the multi partition + // address space. + return align_up(MIN2(ZFailLargerCommits / ZNUMA::count(), vmem.size()), ZGranuleSize); +} + size_t ZPhysicalMemoryManager::commit(const ZVirtualMemory& vmem, uint32_t numa_id) { zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); - const size_t size = vmem.size(); + const size_t size = ZFailLargerCommits > 0 + ? inject_commit_limit(vmem) + : vmem.size(); size_t total_committed = 0; diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index d818cf9fc3f..b1a4ae4c898 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -118,6 +118,11 @@ develop(bool, ZVerifyOops, false, \ "Verify accessed oops") \ \ + develop(size_t, ZFailLargerCommits, 0, \ + "Commits larger than ZFailLargerCommits will be truncated, " \ + "used to stress page allocation commit failure paths " \ + "(0: Disabled)") \ + \ develop(uint, ZFakeNUMA, 1, \ "ZFakeNUMA is used to test the internal NUMA memory support " \ "without the need for UseNUMA") \ diff --git a/test/hotspot/jtreg/gc/z/TestCommitFailure.java b/test/hotspot/jtreg/gc/z/TestCommitFailure.java new file mode 100644 index 00000000000..c1babe7eb83 --- /dev/null +++ b/test/hotspot/jtreg/gc/z/TestCommitFailure.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 gc.z; + +/* + * @test id=ZFakeNUMA + * @requires vm.gc.Z & vm.debug + * @library / /test/lib + * @summary Test ZGC graceful failure when a commit fails (with ZFakeNUMA) + * @run driver gc.z.TestCommitFailure -XX:ZFakeNUMA=16 + */ + +import jdk.test.lib.process.ProcessTools; + +import static gc.testlibrary.Allocation.blackHole; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class TestCommitFailure { + static final int K = 1024; + static final int M = 1024 * K; + + static final int XMS = 128 * M; + static final int XMX = 512 * M; + + static class Test { + static final int LARGE_ALLOC = 256 * M; + static final int SMALL_GARBAGE = 256 * M; + static final int SMALL_LIVE = 128 * M; + + // Allocates at least totalLive bytes of objects and add them to list. + static void allocLive(List list, int totalLive) { + final int largePageAllocationSize = 6 * M; + for (int live = 0; live < totalLive; live += largePageAllocationSize) { + list.add(new byte[largePageAllocationSize - K]); + } + } + + // Allocates at least totalGarbage bytes of garbage large pages. + static void allocGarbage(int totalGarbage) { + final int largePageAllocationSize = 6 * M; + for (int garbage = 0; garbage < totalGarbage; garbage += largePageAllocationSize) { + blackHole(new byte[largePageAllocationSize - K]); + } + } + + public static void main(String[] args) { + final var list = new ArrayList(); + try { + // Fill heap with small live objects + allocLive(list, SMALL_LIVE); + // Fill with small garbage objects + allocGarbage(SMALL_GARBAGE); + // Allocate large objects where commit fails until an OOME is thrown + while (true) { + list.add(new byte[LARGE_ALLOC - K]); + } + } catch (OutOfMemoryError oome) {} + blackHole(list); + } + } + + public static void main(String[] args) throws Exception { + final int xmxInM = XMX / M; + final int xmsInM = XMS / M; + final var arguments = new ArrayList(Arrays.asList(args)); + arguments.addAll(List.of( + "-XX:+UseZGC", + "-Xlog:gc+init", + "-XX:ZFailLargerCommits=" + XMS, + "-Xms" + xmsInM + "M", + "-Xmx" + xmxInM + "M", + Test.class.getName())); + + ProcessTools.executeTestJava(arguments) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("Forced to lower max Java heap size") + .shouldHaveExitValue(0); + } +} From 443b17263876355ef508ae68ddad6c108de29db8 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 28 Aug 2025 05:53:23 +0000 Subject: [PATCH 024/295] 8324751: C2 SuperWord: Aliasing Analysis runtime check Reviewed-by: kvn, mhaessig --- .../share/compiler/compilerDefinitions.cpp | 5 + src/hotspot/share/opto/c2_globals.hpp | 9 + src/hotspot/share/opto/graphKit.cpp | 4 +- src/hotspot/share/opto/loopUnswitch.cpp | 2 + src/hotspot/share/opto/loopnode.cpp | 16 +- src/hotspot/share/opto/mempointer.cpp | 189 ++- src/hotspot/share/opto/mempointer.hpp | 420 +++++- src/hotspot/share/opto/predicates.hpp | 53 +- src/hotspot/share/opto/superword.cpp | 20 +- src/hotspot/share/opto/superword.hpp | 2 + .../share/opto/superwordVTransformBuilder.cpp | 15 +- .../share/opto/traceAutoVectorizationTag.hpp | 1 + src/hotspot/share/opto/vectorization.cpp | 790 +++++++++- src/hotspot/share/opto/vectorization.hpp | 122 +- src/hotspot/share/opto/vtransform.cpp | 242 +++- src/hotspot/share/opto/vtransform.hpp | 115 +- .../TestVectorizationMismatchedAccess.java | 88 +- .../loopopts/superword/TestAliasing.java | 516 +++++++ .../superword/TestAliasingFuzzer.java | 1284 +++++++++++++++++ .../superword/TestCyclicDependency.java | 172 ++- .../superword/TestDependencyOffsets.java | 4 +- .../loopopts/superword/TestMemorySegment.java | 71 +- .../superword/TestMemorySegmentAliasing.java | 914 ++++++++++++ .../superword/TestMemorySegment_8359688.java | 98 ++ .../superword/TestMemorySegment_8360204.java | 90 ++ .../superword/TestMemorySegment_8365982.java | 98 ++ .../loopopts/superword/TestSplitPacks.java | 310 +++- .../runner/LoopArrayIndexComputeTest.java | 105 +- .../bench/vm/compiler/VectorAliasing.java | 308 ++++ 29 files changed, 5812 insertions(+), 251 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index fa894559fef..35201973dfe 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -621,5 +621,10 @@ void CompilerConfig::ergo_initialize() { // blind guess LoopStripMiningIterShortLoop = LoopStripMiningIter / 10; } + if (UseAutoVectorizationSpeculativeAliasingChecks && !LoopMultiversioning && !UseAutoVectorizationPredicate) { + warning("Disabling UseAutoVectorizationSpeculativeAliasingChecks, because neither of the following is enabled:" + " LoopMultiversioning UseAutoVectorizationPredicate"); + UseAutoVectorizationSpeculativeAliasingChecks = false; + } #endif // COMPILER2 } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 3a2d4cbdf96..0a4f231c49b 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -359,6 +359,15 @@ develop(bool, TraceLoopMultiversioning, false, \ "Trace loop multiversioning") \ \ + product(bool, UseAutoVectorizationPredicate, true, DIAGNOSTIC, \ + "Use AutoVectorization predicate (for speculative compilation)") \ + \ + product(bool, UseAutoVectorizationSpeculativeAliasingChecks, true, DIAGNOSTIC, \ + "Allow the use Multiversioning or Predicate to add aliasing" \ + "runtime checks. Runtime checks will only be inserted if either" \ + "LoopMultiversioning or UseAutoVectorizationPredicate are" \ + "enabled.") \ + \ product(bool, AllowVectorizeOnDemand, true, \ "Globally suppress vectorization set in VectorizeMethod") \ \ diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index d65239ab0f8..d4776d9d2f0 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4076,7 +4076,9 @@ void GraphKit::add_parse_predicates(int nargs) { add_parse_predicate(Deoptimization::Reason_profile_predicate, nargs); } } - add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, nargs); + if (UseAutoVectorizationPredicate) { + add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, nargs); + } // Loop Limit Check Predicate should be near the loop. add_parse_predicate(Deoptimization::Reason_loop_limit_check, nargs); } diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index a8d9a5d740b..b40a0492df5 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -481,6 +481,8 @@ void PhaseIdealLoop::do_multiversioning(IdealLoopTree* lpt, Node_List& old_new) // | // slow_path // +// For more descriptions on multiversioning: +// See: PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks IfTrueNode* PhaseIdealLoop::create_new_if_for_multiversion(IfTrueNode* multiversioning_fast_proj) { // Give all nodes in the old sub-graph a name. IfNode* multiversion_if = multiversioning_fast_proj->in(0)->as_If(); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 2c604e6d478..da2252f3d53 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -31,6 +31,7 @@ #include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/arraycopynode.hpp" +#include "opto/c2_globals.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" #include "opto/connode.hpp" @@ -1133,11 +1134,13 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { } } - // We only want to use the auto-vectorization check as a trap once per bci. And - // PhaseIdealLoop::add_parse_predicate only checks trap limits per method, so - // we do a custom check here. - if (!C->too_many_traps(cloned_sfpt->jvms()->method(), cloned_sfpt->jvms()->bci(), Deoptimization::Reason_auto_vectorization_check)) { - add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); + if (UseAutoVectorizationPredicate) { + // We only want to use the auto-vectorization check as a trap once per bci. And + // PhaseIdealLoop::add_parse_predicate only checks trap limits per method, so + // we do a custom check here. + if (!C->too_many_traps(cloned_sfpt->jvms()->method(), cloned_sfpt->jvms()->bci(), Deoptimization::Reason_auto_vectorization_check)) { + add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); + } } add_parse_predicate(Deoptimization::Reason_loop_limit_check, inner_head, outer_ilt, cloned_sfpt); @@ -4642,6 +4645,9 @@ void IdealLoopTree::dump_head() { tty->print(" predicated"); } } + if (UseAutoVectorizationPredicate && predicates.auto_vectorization_check_block()->is_non_empty()) { + tty->print(" auto_vectorization_check_predicate"); + } if (_head->is_CountedLoop()) { CountedLoopNode *cl = _head->as_CountedLoop(); tty->print(" counted"); diff --git a/src/hotspot/share/opto/mempointer.cpp b/src/hotspot/share/opto/mempointer.cpp index 0dadc14a686..a63ba8ef701 100644 --- a/src/hotspot/share/opto/mempointer.cpp +++ b/src/hotspot/share/opto/mempointer.cpp @@ -41,13 +41,22 @@ MemPointer::MemPointer(const MemNode* mem, MemPointer MemPointerParser::parse(MemPointerParserCallback& callback NOT_PRODUCT(COMMA const TraceMemPointer& trace)) { assert(_worklist.is_empty(), "no prior parsing"); + assert(_raw_summands.is_empty(), "no prior parsing"); assert(_summands.is_empty(), "no prior parsing"); Node* pointer = _mem->in(MemNode::Address); const jint size = _mem->memory_size(); +#ifndef PRODUCT + if (trace.is_trace_parsing()) { + tty->print_cr("MemPointerParser::parse: size=%d", size); + tty->print(" mem: "); _mem->dump(); + tty->print(" pointer: "); pointer->dump(); + } +#endif + // Start with the trivial summand. - _worklist.push(MemPointerSummand(pointer, NoOverflowInt(1))); + _worklist.push(MemPointerRawSummand::make_trivial(pointer)); // Decompose the summands until only terminal summands remain. This effectively // parses the pointer expression recursively. @@ -60,11 +69,71 @@ MemPointer MemPointerParser::parse(MemPointerParserCallback& callback parse_sub_expression(_worklist.pop(), callback); } - // Bail out if there is a constant overflow. - if (_con.is_NaN()) { - return MemPointer::make_trivial(pointer, size NOT_PRODUCT(COMMA trace)); - } + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerRawSummand::print_on(tty, _raw_summands); } ) + canonicalize_raw_summands(); + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerRawSummand::print_on(tty, _raw_summands); } ) + create_summands(); + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerSummand::print_on(tty, _con, _summands); } ) + canonicalize_summands(); + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerSummand::print_on(tty, _con, _summands); } ) + + return MemPointer::make(pointer, _raw_summands, _con, _summands, size NOT_PRODUCT(COMMA trace)); +} + +void MemPointerParser::canonicalize_raw_summands() { + // We sort by: + // - int group id + // - variable idx + // This means that summands of the same int group with the same variable are consecutive. + // This simplifies the combining of summands below. + _raw_summands.sort(MemPointerRawSummand::cmp_by_int_group_and_variable_idx); + + // Combine summands of the same int group with the same variable, adding up the scales. + int pos_put = 0; + int pos_get = 0; + while (pos_get < _raw_summands.length()) { + const MemPointerRawSummand& summand = _raw_summands.at(pos_get++); + Node* variable = summand.variable(); + NoOverflowInt scaleI = summand.scaleI(); + NoOverflowInt scaleL = summand.scaleL(); + int int_group = summand.int_group(); + // Add up scale of all summands with the same variable. + while (pos_get < _raw_summands.length() && + _raw_summands.at(pos_get).int_group() == int_group && + _raw_summands.at(pos_get).variable() == variable) { + MemPointerRawSummand s = _raw_summands.at(pos_get++); + if (int_group == 0) { + assert(scaleI.is_one() && s.scaleI().is_one(), "no ConvI2L"); + scaleL = scaleL + s.scaleL(); + } else { + assert(scaleL.value() == s.scaleL().value(), "same ConvI2L, same scaleL"); + scaleI = scaleI + s.scaleI(); + } + } + // Keep summands with non-zero scale. + if (!scaleI.is_zero() && !scaleL.is_NaN()) { + _raw_summands.at_put(pos_put++, MemPointerRawSummand(variable, scaleI, scaleL, int_group)); + } + } + _raw_summands.trunc_to(pos_put); +} + +void MemPointerParser::create_summands() { + assert(_con.is_zero(), "no prior parsing"); + assert(_summands.is_empty(), "no prior parsing"); + + for (int i = 0; i < _raw_summands.length(); i++) { + const MemPointerRawSummand& raw_summand = _raw_summands.at(i); + if (raw_summand.is_con()) { + _con = _con + raw_summand.to_con(); + } else { + _summands.push(raw_summand.to_summand()); + } + } +} + +void MemPointerParser::canonicalize_summands() { // Sorting by variable idx means that all summands with the same variable are consecutive. // This simplifies the combining of summands with the same variable below. _summands.sort(MemPointerSummand::cmp_by_variable_idx); @@ -81,38 +150,36 @@ MemPointer MemPointerParser::parse(MemPointerParserCallback& callback MemPointerSummand s = _summands.at(pos_get++); scale = scale + s.scale(); } - // Bail out if scale is NaN. - if (scale.is_NaN()) { - return MemPointer::make_trivial(pointer, size NOT_PRODUCT(COMMA trace)); - } // Keep summands with non-zero scale. if (!scale.is_zero()) { _summands.at_put(pos_put++, MemPointerSummand(variable, scale)); } } _summands.trunc_to(pos_put); - - return MemPointer::make(pointer, _summands, _con, size NOT_PRODUCT(COMMA trace)); } // Parse a sub-expression of the pointer, starting at the current summand. We parse the // current node, and see if it can be decomposed into further summands, or if the current // summand is terminal. -void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, MemPointerParserCallback& callback) { +void MemPointerParser::parse_sub_expression(const MemPointerRawSummand& summand, MemPointerParserCallback& callback) { Node* n = summand.variable(); - const NoOverflowInt scale = summand.scale(); + const NoOverflowInt scaleI = summand.scaleI(); + const NoOverflowInt scaleL = summand.scaleL(); + const int int_group = summand.int_group(); const NoOverflowInt one(1); int opc = n->Opcode(); - if (is_safe_to_decompose_op(opc, scale)) { + if (is_safe_to_decompose_op(opc, scaleI * scaleL)) { switch (opc) { case Op_ConI: case Op_ConL: { - // Terminal: add to constant. + // Terminal summand. NoOverflowInt con = (opc == Op_ConI) ? NoOverflowInt(n->get_int()) : NoOverflowInt(n->get_long()); - _con = _con + scale * con; + NoOverflowInt conI = (int_group == 0) ? scaleI : scaleI * con; + NoOverflowInt conL = (int_group == 0) ? scaleL * con : scaleL; + _raw_summands.push(MemPointerRawSummand::make_con(conI, conL, int_group)); return; } case Op_AddP: @@ -122,8 +189,8 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me // Decompose addition. Node* a = n->in((opc == Op_AddP) ? 2 : 1); Node* b = n->in((opc == Op_AddP) ? 3 : 2); - _worklist.push(MemPointerSummand(a, scale)); - _worklist.push(MemPointerSummand(b, scale)); + _worklist.push(MemPointerRawSummand(a, scaleI, scaleL, int_group)); + _worklist.push(MemPointerRawSummand(b, scaleI, scaleL, int_group)); callback.callback(n); return; } @@ -134,10 +201,15 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me Node* a = n->in(1); Node* b = n->in(2); - NoOverflowInt sub_scale = NoOverflowInt(-1) * scale; + // int_group x.scaleI x.scaleL y.scaleI y.scaleL + // 2L * (x - y) 0 1 2 1 -2 + // ConvI2L(x - y) 1 1 1 -1 1 - _worklist.push(MemPointerSummand(a, scale)); - _worklist.push(MemPointerSummand(b, sub_scale)); + NoOverflowInt sub_scaleI = (int_group == 0) ? scaleI : scaleI * NoOverflowInt(-1); + NoOverflowInt sub_scaleL = (int_group == 0) ? scaleL * NoOverflowInt(-1) : scaleL; + + _worklist.push(MemPointerRawSummand(a, scaleI, scaleL, int_group)); + _worklist.push(MemPointerRawSummand(b, sub_scaleI, sub_scaleL, int_group)); callback.callback(n); return; } @@ -169,10 +241,14 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me break; } - // Accumulate scale. - NoOverflowInt new_scale = scale * factor; + // int_group x.scaleI x.scaleL + // 2L * (4L * x) 0 1 8 + // 2L * ConvI2L(4 * x) 1 4 2 - _worklist.push(MemPointerSummand(variable, new_scale)); + NoOverflowInt mul_scaleI = (int_group == 0) ? scaleI : scaleI * factor; + NoOverflowInt mul_scaleL = (int_group == 0) ? scaleL * factor : scaleL; + + _worklist.push(MemPointerRawSummand(variable, mul_scaleI, mul_scaleL, int_group)); callback.callback(n); return; } @@ -200,7 +276,16 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me { // Decompose: look through. Node* a = n->in(1); - _worklist.push(MemPointerSummand(a, scale)); + + int cast_int_group = int_group; +#ifdef _LP64 + if (opc == Op_ConvI2L) { + assert(int_group == 0, "only find ConvI2L once"); + // We just discovered a new ConvI2L, and this creates a new "int group". + cast_int_group = _next_int_group++; + } +#endif + _worklist.push(MemPointerRawSummand(a, scaleI, scaleL, cast_int_group)); callback.callback(n); return; } @@ -212,7 +297,7 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me } // Default: we could not parse the "summand" further, i.e. it is terminal. - _summands.push(summand); + _raw_summands.push(summand); } bool MemPointerParser::sub_expression_has_native_base_candidate(Node* start) { @@ -618,3 +703,55 @@ bool MemPointer::never_overlaps_with(const MemPointer& other) const { return is_never_overlap; } +// Examples: +// p1 = MemPointer[size=1, base + i + 16] +// p2 = MemPointer[size=1, base + i + 17] +// -> Always at distance 1 +// -> Can never overlap -> return false +// +// p1 = MemPointer[size=1, base + i + 16] +// p2 = MemPointer[size=1, base + i + 16] +// -> Always at distance 0 +// -> Always have exact overlap -> return true +// +// p1 = MemPointer[size=4, x + y + z + 4L * i + 16] +// p2 = MemPointer[size=4, x + y + z + 4L * i + 56] +// -> Always at distance 40 +// -> Can never overlap -> return false +// +// p1 = MemPointer[size=8, x + y + z + 4L * i + 16] +// p2 = MemPointer[size=8, x + y + z + 4L * i + 20] +// -> Always at distance 4 +// -> Always have partial overlap -> return true +// +// p1 = MemPointer[size=4, base1 + 4L * i1 + 16] +// p2 = MemPointer[size=4, base2 + 4L * i2 + 20] +// -> Have differing summands, distance is unknown +// -> Unknown if overlap at runtime -> return false +bool MemPointer::always_overlaps_with(const MemPointer& other) const { + const MemPointerAliasing aliasing = get_aliasing_with(other NOT_PRODUCT( COMMA _trace )); + + // The aliasing tries to compute: + // distance = other - this + // + // We know that we have an overlap if we can prove: + // this < other + other.size && this + this.size > other + // + // Which we can restate as: + // distance > -other.size && this.size > distance + // + const jint distance_lo = -other.size(); + const jint distance_hi = size(); + bool is_always_overlap = aliasing.is_always_in_distance_range(distance_lo, distance_hi); + +#ifndef PRODUCT + if (_trace.is_trace_overlap()) { + tty->print("Always Overlap: %s, distance_lo: %d, distance_hi: %d, aliasing: ", + is_always_overlap ? "true" : "false", distance_lo, distance_hi); + aliasing.print_on(tty); + tty->cr(); + } +#endif + + return is_always_overlap; +} diff --git a/src/hotspot/share/opto/mempointer.hpp b/src/hotspot/share/opto/mempointer.hpp index 90216a5e2d3..5fe9d78a61e 100644 --- a/src/hotspot/share/opto/mempointer.hpp +++ b/src/hotspot/share/opto/mempointer.hpp @@ -41,6 +41,10 @@ // - alignment -> find an alignment solution for all memops in a vectorized loop // - detect partial overlap -> indicates store-to-load-forwarding failures // +// A more advanced use case of MemPointers is speculative aliasing analysis. If we can prove that +// the MemPointer has a linear form in the loop induction variable (iv), we can formulate runtime +// checks to establish that two MemPointer never overlap for all iterations, i.e. for all iv values. +// // ----------------------------------------------------------------------------------------- // // Intuition and Examples: @@ -158,7 +162,7 @@ // // pointer = SUM(summands) + con // -// Where each summand_i in summands has the form: +// Where each summand_i in summands has the MemPointerSummand form: // // summand_i = scale_i * variable_i // @@ -267,6 +271,10 @@ // the idea of a "safe decomposition", and then prove that all the decompositions we apply // are such "safe decompositions". // +// Even further down, we prove the "MemPointer Linearity Corrolary", where we show that +// (under reasonable restrictions) both the MemPointer and the corresponding pointer +// can be considered linear functions. +// // // Definition: Safe decomposition // Trivial decomposition: @@ -385,7 +393,103 @@ // // This shows that p1 and p2 have a distance greater than the array size, and hence at least one of the two // pointers must be out of bounds. This contradicts our assumption (S1) and we are done. - +// +// +// Having proven the "MemPointer Lemma", we can now derive an interesting corrolary. +// +// With the "Linearity Corrolary" below, we can prove that some MemPointers can be treated as +// linear in some summand variable v over some range r. This is useful when MemPointers are +// used in loops, where v=iv scale_v=scale_iv and the range is the iv range from some initial +// iv value to the last iv value just before the limit. +// For an application, see: VPointer::make_speculative_aliasing_check_with +// +// MemPointer Linearity Corrolary: +// Given: +// (C0) pointer p and its MemPointer mp, which is constructed with safe decompositions. +// (C1) a specific summand "scale_v * v" that occurs in mp. +// (C2) a strided range r = [lo, lo + stride_v, .. hi] for v (lo and hi are inclusive in the range). +// (C3) for all v in this strided range r we know that p is within bounds of its memory object. +// (C4) abs(scale_v * stride_v) < 2^31 +// Required for (S2) in application of MemPointer Lemma below, it is essencial in +// establishing linearity of mp. +// +// Then: +// Both p and mp have a linear form for v in r: +// p(v) = p(lo) - lo * scale_v + v * scale_v (Corrolary P) +// mp(v) = mp(lo) - lo * scale_v + v * scale_v (Corrolary MP) +// +// Note: the calculations are done in long, and hence there can be no int overflow. +// Thus, p(v) and mp(v) can be considered linear functions for v in r. +// +// It can be useful to "anchor" at hi instead of lo: +// p(hi) = p(lo) - lo * scale_v + hi * scale_v +// +// p(v) = p(lo) - lo * scale_v + v * scale_v +// -------------------- +// = p(hi) - hi * scale_v + v * scale_v (Alternative Corrolary P) +// +// +// Proof of "MemPointer Linearity Corrolary": +// We state the form of mp: +// +// mp = summand_rest + scale_v * v + con +// +// We prove the Corrolary by induction over v: +// Base Case: v = lo +// p(lo) = p(lo) - lo * scale_v + lo * scale_v +// mp(lo) = mp(lo) - lo * scale_v + lo * scale_v +// +// Step Case: v0 and v1 in r, v1 = v0 + stride_v +// Assume: +// p(v0) = p(lo) - lo * scale_v + v * scale_v (Induction Hypothesis IH-P) +// mp(v0) = mp(lo) - lo * scale_v + v * scale_v (Induction Hypothesis IH-MP) +// +// We take the form of mp, and further apply SAFE1 decompositions, i.e. long addition, +// subtraction and multiplication: +// mp(v1) = summand_rest + scale_v * v1 + con +// = summand_rest + scale_v * (v0 + stride_v) + con +// = summand_rest + scale_v * v0 + scale_v * stride_v + con +// = mp(v0) + scale_v * stride_v +// +// From this it follows that we can see mp(v0) and mp(v1) as two MemPointer with the +// same summands, and only their constants differ by exactly "scale_v * stride_v": +// mp(v0) = summand_rest + scale_v * v0 + con +// mp(v1) = summand_rest + scale_v * v0 + con + scale_v * stride_v (MP-DIFF) +// +// We continue by applying the Induction Hypothesis IH-MP +// mp(v1) = mp(v0) + scale_v * stride_v +// -------- apply (IH-MP) ------------- +// = mp(lo) - lo * scale_v + v0 * scale_v + scale_v * stride_v +// = mp(lo) - lo * scale_v + (v0 + stride_v) * scale_v +// = mp(lo) - lo * scale_v + v1 * scale_v +// +// This proves the Corrolary MP. +// +// To prove the Corrolary P, we now apply the MemPointer Lemma: +// (S0) Let p(v0) and p(v1) be the pointers corresponding to v0 and v1, and mp(v0) and mp(v1) +// their MemPointer. (C0) provides the safe deconstruction, and reformulation of terms +// happens with long addition, subtraction and multiplication only, and is hence SAFE +// as well. +// (S1) According to (C3), p is in bounds of its memory object for all v in r. Since v0 and +// v1 are in r, it follows that p(v0) and p(v1) are in bounds of the same memory object. +// (S2) The difference of constants of mp(v0) and mp(v1) is exactly "scale_v * stride_v" (MP-DIFF). +// Given (C4), this difference is not too large. +// (S3) All summands of mp0 and mp1 are the same (only the constants differ), given (MP-DIFF). +// +// It follows: +// p(v1) - p(v0) = mp(v1) - mp(v0) +// +// Reformulating and applying (MP-DIFF) and (IH-P): +// p(v1) = p(v0) + mp(v1) - mp(v1) +// apply (MP-DIFF) +// = p(v0) + scale_v * stride_v +// ------------ apply (IH-P) ------------ +// = p(lo) - lo * scale_v + v0 * scale_v + scale_v * stride_v +// = p(lo) - lo * scale_v + (v0 + stride_v) * scale_v +// = p(lo) - lo * scale_v + v1 * scale_v +// +// This proves Corrolary P. +// #ifndef PRODUCT class TraceMemPointer : public StackObj { private: @@ -466,6 +570,13 @@ public: (_distance <= distance_lo || distance_hi <= _distance); } + // Use case: overlap. + // Note: the bounds are exclusive: lo < element < hi + bool is_always_in_distance_range(const jint distance_lo, const jint distance_hi) const { + return _aliasing == AlwaysAtDistance && + (distance_lo < _distance && _distance < distance_hi); + } + #ifndef PRODUCT void print_on(outputStream* st) const { switch(_aliasing) { @@ -540,7 +651,167 @@ public: #ifndef PRODUCT void print_on(outputStream* st) const { _scale.print_on(st); - tty->print(" * [%d %s]", _variable->_idx, _variable->Name()); + st->print(" * [%d %s]", _variable->_idx, _variable->Name()); + } + + static void print_on(outputStream* st, NoOverflowInt con, const GrowableArray& summands) { + st->print("Summands (%d): con(", summands.length()); + con.print_on(st); + st->print(")"); + for (int i = 0; i < summands.length(); i++) { + st->print(" + "); + summands.at(i).print_on(tty); + } + st->cr(); + } +#endif +}; + +// We need two different ways of tracking the summands: +// - MemPointerRawSummand: designed to keep track of the original form of +// the pointer, preserving its overflow behavior. +// - MemPointerSummand: designed to allow simplification of the MemPointer +// form, does not preserve the original form and +// ignores overflow from ConvI2L. +// +// The MemPointerSummand is designed to allow the simplification of +// the MemPointer form as much as possible, to allow aliasing checks +// to be as simple as possible. For example, the C2 IR pointer: +// +// pointer = AddP( +// AddP( +// base, +// LShiftL( +// ConvI2L( +// AddI(AddI(i, LShiftI(j, 2)), con1) +// ), +// 1 +// ) +// ), +// con2 +// ) +// +// and more readable: +// +// pointer = base + 2L * ConvI2L(i + 4 * j + con1) + con2 +// +// is simplified to this MemPointer form, using only MemPointerSummands, +// which ignore the possible overflow in ConvI2L: +// +// pointer = base + 2L * ConvI2L(i) + 8L * ConvI2L(j) + con +// con = 2L * con1 + con2 +// +// This is really convenient, because this way we are able to ignore +// the ConvI2L in the aliasing anaylsis computation, and we can collect +// all constants to a single constant. Even with this simplicication, +// we are able to prove the correctness of the aliasing checks. +// +// However, there is one thing we are not able to do with this simplification: +// we cannot reconstruct the original pointer expression, because the +// simplification ignores overflows that could happen inside the ConvI2L: +// +// 2L * ConvI2L(i + 4 * j + con1) != 2L * ConvI2L(i) + 8L * ConvI2L(j) + 2L * con1 +// +// The MemPointerRawSummand is designed to keep track of the original form +// of the pointer, preserving its overflow behaviour. We observe that the +// only critical point for overflows is at the ConvI2L. Thus, we give each +// ConvI2L a "int group" id > 0, and all raw summands belonging to that ConvI2L +// have that id. This allows us to reconstruct which raw summands need to +// be added together before the ConvI2L. Any raw summands that do not belong +// to a ConvI2L (i.e. the summands with long variables) have "int group" +// id = 0, since they do not belong to any such "int group" and can be +// directly added together. For raw summands belonging to an "int group", +// we need to track the scale inside (scaleI) and outside (scaleL) the +// ConvI2L. With the example from above: +// +// pointer = base + 2L * ConvI2L(i + 4 * j + con1) + con2 +// +// _variable = base _variable = i _variable = j _variable = null _variable = null +// _scaleI = 1 _scaleI = 1 _scaleI = 4 _scaleI = con1 _scaleI = 1 +// _scaleL = 1 _scaleL = 2 _scaleL = 2 _scaleL = 2 _scaleL = con2 +// _int_group = 0 _int_group = 1 _int_group = 1 _int_group = 1 _int_group = 0 +// +// Note: we also need to track constants as separate raw summands. For +// this, we say that a raw summand tracks a constant iff _variable == null, +// and we store the constant value in _scaleI (for int constant) and in +// _scaleL (for long constants). +// +class MemPointerRawSummand : public StackObj { +private: + Node* _variable; + NoOverflowInt _scaleI; + NoOverflowInt _scaleL; + int _int_group; + +public: + MemPointerRawSummand(Node* variable, NoOverflowInt scaleI, NoOverflowInt scaleL, int int_group) : + _variable(variable), _scaleI(scaleI), _scaleL(scaleL), _int_group(int_group) {} + + MemPointerRawSummand() : + MemPointerRawSummand(nullptr, NoOverflowInt::make_NaN(), NoOverflowInt::make_NaN(), -1) {} + + static MemPointerRawSummand make_trivial(Node* variable) { + assert(variable != nullptr, "must have variable"); + return MemPointerRawSummand(variable, NoOverflowInt(1), NoOverflowInt(1), 0); + } + + static MemPointerRawSummand make_con(NoOverflowInt scaleI, NoOverflowInt scaleL, int int_group) { + return MemPointerRawSummand(nullptr, scaleI, scaleL, int_group); + } + + bool is_valid() const { return _int_group >= 0; } + bool is_con() const { assert(is_valid(), ""); return _variable == nullptr; } + Node* variable() const { assert(is_valid(), ""); return _variable; } + NoOverflowInt scaleI() const { assert(is_valid(), ""); return _scaleI; } + NoOverflowInt scaleL() const { assert(is_valid(), ""); return _scaleL; } + int int_group() const { assert(is_valid(), ""); return _int_group; } + + MemPointerSummand to_summand() const { + assert(!is_con(), "must be variable"); + return MemPointerSummand(variable(), scaleL() * scaleI()); + } + + NoOverflowInt to_con() const { + assert(is_con(), "must be constant"); + return scaleL() * scaleI(); + } + + static int cmp_by_int_group_and_variable_idx(MemPointerRawSummand* p1, MemPointerRawSummand* p2) { + int int_group_diff = p1->int_group() - p2->int_group(); + if (int_group_diff != 0) { return int_group_diff; } + + if (p1->is_con()) { + return p2->is_con() ? 0 : 1; + } + if (p2->is_con()) { + return -1; + } + return p1->variable()->_idx - p2->variable()->_idx; + } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + if (!is_valid()) { + st->print(""); + } else { + st->print("<%d: ", _int_group); + _scaleL.print_on(st); + st->print(" * "); + _scaleI.print_on(st); + if (!is_con()) { + st->print(" * [%d %s]", _variable->_idx, _variable->Name()); + } + st->print(">"); + } + } + + static void print_on(outputStream* st, const GrowableArray& summands) { + st->print("Raw Summands (%d): ", summands.length()); + for (int i = 0; i < summands.length(); i++) { + if (i > 0) { st->print(" + "); } + summands.at(i).print_on(tty); + } + st->cr(); } #endif }; @@ -582,10 +853,13 @@ public: // class MemPointer : public StackObj { public: - // We limit the number of summands to 10. This is just a best guess, and not at this - // point supported by evidence. But I think it is reasonable: usually, a pointer - // contains a base pointer (e.g. array pointer or null for native memory) and a few - // variables. It should be rare that we have more than 9 variables. + // We limit the number of summands to 10, and the raw summands to 16. This is just a + // best guess, and not at this point supported by evidence. But I think it is reasonable: + // usually, a pointer contains a base pointer (e.g. array pointer or null for native memory) + // and a few variables. It should be rare that we have more than 9 variables. We need + // a few more raw summands, especially because there can be multiple constants, one + // per ConvI2L "int group". + static const int RAW_SUMMANDS_SIZE = 16; static const int SUMMANDS_SIZE = 10; // A base can be: @@ -637,10 +911,20 @@ public: }; private: + // Raw summands: represent the pointer form exactly, allowing the reconstruction of the + // pointer expression. Overflows inside the "int groups" (i.e. ConvI2L) + // are preserved, and there may be multiple constants. + MemPointerRawSummand _raw_summands[RAW_SUMMANDS_SIZE]; + + // Summands: Simplified form, with only a single constant. Makes aliasing analysis + // much simpler. MemPointerSummand _summands[SUMMANDS_SIZE]; const NoOverflowInt _con; const Base _base; + + // Size in bytes for the referenced memory region: [pointer, pointer + size) const jint _size; + NOT_PRODUCT( const TraceMemPointer& _trace; ) // Default / trivial: pointer = 0 + 1 * pointer @@ -659,6 +943,7 @@ private: // pointer = SUM(SUMMANDS) + con MemPointer(Node* pointer, + const GrowableArray& raw_summands, const GrowableArray& summands, const NoOverflowInt& con, const jint size @@ -670,14 +955,25 @@ private: { assert(!_con.is_NaN(), "non-NaN constant"); assert(summands.length() <= SUMMANDS_SIZE, "summands must fit"); + assert(raw_summands.length() <= RAW_SUMMANDS_SIZE, "raw summands must fit"); #ifdef ASSERT for (int i = 0; i < summands.length(); i++) { const MemPointerSummand& s = summands.at(i); assert(s.variable() != nullptr, "variable cannot be null"); assert(!s.scale().is_NaN(), "non-NaN scale"); } + for (int i = 0; i < raw_summands.length(); i++) { + const MemPointerRawSummand& s = raw_summands.at(i); + assert(!s.scaleI().is_NaN(), "non-NaN scale"); + assert(!s.scaleL().is_NaN(), "non-NaN scale"); + } #endif + // Copy raw summands in the same order. + for (int i = 0; i < raw_summands.length(); i++) { + _raw_summands[i] = raw_summands.at(i); + } + // Put the base in the 0th summand. Node* base = _base.object_or_native_or_null(); int pos = 0; @@ -708,6 +1004,11 @@ private: NOT_PRODUCT(COMMA _trace(old._trace)) { assert(!_con.is_NaN(), "non-NaN constant"); + + for (int i = 0; i < RAW_SUMMANDS_SIZE; i++) { + _raw_summands[i] = old.raw_summands_at(i); + } + for (int i = 0; i < SUMMANDS_SIZE; i++) { _summands[i] = old.summands_at(i); } @@ -733,17 +1034,29 @@ public: } static MemPointer make(Node* pointer, + const GrowableArray& raw_summands, + const NoOverflowInt con, const GrowableArray& summands, - const NoOverflowInt& con, const jint size NOT_PRODUCT(COMMA const TraceMemPointer& trace)) { - if (summands.length() <= SUMMANDS_SIZE) { - return MemPointer(pointer, summands, con, size NOT_PRODUCT(COMMA trace)); + if (raw_summands.length() <= RAW_SUMMANDS_SIZE && + summands.length() <= SUMMANDS_SIZE && + has_no_NaN_in_con_and_summands(con, summands)) { + return MemPointer(pointer, raw_summands, summands, con, size NOT_PRODUCT(COMMA trace)); } else { return MemPointer::make_trivial(pointer, size NOT_PRODUCT(COMMA trace)); } } + static bool has_no_NaN_in_con_and_summands(const NoOverflowInt con, + const GrowableArray& summands) { + if (con.is_NaN()) { return false; } + for (int i = 0; i < summands.length(); i++) { + if (summands.at(i).scale().is_NaN()) { return false; } + } + return true; + } + MemPointer make_with_size(const jint new_size) const { return MemPointer(*this, this->con(), new_size); }; @@ -775,10 +1088,34 @@ public: return _summands[i]; } + const MemPointerRawSummand& raw_summands_at(const uint i) const { + assert(i < RAW_SUMMANDS_SIZE, "in bounds"); + return _raw_summands[i]; + } + const NoOverflowInt con() const { return _con; } const Base& base() const { return _base; } jint size() const { return _size; } + int max_int_group() const { + int n = 0; + for (int i = 0; i < RAW_SUMMANDS_SIZE; i++) { + const MemPointerRawSummand& s = _raw_summands[i]; + if (!s.is_valid()) { continue; } + n = MAX2(n, s.int_group()); + } + return n; + } + + template + void for_each_raw_summand_of_int_group(int int_group, Callback callback) const { + for (int i = 0; i < RAW_SUMMANDS_SIZE; i++) { + const MemPointerRawSummand& s = _raw_summands[i]; + if (!s.is_valid() || s.int_group() != int_group) { continue; } + callback(s); + } + } + static int cmp_summands(const MemPointer& a, const MemPointer& b) { for (int i = 0; i < SUMMANDS_SIZE; i++) { const MemPointerSummand& s_a = a.summands_at(i); @@ -801,6 +1138,7 @@ public: bool is_adjacent_to_and_before(const MemPointer& other) const; bool never_overlaps_with(const MemPointer& other) const; + bool always_overlaps_with(const MemPointer& other) const; #ifndef PRODUCT void print_form_on(outputStream* st) const { @@ -818,13 +1156,54 @@ public: } } - void print_on(outputStream* st, bool end_with_cr = true) const { + void print_on(outputStream* st) const { st->print("MemPointer[size: %2d, base: ", size()); _base.print_on(st); st->print(", form: "); print_form_on(st); st->print("]"); - if (end_with_cr) { st->cr(); } + st->cr(); + + st->print(" raw: "); + + int long_count = 0; + for_each_raw_summand_of_int_group(0, [&] (const MemPointerRawSummand& s) { + if (long_count > 0) { st->print(" + "); } + long_count++; + if (s.is_con()) { + // Long constant. + NoOverflowInt con = s.scaleI() * s.scaleL(); + con.print_on(st); + st->print("L"); + } else { + // Long variable. + assert(s.scaleI().is_one(), "must be long variable"); + s.scaleL().print_on(st); + st->print("L * [%d %s]", s.variable()->_idx, s.variable()->Name()); + } + }); + + // Int groups, i.e. "ConvI2L(...)" + for (int int_group = 1; int_group <= max_int_group(); int_group++) { + if (long_count > 0) { st->print(" + "); } + long_count++; + int int_count = 0; + for_each_raw_summand_of_int_group(int_group, [&] (const MemPointerRawSummand& s) { + if (int_count == 0) { + s.scaleL().print_on(st); + st->print("L * ConvI2L("); + } else { + st->print(" + "); + } + int_count++; + s.scaleI().print_on(st); + if (!s.is_con()) { + st->print(" * [%d %s]", s.variable()->_idx, s.variable()->Name()); + } + }); + st->print(")"); + } + st->cr(); } #endif }; @@ -838,9 +1217,13 @@ class MemPointerParser : public StackObj { private: const MemNode* _mem; - // Internal data-structures for parsing. - NoOverflowInt _con; - GrowableArray _worklist; + // Internal data-structures for parsing raw summands. + int _next_int_group = 1; + GrowableArray _worklist; + GrowableArray _raw_summands; + + // Internal data-structures for parsing "regular" summands. + NoOverflowInt _con = NoOverflowInt(0); GrowableArray _summands; // Resulting decomposed-form. @@ -850,7 +1233,6 @@ private: MemPointerParserCallback& callback NOT_PRODUCT(COMMA const TraceMemPointer& trace)) : _mem(mem), - _con(NoOverflowInt(0)), _mem_pointer(parse(callback NOT_PRODUCT(COMMA trace))) {} public: @@ -881,10 +1263,14 @@ private: MemPointer parse(MemPointerParserCallback& callback NOT_PRODUCT(COMMA const TraceMemPointer& trace)); - void parse_sub_expression(const MemPointerSummand& summand, MemPointerParserCallback& callback); + void parse_sub_expression(const MemPointerRawSummand& summand, MemPointerParserCallback& callback); static bool sub_expression_has_native_base_candidate(Node* n); bool is_safe_to_decompose_op(const int opc, const NoOverflowInt& scale) const; + + void canonicalize_raw_summands(); + void create_summands(); + void canonicalize_summands(); }; #endif // SHARE_OPTO_MEMPOINTER_HPP diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index ef7c5600853..32b1c1cd3c4 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_OPTO_PREDICATES_HPP #define SHARE_OPTO_PREDICATES_HPP +#include "opto/c2_globals.hpp" #include "opto/cfgnode.hpp" #include "opto/opaquenode.hpp" #include "opto/predicates_enums.hpp" @@ -44,12 +45,15 @@ class TemplateAssertionPredicate; * - Parse Predicate: Added during parsing to capture the current JVM state. This predicate represents a "placeholder" * above which Regular Predicates can be created later after parsing. * - * There are initially three Parse Predicates for each loop: - * - Loop Parse Predicate: The Parse Predicate added for Loop Predicates. - * - Profiled Loop Parse Predicate: The Parse Predicate added for Profiled Loop Predicates. - * - Loop Limit Check Parse Predicate: The Parse Predicate added for a Loop Limit Check Predicate. + * There are initially five Parse Predicates for each loop: + * - Loop Parse Predicate: The Parse Predicate added for Loop Predicates. + * - Profiled Loop Parse Predicate: The Parse Predicate added for Profiled Loop Predicates. + * - Loop Limit Check Parse Predicate: The Parse Predicate added for a Loop Limit Check Predicate. + * - Short Running Loop Parse Predicate: The Parse Predicate added for the short running long loop check. + * - AutoVectorization Parse Predicate: The Parse Predicate added for AutoVectorization runtime checks. * - Runtime Predicate: This term is used to refer to a Hoisted Check Predicate (either a Loop Predicate or a Profiled - * Loop Predicate) or a Loop Limit Check Predicate. These predicates will be checked at runtime while + * Loop Predicate), a Loop Limit Check Predicate, a Short Running Long Loop Predicate, or a + * AutoVectorization Runtime Check Predicate. These predicates will be checked at runtime while * the Parse and Assertion Predicates are always removed before code generation (except for * Initialized Assertion Predicates which are kept in debug builds while being removed in product * builds). @@ -81,6 +85,21 @@ class TemplateAssertionPredicate; * int counted loops with long range checks for which a loop nest also needs to be created * in the general case (so the transformation of long range checks to int range checks is * legal). + * - AutoVectorization: This predicate is used for speculative runtime checks required for AutoVectorization. + * Runtime Check There are multiple reasons why we need a runtime check to allow vectorization: + * Predicate - Unknown aliasing: + * An important compoinent of AutoVectorization is proving that memory addresses do not + * alias, and can therefore be reordered. In some cases, this cannot be done statically + * and a runtime check is necessary. + * - Unknown alignment of native memory: + * While heap objects have 8-byte alignment, off-heap (native) memory often has no alignment + * guarantees. On platforms that require vectors to be aligned, we need to prove alignment. + * We cannot do that statically with native memory, hence we need a runtime check. + * The benefit of using a predicate is that we only have to compile the vectorized loop. If + * the runtime check fails, we simply deoptimize. Should we eventually recompile, then the + * predicate is not available any more, and we instead use a multiversioning approach with + * both a vectorized and a scalar loop, where the runtime determines which loop is taken. + * See: PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks * - Assertion Predicate: An always true predicate which will never fail (its range is already covered by an earlier * Hoisted Check Predicate or the main-loop entry guard) but is required in order to fold away a * dead sub loop in which some data could be proven to be dead (by the type system) and replaced @@ -157,19 +176,27 @@ class TemplateAssertionPredicate; * Predicates, and the associated Parse Predicate which all share the same uncommon trap. This block * could be empty if there were no Runtime Predicates created and the Parse Predicate was already * removed. - * There are three different Predicate Blocks: + * There are five different Predicate Blocks: + * - Short Running Long Groups the Short Running Long Loop Predicate (if created), and the + * Loop Predicate Block: Short Running Long Loop Parse Predicate together. * - Loop Predicate Block: Groups the Loop Predicates (if any), including the Assertion Predicates, * and the Loop Parse Predicate (if not removed, yet) together. * - Profiled Loop Groups the Profiled Loop Predicates (if any), including the Assertion * Predicate Block: Predicates, and the Profiled Loop Parse Predicate (if not removed, yet) * together. + * - AutoVectorization Groups the AutoVectorization Runtime Check Predicates (if any), and the + * Runtime Check AutoVectorization Runtime Check Parse Predicate together. + * Predicate Block: * - Loop Limit Check Groups the Loop Limit Check Predicate (if created) and the Loop Limit * Predicate Block: Check Parse Predicate (if not removed, yet) together. * - Regular Predicate Block: A block that only contains the Regular Predicates of a Predicate Block without the * Parse Predicate. * * Initially, before applying any loop-splitting optimizations, we find the following structure after Loop Predication - * (predicates inside square brackets [] do not need to exist if there are no checks to hoist): + * (predicates inside square brackets [] do not need to exist if there are no checks to hoist / insert): + * + * [Short Running Long Loop Predicate] (at most one) \ Short Running Long + * Short Running Long Loop Parse Predicate / Loop Predicate Block * * [Loop Predicate 1 + two Template Assertion Predicates] \ * [Loop Predicate 2 + two Template Assertion Predicates] | @@ -183,6 +210,12 @@ class TemplateAssertionPredicate; * [Profiled Loop Predicate m + two Template Assertion Predicates] | * Profiled Loop Parse Predicate / * + * [AutoVectorization Runtime Check Predicate 1] \ + * [AutoVectorization Runtime Check Predicate 2] | AutoVectorization + * ... | Runtime Check + * [AutoVectorization Runtime Check Predicate l] | Predicate Block + * AutoVectorization Runtime Check Parse Predicate / + * * [Loop Limit Check Predicate] (at most one) \ Loop Limit Check * Loop Limit Check Parse Predicate / Predicate Block * Loop Head @@ -782,8 +815,10 @@ class PredicateIterator : public StackObj { Node* current_node = _start_node; PredicateBlockIterator loop_limit_check_predicate_iterator(current_node, Deoptimization::Reason_loop_limit_check); current_node = loop_limit_check_predicate_iterator.for_each(predicate_visitor); - PredicateBlockIterator auto_vectorization_check_iterator(current_node, Deoptimization::Reason_auto_vectorization_check); - current_node = auto_vectorization_check_iterator.for_each(predicate_visitor); + if (UseAutoVectorizationPredicate) { + PredicateBlockIterator auto_vectorization_check_iterator(current_node, Deoptimization::Reason_auto_vectorization_check); + current_node = auto_vectorization_check_iterator.for_each(predicate_visitor); + } if (UseLoopPredicate) { if (UseProfiledLoopPredicate) { PredicateBlockIterator profiled_loop_predicate_iterator(current_node, Deoptimization::Reason_profile_predicate); diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 2316b0bb49a..cb92febf803 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -461,6 +461,9 @@ bool SuperWord::transform_loop() { // inserting scalar promotion, vector creation from multiple scalars, and // extraction of scalar values from vectors. // +// Runtime Checks: +// Some required properties cannot be proven statically, and require a +// runtime check. See VTransform::add_speculative_check bool SuperWord::SLP_extract() { assert(cl()->is_main_loop(), "SLP should only work on main loops"); @@ -832,12 +835,18 @@ bool VLoopDependencyGraph::independent(Node* s1, Node* s2) const { Node* shallow = d1 > d2 ? s2 : s1; int min_d = MIN2(d1, d2); // prune traversal at min_d + // If we can speculate (using the aliasing runtime check), we can drop the weak edges, + // and later insert a runtime check. + // If we cannot speculate (aliasing analysis runtime checks), we need to respect all edges. + bool speculate_away_weak_edges = _vloop.use_speculative_aliasing_checks(); + ResourceMark rm; Unique_Node_List worklist; worklist.push(deep); for (uint i = 0; i < worklist.size(); i++) { Node* n = worklist.at(i); for (PredsIterator preds(*this, n); !preds.done(); preds.next()) { + if (speculate_away_weak_edges && preds.is_current_weak_memory_edge()) { continue; } Node* pred = preds.current(); if (_vloop.in_bb(pred) && depth(pred) >= min_d) { if (pred == shallow) { @@ -869,9 +878,16 @@ bool VLoopDependencyGraph::mutually_independent(const Node_List* nodes) const { worklist.push(n); // start traversal at all nodes in nodes list nodes_set.set(_body.bb_idx(n)); } + + // If we can speculate (using the aliasing runtime check), we can drop the weak edges, + // and later insert a runtime check. + // If we cannot speculate (aliasing analysis runtime checks), we need to respect all edges. + bool speculate_away_weak_edges = _vloop.use_speculative_aliasing_checks(); + for (uint i = 0; i < worklist.size(); i++) { Node* n = worklist.at(i); for (PredsIterator preds(*this, n); !preds.done(); preds.next()) { + if (speculate_away_weak_edges && preds.is_current_weak_memory_edge()) { continue; } Node* pred = preds.current(); if (_vloop.in_bb(pred) && depth(pred) >= min_d) { if (nodes_set.test(_body.bb_idx(pred))) { @@ -1936,6 +1952,7 @@ bool SuperWord::schedule_and_apply() const { VTransformTrace trace(_vloop.vtrace(), is_trace_superword_rejections(), is_trace_align_vector(), + _vloop.is_trace_speculative_aliasing_analysis(), _vloop.is_trace_speculative_runtime_checks(), is_trace_superword_info()); #endif @@ -1989,7 +2006,8 @@ void VTransform::apply() { adjust_pre_loop_limit_to_align_main_loop_vectors(); C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); - apply_speculative_runtime_checks(); + apply_speculative_alignment_runtime_checks(); + apply_speculative_aliasing_runtime_checks(); C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, 4, cl()); apply_vectorization(); diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 57a403b4498..0940e752f85 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -55,6 +55,8 @@ // Definition 3.3 A Pair is a Pack of size two, where the // first statement is considered the left element, and the // second statement is considered the right element. +// +// For more documentation, see: SuperWord::SLP_extract // The PairSet is a set of pairs. These are later combined to packs, // and stored in the PackSet. diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index 83496f9d0be..404eb02372e 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -94,7 +94,7 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } else if (p0->is_CMove()) { // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. set_all_req_with_vectors(pack, vtn); - VTransformBoolVectorNode* vtn_mask_cmp = vtn->in(1)->isa_BoolVector(); + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(1)->isa_BoolVector(); if (vtn_mask_cmp->test()._is_negated) { vtn->swap_req(2, 3); // swap if test was negated. } @@ -299,17 +299,24 @@ void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, } } -void SuperWordVTransformBuilder::add_memory_dependencies_of_node_to_vtnode(Node*n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies) { +void SuperWordVTransformBuilder::add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies) { + // If we cannot speculate, then all dependencies must be strong edges, i.e. scheduling must respect them. + bool are_speculative_checks_possible = _vloop.are_speculative_checks_possible(); + for (VLoopDependencyGraph::PredsIterator preds(_vloop_analyzer.dependency_graph(), n); !preds.done(); preds.next()) { Node* pred = preds.current(); if (!_vloop.in_bb(pred)) { continue; } if (!preds.is_current_memory_edge()) { continue; } + assert(n->is_Mem() && pred->is_Mem(), "only memory edges"); // Only track every memory edge once. VTransformNode* dependency = get_vtnode(pred); if (vtn_memory_dependencies.test_set(dependency->_idx)) { continue; } - assert(n->is_Mem() && pred->is_Mem(), "only memory edges"); - vtn->add_memory_dependency(dependency); // Add every dependency only once per vtn. + if (are_speculative_checks_possible && preds.is_current_weak_memory_edge()) { + vtn->add_weak_memory_edge(dependency); + } else { + vtn->add_strong_memory_edge(dependency); + } } } diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 0e14964263d..6713ed6cac6 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -46,6 +46,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(SPECULATIVE_ALIASING_ANALYSIS, "Trace Speculative Aliasing Analysis") \ flags(SPECULATIVE_RUNTIME_CHECKS, "Trace VTransform::apply_speculative_runtime_checks") \ flags(VTRANSFORM, "Trace VTransform Graph") \ flags(ALL, "Trace everything (very verbose)") diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index d2cb62c92c9..cd5aba6c31d 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -23,9 +23,14 @@ */ #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" +#include "opto/divnode.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" +#include "opto/noOverflowInt.hpp" +#include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/vectorization.hpp" @@ -257,13 +262,17 @@ void VLoopVPointers::print() const { // - No Load-Load edges. // - Inside a slice, add all Store-Load, Load-Store, Store-Store edges, // except if we can prove that the memory does not overlap. +// - Strong edge: must be respected. +// - Weak edge: if we add a speculative aliasing check, we can violate +// the edge, i.e. spaw the order. void VLoopDependencyGraph::construct() { const GrowableArray& mem_slice_heads = _memory_slices.heads(); const GrowableArray& mem_slice_tails = _memory_slices.tails(); ResourceMark rm; GrowableArray slice_nodes; - GrowableArray memory_pred_edges; + GrowableArray strong_memory_edges; + GrowableArray weak_memory_edges; // For each memory slice, create the memory subgraph for (int i = 0; i < mem_slice_heads.length(); i++) { @@ -275,7 +284,8 @@ void VLoopDependencyGraph::construct() { // In forward order (reverse of reverse), visit all memory nodes in the slice. for (int j = slice_nodes.length() - 1; j >= 0 ; j--) { MemNode* n1 = slice_nodes.at(j); - memory_pred_edges.clear(); + strong_memory_edges.clear(); + weak_memory_edges.clear(); const VPointer& p1 = _vpointers.vpointer(n1); // For all memory nodes before it, check if we need to add a memory edge. @@ -286,15 +296,20 @@ void VLoopDependencyGraph::construct() { if (n1->is_Load() && n2->is_Load()) { continue; } const VPointer& p2 = _vpointers.vpointer(n2); + + // If we can prove that they will never overlap -> drop edge. if (!p1.never_overlaps_with(p2)) { - // Possibly overlapping memory - memory_pred_edges.append(_body.bb_idx(n2)); + if (p1.can_make_speculative_aliasing_check_with(p2)) { + weak_memory_edges.append(_body.bb_idx(n2)); + } else { + strong_memory_edges.append(_body.bb_idx(n2)); + } } } - if (memory_pred_edges.is_nonempty()) { + if (strong_memory_edges.is_nonempty() || weak_memory_edges.is_nonempty()) { // Data edges are taken implicitly from the C2 graph, thus we only add // a dependency node if we have memory edges. - add_node(n1, memory_pred_edges); + add_node(n1, strong_memory_edges, weak_memory_edges); } } slice_nodes.clear(); @@ -305,16 +320,18 @@ void VLoopDependencyGraph::construct() { NOT_PRODUCT( if (_vloop.is_trace_dependency_graph()) { print(); } ) } -void VLoopDependencyGraph::add_node(MemNode* n, GrowableArray& memory_pred_edges) { +void VLoopDependencyGraph::add_node(MemNode* n, GrowableArray& strong_memory_edges, GrowableArray& weak_memory_edges) { assert(_dependency_nodes.at_grow(_body.bb_idx(n), nullptr) == nullptr, "not yet created"); - assert(!memory_pred_edges.is_empty(), "no need to create a node without edges"); - DependencyNode* dn = new (_arena) DependencyNode(n, memory_pred_edges, _arena); + DependencyNode* dn = new (_arena) DependencyNode(n, strong_memory_edges, weak_memory_edges, _arena); _dependency_nodes.at_put_grow(_body.bb_idx(n), dn, nullptr); } int VLoopDependencyGraph::find_max_pred_depth(const Node* n) const { int max_pred_depth = 0; if (!n->is_Phi()) { // ignore backedge + // We must compute the dependence graph depth with all edges (including the weak edges), so that + // the independence queries work correctly, no matter if we check independence with or without + // weak edges. for (PredsIterator it(*this, n); !it.done(); it.next()) { Node* pred = it.current(); if (_vloop.in_bb(pred)) { @@ -358,8 +375,13 @@ void VLoopDependencyGraph::print() const { const DependencyNode* dn = dependency_node(n); if (dn != nullptr) { tty->print(" DependencyNode[%d %s:", n->_idx, n->Name()); - for (uint j = 0; j < dn->memory_pred_edges_length(); j++) { - Node* pred = _body.body().at(dn->memory_pred_edge(j)); + for (uint j = 0; j < dn->num_strong_memory_edges(); j++) { + Node* pred = _body.body().at(dn->strong_memory_edge(j)); + tty->print(" %d %s", pred->_idx, pred->Name()); + } + tty->print(" | weak:"); + for (uint j = 0; j < dn->num_weak_memory_edges(); j++) { + Node* pred = _body.body().at(dn->weak_memory_edge(j)); tty->print(" %d %s", pred->_idx, pred->Name()); } tty->print_cr("]"); @@ -367,11 +389,18 @@ void VLoopDependencyGraph::print() const { } tty->cr(); - tty->print_cr(" Complete dependency graph:"); + // If we cannot speculate (aliasing analysis runtime checks), we need to respect all edges. + bool with_weak_memory_edges = !_vloop.use_speculative_aliasing_checks(); + if (with_weak_memory_edges) { + tty->print_cr(" Complete dependency graph (with weak edges, because we cannot speculate):"); + } else { + tty->print_cr(" Dependency graph without weak edges (because we can speculate):"); + } for (int i = 0; i < _body.body().length(); i++) { Node* n = _body.body().at(i); tty->print(" d%02d Dependencies[%d %s:", depth(n), n->_idx, n->Name()); for (PredsIterator it(*this, n); !it.done(); it.next()) { + if (!with_weak_memory_edges && it.is_current_weak_memory_edge()) { continue; } Node* pred = it.current(); tty->print(" %d %s", pred->_idx, pred->Name()); } @@ -381,16 +410,25 @@ void VLoopDependencyGraph::print() const { #endif VLoopDependencyGraph::DependencyNode::DependencyNode(MemNode* n, - GrowableArray& memory_pred_edges, + GrowableArray& strong_memory_edges, + GrowableArray& weak_memory_edges, Arena* arena) : _node(n), - _memory_pred_edges_length(memory_pred_edges.length()), - _memory_pred_edges(nullptr) + _num_strong_memory_edges(strong_memory_edges.length()), + _num_weak_memory_edges(weak_memory_edges.length()), + _memory_edges(nullptr) { - assert(memory_pred_edges.is_nonempty(), "not empty"); - uint bytes = memory_pred_edges.length() * sizeof(int); - _memory_pred_edges = (int*)arena->Amalloc(bytes); - memcpy(_memory_pred_edges, memory_pred_edges.adr_at(0), bytes); + assert(strong_memory_edges.is_nonempty() || weak_memory_edges.is_nonempty(), "only generate DependencyNode if there are pred edges"); + uint bytes_strong = strong_memory_edges.length() * sizeof(int); + uint bytes_weak = weak_memory_edges.length() * sizeof(int); + uint bytes_total = bytes_strong + bytes_weak; + _memory_edges = (int*)arena->Amalloc(bytes_total); + if (strong_memory_edges.length() > 0) { + memcpy(_memory_edges, strong_memory_edges.adr_at(0), bytes_strong); + } + if (weak_memory_edges.length() > 0) { + memcpy(_memory_edges + strong_memory_edges.length(), weak_memory_edges.adr_at(0), bytes_weak); + } } VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& dependency_graph, @@ -400,36 +438,726 @@ VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& d _dependency_node(dependency_graph.dependency_node(node)), _current(nullptr), _is_current_memory_edge(false), - _next_pred(0), - _end_pred(node->req()), - _next_memory_pred(0), - _end_memory_pred((_dependency_node != nullptr) ? _dependency_node->memory_pred_edges_length() : 0) + _is_current_weak_memory_edge(false), + _next_data_edge(0), + _end_data_edge(node->req()), + _next_strong_memory_edge(0), + _end_strong_memory_edge((_dependency_node != nullptr) ? _dependency_node->num_strong_memory_edges() : 0), + _next_weak_memory_edge(0), + _end_weak_memory_edge((_dependency_node != nullptr) ? _dependency_node->num_weak_memory_edges() : 0) { if (_node->is_Store() || _node->is_Load()) { - // Load: address - // Store: address, value - _next_pred = MemNode::Address; + // Ignore ctrl and memory, only address and value are data dependencies. + // Memory edges are already covered by the strong and weak memory edges. + // Load: [ctrl, memory] address + // Store: [ctrl, memory] address, value + _next_data_edge = MemNode::Address; } else { assert(!_node->is_Mem(), "only loads and stores are expected mem nodes"); - _next_pred = 1; // skip control + _next_data_edge = 1; // skip control } next(); } void VLoopDependencyGraph::PredsIterator::next() { - if (_next_pred < _end_pred) { - _current = _node->in(_next_pred++); + if (_next_data_edge < _end_data_edge) { + _current = _node->in(_next_data_edge++); _is_current_memory_edge = false; - } else if (_next_memory_pred < _end_memory_pred) { - int pred_bb_idx = _dependency_node->memory_pred_edge(_next_memory_pred++); + _is_current_weak_memory_edge = false; + } else if (_next_strong_memory_edge < _end_strong_memory_edge) { + int pred_bb_idx = _dependency_node->strong_memory_edge(_next_strong_memory_edge++); _current = _dependency_graph._body.body().at(pred_bb_idx); _is_current_memory_edge = true; + _is_current_weak_memory_edge = false; + } else if (_next_weak_memory_edge < _end_weak_memory_edge) { + int pred_bb_idx = _dependency_node->weak_memory_edge(_next_weak_memory_edge++); + _current = _dependency_graph._body.body().at(pred_bb_idx); + _is_current_memory_edge = true; + _is_current_weak_memory_edge = true; } else { _current = nullptr; // done _is_current_memory_edge = false; + _is_current_weak_memory_edge = false; } } +// Computing aliasing runtime check using init and last of main-loop +// ----------------------------------------------------------------- +// +// We have two VPointer vp1 and vp2, and would like to create a runtime check that +// guarantees that the corresponding pointers p1 and p2 do not overlap (alias) for +// any iv value in the strided range r = [init, init + iv_stride, .. limit). +// Remember that vp1 and vp2 both represent a region in memory, starting at a +// "pointer", and extending for "size" bytes: +// +// vp1(iv) = [p1(iv), size1) +// vp2(iv) = [p2(iv), size2) +// +// |---size1---> |-------size2-------> +// | | +// p1(iv) p2(iv) +// +// In each iv value (intuitively: for each iteration), we check that there is no +// overlap: +// +// for all iv in r: p1(iv) + size1 <= p2(iv) OR p2(iv) + size2 <= p1(iv) +// +// This would allow situations where for some iv p1 is lower than p2, and for +// other iv p1 is higher than p2. This is not very useful in practice. We can +// strengthen the condition, which will make the check simpler later: +// +// for all iv in r: p1(iv) + size1 <= p2(iv) (P1-BEFORE-P2) +// OR +// for all iv in r: p2(iv) + size2 <= p1(iv) (P1-AFTER-P2) +// +// Note: apart from this strengthening, the checks we derive below are byte accurate, +// i.e. they are equivalent to the conditions above. This means we have NO case +// where: +// 1) The check passes (predicts no overlap) but the pointers do actually overlap. +// This would be bad because we would wrongly vectorize, possibly leading to +// wrong results. +// 2) The check does not pass (predicts overlap) but the pointers do not overlap. +// This would be suboptimal, as we would not be able to vectorize, and either +// trap (with predicate), or go into the slow-loop (with multiversioning). +// +// +// We apply the "MemPointer Linearity Corrolary" to VPointer vp and the corresponding +// pointer p: +// (C0) is given by the construction of VPointer vp, which simply wraps a MemPointer mp. +// (c1) with v = iv and scale_v = iv_scale +// (C2) with r = [init, init + iv_stride, .. last - stride_v, last], which is the set +// of possible iv values in the loop, with "init" the first iv value, and "last" +// the last iv value which is closest to limit. +// Note: iv_stride > 0 -> limit - iv_stride <= last < limit +// iv_stride < 0 -> limit < last <= limit - iv_stride +// We have to be a little careful, and cannot just use "limit" instead of "last" as +// the last value in r, because the iv never reaches limit in the main-loop, and +// so we are not sure if the memory access at p(limit) is still in bounds. +// For now, we just assume that we can compute init and limit, and we will derive +// the computation of these values later on. +// (C3) the memory accesses for every iv value in the loop must be in bounds, otherwise +// the program has undefined behaviour already. +// (C4) abs(iv_scale * iv_stride) < 2^31 is given by the checks in +// VPointer::init_are_scale_and_stride_not_too_large. +// +// Hence, it follows that we can see p and vp as linear functions of iv in r, i.e. for +// all iv values in the loop: +// p(iv) = p(init) - init * iv_scale + iv * iv_scale +// vp(iv) = vp(init) - init * iv_scale + iv * iv_scale +// +// Hence, p1 and p2 have the linear form: +// p1(iv) = p1(init) - init * iv_scale1 + iv * iv_scale1 (LINEAR-FORM-INIT) +// p2(iv) = p2(init) - init * iv_scale2 + iv * iv_scale2 +// +// With the (Alternative Corrolary P) we get the alternative linar form: +// p1(iv) = p1(last) - last * iv_scale1 + iv * iv_scale1 (LINEAR-FORM-LAST) +// p2(iv) = p2(last) - last * iv_scale2 + iv * iv_scale2 +// +// +// We can now use this linearity to construct aliasing runtime checks, depending on the +// different "geometry" of the two VPointer over their iv, i.e. the "slopes" of the linear +// functions. In the following graphs, the x-axis denotes the values of iv, from init to +// last. And the y-axis denotes the pointer position p(iv). Intuitively, this problem +// can be seen as having two bands that should not overlap. +// +// Case 1 Case 2 Case 3 +// parallel lines same sign slope different sign slope +// but not parallel +// +// +---------+ +---------+ +---------+ +// | | | #| |# | +// | | | # | | # | +// | #| | # | | # | +// | # | | # | | # | +// | # | | # | | #| +// | # ^ | | # | | ^| +// |# | #| | # | | || +// | v # | | # | | v| +// | # | |# #| | #| +// | # | |^ # | | # | +// |# | || # | | # | +// | | |v # | | # | +// | | |# | |# | +// +---------+ +---------+ +---------+ +// +// +// Case 1: parallel lines, i.e. iv_scale = iv_scale1 = iv_scale2 +// +// p1(iv) = p1(init) - init * iv_scale + iv * iv_scale +// p2(iv) = p2(init) - init * iv_scale + iv * iv_scale +// +// Given this, it follows: +// p1(iv) + size1 <= p2(iv) <==> p1(init) + size1 <= p2(init) +// p2(iv) + size2 <= p1(iv) <==> p2(init) + size2 <= p1(init) +// +// Hence, we do not have to check the condition for every iv, but only for init. +// +// p1(init) + size1 <= p2(init) OR p2(init) + size2 <= p1(init) +// ----- is equivalent to ----- ---- is equivalent to ------ +// (P1-BEFORE-P2) OR (P1-AFTER-P2) +// +// +// Case 2 and 3: different slopes, i.e. iv_scale1 != iv_scale2 +// +// Without loss of generality, we assume iv_scale1 < iv_scale2. +// (Otherwise, we just swap p1 and p2). +// +// If iv_stride >= 0, i.e. init <= iv <= last: +// (iv - init) * iv_scale1 <= (iv - init) * iv_scale2 +// (iv - last) * iv_scale1 >= (iv - last) * iv_scale2 (POS-STRIDE) +// If iv_stride <= 0, i.e. last <= iv <= init: +// (iv - init) * iv_scale1 >= (iv - init) * iv_scale2 +// (iv - last) * iv_scale1 <= (iv - last) * iv_scale2 (NEG-STRIDE) +// +// Below, we show that these conditions are equivalent: +// +// p1(init) + size1 <= p2(init) (if iv_stride >= 0) | p2(last) + size2 <= p1(last) (if iv_stride >= 0) | +// p1(last) + size1 <= p2(last) (if iv_stride <= 0) | p2(init) + size2 <= p1(init) (if iv_stride <= 0) | +// ---- are equivalent to ----- | ---- are equivalent to ----- | +// (P1-BEFORE-P2) | (P1-AFTER-P2) | +// | | +// Proof: | | +// | | +// Assume: (P1-BEFORE-P2) | Assume: (P1-AFTER-P2) | +// for all iv in r: p1(iv) + size1 <= p2(iv) | for all iv in r: p2(iv) + size2 <= p1(iv) | +// => And since init and last in r => | => And since init and last in r => | +// p1(init) + size1 <= p2(init) | p2(init) + size2 <= p1(init) | +// p1(last) + size1 <= p2(last) | p2(last) + size2 <= p1(last) | +// | | +// | | +// Assume: p1(init) + size1 <= p2(init) | Assume: p2(last) + size2 <= p1(last) | +// and: iv_stride >= 0 | and: iv_stride >= 0 | +// | | +// size1 + p1(iv) | size2 + p2(iv) | +// --------- apply (LINEAR-FORM-INIT) --------- | --------- apply (LINEAR-FORM-LAST) --------- | +// = size1 + p1(init) - init * iv_scale1 + iv * iv_scale1 | = size2 + p2(last) - last * iv_scale2 + iv * iv_scale2 | +// ------ apply (POS-STRIDE) --------- | ------ apply (POS-STRIDE) --------- | +// <= size1 + p1(init) - init * iv_scale2 + iv * iv_scale2 | <= size2 + p2(last) - last * iv_scale1 + iv * iv_scale1 | +// -- assumption -- | -- assumption -- | +// <= p2(init) - init * iv_scale2 + iv * iv_scale2 | <= p1(last) - last * iv_scale1 + iv * iv_scale1 | +// --------- apply (LINEAR-FORM-INIT) --------- | --------- apply (LINEAR-FORM-LAST) --------- | +// = p2(iv) | = p1(iv) | +// | | +// | | +// Assume: p1(last) + size1 <= p2(last) | Assume: p2(init) + size2 <= p1(init) | +// and: iv_stride <= 0 | and: iv_stride <= 0 | +// | | +// size1 + p1(iv) | size2 + p2(iv) | +// --------- apply (LINEAR-FORM-LAST) --------- | --------- apply (LINEAR-FORM-INIT) --------- | +// = size1 + p1(last) - last * iv_scale1 + iv * iv_scale1 | = size2 + p2(init) - init * iv_scale2 + iv * iv_scale2 | +// ------ apply (NEG-STRIDE) --------- | ------ apply (NEG-STRIDE) --------- | +// <= size1 + p1(last) - last * iv_scale2 + iv * iv_scale2 | <= size2 + p2(init) - init * iv_scale1 + iv * iv_scale1 | +// -- assumption -- | -- assumption -- | +// <= p2(last) - last * iv_scale2 + iv * iv_scale2 | <= p1(init) - init * iv_scale1 + iv * iv_scale1 | +// --------- apply (LINEAR-FORM-LAST) --------- | --------- apply (LINEAR-FORM-INIT) --------- | +// = p2(iv) | = p1(iv) | +// | | +// +// The obtained conditions already look very simple. However, we would like to avoid +// computing 4 addresses (p1(init), p1(last), p2(init), p2(last)), and would instead +// prefer to only compute 2 addresses, and derive the other two from the distance (span) +// between the pointers at init and last. Using (LINEAR-FORM-INIT), we get: +// +// p1(last) = p1(init) - init * iv_scale1 + last * iv_scale1 (SPAN-1) +// --------------- defines ------------- +// p1(init) + span1 +// +// p2(last) = p2(init) - init * iv_scale2 + last * iv_scale2 (SPAN-2) +// --------------- defines ------------- +// p1(init) + span2 +// +// span1 = - init * iv_scale1 + last * iv_scale1 = (last - init) * iv_scale1 +// span2 = - init * iv_scale2 + last * iv_scale2 = (last - init) * iv_scale2 +// +// Thus, we can use the conditions below: +// p1(init) + size1 <= p2(init) OR p2(init) + span2 + size2 <= p1(init) + span1 (if iv_stride >= 0) +// p1(init) + span1 + size1 <= p2(init) + span2 OR p2(init) + size2 <= p1(init) (if iv_stride <= 0) +// +// Below, we visualize the conditions, so that the reader can gain an intuitiion. +// For simplicity, we only show the case with iv_stride > 0. Also, remember that +// iv_scale1 < iv_scale2. +// +// +---------+ +---------+ +// | #| | #| <-- p1(init) + span1 +// | # | ^ span2 span1 ^ | # ^| +// | # | | | | # || +// | # | | | | # v| <-- p2(init) + span2 + size2 +// | # | | v |# #| +// | # | | span2 ^ | # | +// | # | | | | # | +// | # | | | | # | +// p2(init) --> |# #| v | | # | +// |^ # | ^ span1 | | # | +// || # | | | | # | +// p1(init) + size1 --> |v # | | | | # | +// |# | v v |# | +// +---------+ +---------+ +// +// ------------------------------------------------------------------------------------------------------------------------- +// +// Computing the last iv value in a loop +// ------------------------------------- +// +// Let us define a helper function, that computes the last iv value in a loop, +// given variable init and limit values, and a constant stride. If the loop +// is never entered, we just return the init value. +// +// LAST(init, stride, limit), where stride > 0: | LAST(init, stride, limit), where stride < 0: +// last = init | last = init +// for (iv = init; iv < limit; iv += stride) | for (iv = init; iv > limit; iv += stride) +// last = iv | last = iv +// +// It follows that for some k: +// last = init + k * stride +// +// If the loop is not entered, we can set k=0. +// +// If the loop is entered: +// last is very close to limit: +// stride > 0 -> limit - stride <= last < limit +// stride < 0 -> limit < last <= limit - stride +// +// If stride > 0: +// limit - stride <= last < limit +// limit - stride <= init + k * stride < limit +// limit - init - stride <= k * stride < limit - init +// limit - init - stride - 1 < k * stride <= limit - init - 1 +// (limit - init - stride - 1) / stride < k <= (limit - init - 1) / stride +// (limit - init - 1) / stride - 1 < k <= (limit - init - 1) / stride +// -> k = (limit - init - 1) / stride +// -> dividend "limit - init - 1" is >=0. So a regular round to zero division can be used. +// Note: to incorporate the case where the loop is not entered (init >= limit), we see +// that the divident is zero or negative, and so the result will be zero or +// negative. Thus, we can just clamp k to zero, or last to init, so that we get +// a solution that also works when the loop is not entered: +// +// k = (limit - init - 1) / abs(stride) +// last = MAX(init, init + k * stride) +// +// If stride < 0: +// limit < last <= limit - stride +// limit < init + k * stride <= limit - stride +// limit - init < k * stride <= limit - init - stride +// limit - init + 1 <= k * stride < limit - init - stride + 1 +// (limit - init + 1) / stride >= k > (limit - init - stride + 1) / stride +// -(limit - init + 1) / abs(stride) >= k > -(limit - init - stride + 1) / abs(stride) +// -(limit - init + 1) / abs(stride) >= k > -(limit - init + 1) / abs(stride) - 1 +// (init - limit - 1) / abs(stride) >= k > (init - limit - 1) / abs(stride) - 1 +// (init - limit - 1) / abs(stride) >= k > (init - limit - 1) / abs(stride) - 1 +// -> k = (init - limit - 1) / abs(stride) +// -> dividend "init - limit" is >=0. So a regular round to zero division can be used. +// Note: to incorporate the case where the loop is not entered (init <= limit), we see +// that the divident is zero or negative, and so the result will be zero or +// negative. Thus, we can just clamp k to zero, or last to init, so that we get +// a solution that also works when the loop is not entered: +// +// k = (init - limit - 1) / abs(stride) +// last = MIN(init, init + k * stride) +// +// Now we can put it all together: +// LAST(init, stride, limit) +// If stride > 0: +// k = (limit - init - 1) / abs(stride) +// last = MAX(init, init + k * stride) +// If stride < 0: +// k = (init - limit - 1) / abs(stride) +// last = MIN(init, init + k * stride) +// +// We will have to consider the implications of clamping to init when the loop is not entered +// at the use of LAST further down. +// +// ------------------------------------------------------------------------------------------------------------------------- +// +// Computing init and last for the main-loop +// ----------------------------------------- +// +// As we have seen above, we always need the "init" of the main-loop. And if "iv_scale1 != iv_scale2", then we +// also need the "last" of the main-loop. These values need to be pre-loop invariant, because the check is +// to be performed before the pre-loop (at the predicate or multiversioning selector_if). It will be helpful +// to recall the iv structure in the pre and main-loop: +// +// | iv = pre_init +// | +// Pre-Loop | +----------------+ +// phi | +// | | -> pre_last: last iv value in pre-loop +// + pre_iv_stride | +// |-----------------+ +// | exit check: < pre_limit +// | +// | iv = main_init = init +// | +// Main-Loop | +------------------------------+ +// phi | +// | | -> last: last iv value in main-loop +// + main_iv_stride = iv_stride | +// |-------------------------------+ +// | exit check: < main_limit = limit +// +// Unfortunately, the init (aka. main_init) is not pre-loop invariant, rather it is only available +// after the pre-loop. We will have to compute: +// +// pre_last = LAST(pre_init, pre_iv_stride, pre_limit) +// init = pre_last + pre_iv_stride +// +// If we need "last", we unfortunately must compute it as well: +// +// last = LAST(init, iv_stride, limit) +// +// +// These computations assume that we indeed do enter the main-loop - otherwise +// it does not make sense to talk about the "last main iteration". Of course +// entering the main-loop implies that we entered the pre-loop already. But +// what happens if we check the aliasing runtime check, but later would never +// enter the main-loop? +// +// First: no matter if we pass or fail the aliasing runtime check, we will +// not get wrong results. If we fail the check, we end up in the less optimized +// slow-loop. If we pass the check, and we don't enter the main-loop, we +// never rely on the aliasing check, after all only the vectorized main-loop +// (and the vectorized post-loop) rely on the aliasing check. +// +// But: The worry is that we may fail the aliasing runtime check "spuriously", +// i.e. even though we would never enter the main-loop, and that this could have +// unfortunate side-effects (for example deopting unnecessarily). Let's +// look at the two possible cases: +// 1) We would never even enter the pre-loop. +// There are only predicates between the aliasing runtime check and the pre-loop, +// so a predicate would have to fail. These are rather rare cases. If we +// are using multiversioning for the aliasing runtime check, we would +// immediately fail the predicate in either the slow or fast loop, so +// the decision of the aliasing runtime check does not matter. But if +// we are using a predicate for the aliaing runtime check, then we may +// end up deopting twice: once for the aliasing runtime check, and then +// again for the other predicate. This would not be great, but again, +// failing predicates are rare in the first place. +// +// 2) We would enter the pre-loop, but not the main-loop. +// The pre_last must be accurate, because we are entering the pre-loop. +// But then we fail the zero-trip guard of the main-loop. Thus, for the +// main-loop, the init lies "after" the limit. Thus, the computed last +// for the main-loop equals the init. This means that span1 and span2 +// are zero. Hence, p1(init) and p2(init) would have to alias for the +// aliasing runtime check to fail. Hence, it would not be surprising +// at all if we deopted because of the aliasing runtime check. +// +bool VPointer::can_make_speculative_aliasing_check_with(const VPointer& other) const { + const VPointer& vp1 = *this; + const VPointer& vp2 = other; + + if (!_vloop.use_speculative_aliasing_checks()) { return false; } + + // Both pointers need a nice linear form, otherwise we cannot formulate the check. + if (!vp1.is_valid() || !vp2.is_valid()) { return false; } + + // The pointers always overlap -> a speculative check would always fail. + if (vp1.always_overlaps_with(vp2)) { return false; } + + // The pointers never overlap -> a speculative check would always succeed. + assert(!vp1.never_overlaps_with(vp2), "ensured by caller"); + + // The speculative aliasing check happens either at the AutoVectorization predicate + // or at the multiversion_if. That is before the pre-loop. From the construction of + // VPointer, we already know that all its variables (except iv) are pre-loop invariant. + // + // For the computation of main_init, we also need the pre_limit, and so we need + // to check that this value is pre-loop invariant. In the case of non-equal iv_scales, + // we also need the main_limit in the aliasing check, and so this value must then + // also be pre-loop invariant. + Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); + Node* pre_limit = pre_limit_opaq->in(1); + Node* main_limit = _vloop.cl()->limit(); + + if (!_vloop.is_pre_loop_invariant(pre_limit)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not pre-loop independent!"); + } +#endif + return false; + } + + if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_pre_loop_invariant(main_limit)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not pre-loop independent!"); + } +#endif + return false; + } + + return true; +} + +// For description and derivation see "Computing the last iv value in a loop". +// Note: the iv computations here should not overflow. But out of an abundance +// of caution, we compute everything in long anyway. +Node* make_last(Node* initL, jint stride, Node* limitL, PhaseIdealLoop* phase) { + PhaseIterGVN& igvn = phase->igvn(); + + Node* abs_strideL = igvn.longcon(abs(stride)); + Node* strideL = igvn.longcon(stride); + + // If in some rare case the limit is "before" init, then + // this subtraction could overflow. Doing the calculations + // in long prevents this. Below, we clamp the "last" value + // back to init, which gets us back into the safe int range. + Node* diffL = (stride > 0) ? new SubLNode(limitL, initL) + : new SubLNode(initL, limitL); + Node* diffL_m1 = new AddLNode(diffL, igvn.longcon(-1)); + Node* k = new DivLNode(nullptr, diffL_m1, abs_strideL); + + // Compute last = init + k * iv_stride + Node* k_mul_stride = new MulLNode(k, strideL); + Node* last = new AddLNode(initL, k_mul_stride); + + // Make sure that the last does not lie "before" init. + Node* last_clamped = MaxNode::build_min_max_long(&igvn, initL, last, stride > 0); + + phase->register_new_node_with_ctrl_of(diffL, initL); + phase->register_new_node_with_ctrl_of(diffL_m1, initL); + phase->register_new_node_with_ctrl_of(k, initL); + phase->register_new_node_with_ctrl_of(k_mul_stride, initL); + phase->register_new_node_with_ctrl_of(last, initL); + phase->register_new_node_with_ctrl_of(last_clamped, initL); + + return last_clamped; +} + +BoolNode* make_a_plus_b_leq_c(Node* a, Node* b, Node* c, PhaseIdealLoop* phase) { + Node* a_plus_b = new AddLNode(a, b); + Node* cmp = CmpNode::make(a_plus_b, c, T_LONG, true); + BoolNode* bol = new BoolNode(cmp, BoolTest::le); + phase->register_new_node_with_ctrl_of(a_plus_b, a); + phase->register_new_node_with_ctrl_of(cmp, a); + phase->register_new_node_with_ctrl_of(bol, a); + return bol; +} + +BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) const { + // Ensure iv_scale1 <= iv_scale2. + const VPointer& vp1 = (this->iv_scale() <= other.iv_scale()) ? *this : other; + const VPointer& vp2 = (this->iv_scale() <= other.iv_scale()) ? other :*this ; + assert(vp1.iv_scale() <= vp2.iv_scale(), "ensured by swapping if necessary"); + + assert(vp1.can_make_speculative_aliasing_check_with(vp2), "sanity"); + + PhaseIdealLoop* phase = _vloop.phase(); + PhaseIterGVN& igvn = phase->igvn(); + + // init (aka main_init): compute it from the the pre-loop structure. + // As described above, we cannot just take the _vloop.cl().init_trip(), because that + // value is pre-loop dependent, and we need a pre-loop independent value, so we can + // have it available at the predicate / multiversioning selector_if. + // For this, we need to be sure that the pre_limit is pre-loop independent as well, + // see can_make_speculative_aliasing_check_with. + Node* pre_init = _vloop.pre_loop_end()->init_trip(); + jint pre_iv_stride = _vloop.pre_loop_end()->stride_con(); + Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); + Node* pre_limit = pre_limit_opaq->in(1); + assert(_vloop.is_pre_loop_invariant(pre_init), "needed for aliasing check before pre-loop"); + assert(_vloop.is_pre_loop_invariant(pre_limit), "needed for aliasing check before pre-loop"); + + Node* pre_initL = new ConvI2LNode(pre_init); + Node* pre_limitL = new ConvI2LNode(pre_limit); + phase->register_new_node_with_ctrl_of(pre_initL, pre_init); + phase->register_new_node_with_ctrl_of(pre_limitL, pre_init); + + Node* pre_lastL = make_last(pre_initL, pre_iv_stride, pre_limitL, phase); + + Node* main_initL = new AddLNode(pre_lastL, igvn.longcon(pre_iv_stride)); + phase->register_new_node_with_ctrl_of(main_initL, pre_init); + + Node* main_init = new ConvL2INode(main_initL); + phase->register_new_node_with_ctrl_of(main_init, pre_init); + + Node* p1_init = vp1.make_pointer_expression(main_init); + Node* p2_init = vp2.make_pointer_expression(main_init); + Node* size1 = igvn.longcon(vp1.size()); + Node* size2 = igvn.longcon(vp2.size()); + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr("\nVPointer::make_speculative_aliasing_check_with:"); + tty->print("pre_init: "); pre_init->dump(); + tty->print("pre_limit: "); pre_limit->dump(); + tty->print("pre_lastL: "); pre_lastL->dump(); + tty->print("main_init: "); main_init->dump(); + tty->print_cr("p1_init:"); + p1_init->dump_bfs(5, nullptr, ""); + tty->print_cr("p2_init:"); + p2_init->dump_bfs(5, nullptr, ""); + } +#endif + + BoolNode* condition1 = nullptr; + BoolNode* condition2 = nullptr; + if (vp1.iv_scale() == vp2.iv_scale()) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr(" Same iv_scale(%d) -> parallel lines -> simple conditions:", vp1.iv_scale()); + tty->print_cr(" p1(init) + size1 <= p2(init) OR p2(init) + size2 <= p1(init)"); + tty->print_cr(" -------- condition1 -------- ------- condition2 ---------"); + } +#endif + condition1 = make_a_plus_b_leq_c(p1_init, size1, p2_init, phase); + condition2 = make_a_plus_b_leq_c(p2_init, size2, p1_init, phase); + } else { + assert(vp1.iv_scale() < vp2.iv_scale(), "assumed in proof, established above by swapping"); + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr(" Different iv_scale -> lines with different slopes -> more complex conditions:"); + tty->print_cr(" p1(init) + size1 <= p2(init) OR p2(init) + span2 + size2 <= p1(init) + span1 (if iv_stride >= 0)"); + tty->print_cr(" p1(init) + span1 + size1 <= p2(init) + span2 OR p2(init) + size2 <= p1(init) (if iv_stride <= 0)"); + tty->print_cr(" ---------------- condition1 ---------------- --------------- condition2 -----------------"); + } +#endif + + // last (aka main_last): compute from main-loop structure. + jint main_iv_stride = _vloop.iv_stride(); + Node* main_limit = _vloop.cl()->limit(); + assert(_vloop.is_pre_loop_invariant(main_limit), "needed for aliasing check before pre-loop"); + + Node* main_limitL = new ConvI2LNode(main_limit); + phase->register_new_node_with_ctrl_of(main_limitL, pre_init); + + Node* main_lastL = make_last(main_initL, main_iv_stride, main_limitL, phase); + + // Compute span1 = (last - init) * iv_scale1 + // span2 = (last - init) * iv_scale2 + Node* last_minus_init = new SubLNode(main_lastL, main_initL); + Node* iv_scale1 = igvn.longcon(vp1.iv_scale()); + Node* iv_scale2 = igvn.longcon(vp2.iv_scale()); + Node* span1 = new MulLNode(last_minus_init, iv_scale1); + Node* span2 = new MulLNode(last_minus_init, iv_scale2); + + phase->register_new_node_with_ctrl_of(last_minus_init, pre_init); + phase->register_new_node_with_ctrl_of(span1, pre_init); + phase->register_new_node_with_ctrl_of(span2, pre_init); + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print("main_limitL: "); main_limitL->dump(); + tty->print("main_lastL: "); main_lastL->dump(); + tty->print("p1_init: "); p1_init->dump(); + tty->print("p2_init: "); p2_init->dump(); + tty->print("size1: "); size1->dump(); + tty->print("size2: "); size2->dump(); + tty->print_cr("span1: "); span1->dump_bfs(5, nullptr, ""); + tty->print_cr("span2: "); span2->dump_bfs(5, nullptr, ""); + } +#endif + + Node* p1_init_plus_span1 = new AddLNode(p1_init, span1); + Node* p2_init_plus_span2 = new AddLNode(p2_init, span2); + phase->register_new_node_with_ctrl_of(p1_init_plus_span1, pre_init); + phase->register_new_node_with_ctrl_of(p2_init_plus_span2, pre_init); + if (_vloop.iv_stride() >= 0) { + condition1 = make_a_plus_b_leq_c(p1_init, size1, p2_init, phase); + condition2 = make_a_plus_b_leq_c(p2_init_plus_span2, size2, p1_init_plus_span1, phase); + } else { + condition1 = make_a_plus_b_leq_c(p1_init_plus_span1, size1, p2_init_plus_span2, phase); + condition2 = make_a_plus_b_leq_c(p2_init, size2, p1_init, phase); + } + } + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr("condition1:"); + condition1->dump_bfs(5, nullptr, ""); + tty->print_cr("condition2:"); + condition2->dump_bfs(5, nullptr, ""); + } +#endif + + // Construct "condition1 OR condition2". Convert the bol value back to an int value + // that we can "OR" to create a single bol value. On x64, the two CMove are converted + // to two setbe instructions which capture the condition bits to a register, meaning + // we only have a single branch in the end. + Node* zero = igvn.intcon(0); + Node* one = igvn.intcon(1); + Node* cmov1 = new CMoveINode(condition1, zero, one, TypeInt::INT); + Node* cmov2 = new CMoveINode(condition2, zero, one, TypeInt::INT); + phase->register_new_node_with_ctrl_of(cmov1, main_initL); + phase->register_new_node_with_ctrl_of(cmov2, main_initL); + + Node* c1_or_c2 = new OrINode(cmov1, cmov2); + Node* cmp = CmpNode::make(c1_or_c2, zero, T_INT); + BoolNode* bol = new BoolNode(cmp, BoolTest::ne); + phase->register_new_node_with_ctrl_of(c1_or_c2, main_initL); + phase->register_new_node_with_ctrl_of(cmp, main_initL); + phase->register_new_node_with_ctrl_of(bol, main_initL); + + return bol; +} + +Node* VPointer::make_pointer_expression(Node* iv_value) const { + assert(is_valid(), "must be valid"); + + PhaseIdealLoop* phase = _vloop.phase(); + PhaseIterGVN& igvn = phase->igvn(); + Node* iv = _vloop.iv(); + Node* ctrl = phase->get_ctrl(iv_value); + + auto maybe_add = [&] (Node* n1, Node* n2, BasicType bt) { + if (n1 == nullptr) { return n2; } + Node* add = AddNode::make(n1, n2, bt); + phase->register_new_node(add, ctrl); + return add; + }; + + Node* expression = nullptr; + mem_pointer().for_each_raw_summand_of_int_group(0, [&] (const MemPointerRawSummand& s) { + Node* node = nullptr; + if (s.is_con()) { + // Long constant. + NoOverflowInt con = s.scaleI() * s.scaleL(); + node = igvn.longcon(con.value()); + } else { + // Long variable. + assert(s.scaleI().is_one(), "must be long variable"); + Node* scaleL = igvn.longcon(s.scaleL().value()); + Node* variable = (s.variable() == iv) ? iv_value : s.variable(); + if (variable->bottom_type()->isa_ptr() != nullptr) { + variable = new CastP2XNode(nullptr, variable); + phase->register_new_node(variable, ctrl); + } + node = new MulLNode(scaleL, variable); + phase->register_new_node(node, ctrl); + } + expression = maybe_add(expression, node, T_LONG); + }); + + int max_int_group = mem_pointer().max_int_group(); + for (int int_group = 1; int_group <= max_int_group; int_group++) { + Node* int_expression = nullptr; + NoOverflowInt int_group_scaleL; + mem_pointer().for_each_raw_summand_of_int_group(int_group, [&] (const MemPointerRawSummand& s) { + Node* node = nullptr; + if (s.is_con()) { + node = igvn.intcon(s.scaleI().value()); + } else { + Node* scaleI = igvn.intcon(s.scaleI().value()); + Node* variable = (s.variable() == iv) ? iv_value : s.variable(); + node = new MulINode(scaleI, variable); + phase->register_new_node(node, ctrl); + } + int_group_scaleL = s.scaleL(); // remember for multiplication after ConvI2L + int_expression = maybe_add(int_expression, node, T_INT); + }); + assert(int_expression != nullptr, "no empty int group"); + int_expression = new ConvI2LNode(int_expression); + phase->register_new_node(int_expression, ctrl); + Node* scaleL = igvn.longcon(int_group_scaleL.value()); + int_expression = new MulLNode(scaleL, int_expression); + phase->register_new_node(int_expression, ctrl); + expression = maybe_add(expression, int_expression, T_LONG); + } + + return expression; +} + #ifndef PRODUCT void VPointer::print_on(outputStream* st, bool end_with_cr) const { st->print("VPointer["); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 0af97eb78e4..baca0d5b927 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -29,6 +29,7 @@ #include "opto/matcher.hpp" #include "opto/mempointer.hpp" #include "opto/traceAutoVectorizationTag.hpp" +#include "utilities/growableArray.hpp" #include "utilities/pair.hpp" // Code in this file and the vectorization.cpp contains shared logics and @@ -161,6 +162,10 @@ public: _multiversioning_fast_proj != nullptr; } + bool use_speculative_aliasing_checks() const { + return are_speculative_checks_possible() && UseAutoVectorizationSpeculativeAliasingChecks; + } + // Estimate maximum size for data structures, to avoid repeated reallocation int estimated_body_length() const { return lpt()->_body.size(); }; int estimated_node_count() const { return (int)(1.10 * phase()->C->unique()); }; @@ -203,6 +208,10 @@ public: bool is_trace_speculative_runtime_checks() const { return _vtrace.is_trace(TraceAutoVectorizationTag::SPECULATIVE_RUNTIME_CHECKS); } + + bool is_trace_speculative_aliasing_analysis() const { + return _vtrace.is_trace(TraceAutoVectorizationTag::SPECULATIVE_ALIASING_ANALYSIS); + } #endif // Is the node in the basic block of the loop? @@ -222,15 +231,18 @@ public: return false; } + // Usually the ctrl of n is already before the pre-loop. Node* ctrl = phase()->get_ctrl(n); - - // Quick test: is it in the main-loop? - if (lpt()->is_member(phase()->get_loop(ctrl))) { - return false; + if (is_before_pre_loop(ctrl)) { + return true; } - // Is it before the pre-loop? - return phase()->is_dominator(ctrl, pre_loop_head()); + // But in some cases, the ctrl of n is between the pre and + // main loop, but the early ctrl is before the pre-loop. + // As long as the early ctrl is before the pre-loop, we can + // compute n before the pre-loop. + Node* early = phase()->compute_early_ctrl(n, ctrl); + return is_before_pre_loop(early); } // Check if the loop passes some basic preconditions for vectorization. @@ -239,6 +251,16 @@ public: private: VStatus check_preconditions_helper(); + + bool is_before_pre_loop(Node* ctrl) const { + // Quick test: is it in the main-loop? + if (lpt()->is_member(phase()->get_loop(ctrl))) { + return false; + } + + // Is it before the pre-loop? + return phase()->is_dominator(ctrl, pre_loop_head()); + } }; // Optimization to keep allocation of large arrays in AutoVectorization low. @@ -569,6 +591,9 @@ private: // - Memory-dependencies: the edges in the C2 memory-slice are too restrictive: for example all // stores are serialized, even if their memory does not overlap. Thus, // we refine the memory-dependencies (see construct method). +// - Strong edge: must be respected. +// - Weak edge: if we add a speculative aliasing check, we can violate +// the edge, i.e. swap the order. class VLoopDependencyGraph : public StackObj { private: class DependencyNode; @@ -611,7 +636,7 @@ public: bool mutually_independent(const Node_List* nodes) const; private: - void add_node(MemNode* n, GrowableArray& memory_pred_edges); + void add_node(MemNode* n, GrowableArray& strong_memory_edges, GrowableArray& weak_memory_edges); int depth(const Node* n) const { return _depths.at(_body.bb_idx(n)); } void set_depth(const Node* n, int d) { _depths.at_put(_body.bb_idx(n), d); } int find_max_pred_depth(const Node* n) const; @@ -625,16 +650,23 @@ private: class DependencyNode : public ArenaObj { private: MemNode* _node; // Corresponding ideal node - const uint _memory_pred_edges_length; - int* _memory_pred_edges; // memory pred-edges, mapping to bb_idx + const uint _num_strong_memory_edges; + const uint _num_weak_memory_edges; + int* _memory_edges; // memory pred-edges, mapping to bb_idx public: - DependencyNode(MemNode* n, GrowableArray& memory_pred_edges, Arena* arena); + DependencyNode(MemNode* n, GrowableArray& strong_memory_edges, GrowableArray& weak_memory_edges, Arena* arena); NONCOPYABLE(DependencyNode); - uint memory_pred_edges_length() const { return _memory_pred_edges_length; } + uint num_strong_memory_edges() const { return _num_strong_memory_edges; } + uint num_weak_memory_edges() const { return _num_weak_memory_edges; } - int memory_pred_edge(uint i) const { - assert(i < _memory_pred_edges_length, "bounds check"); - return _memory_pred_edges[i]; + int strong_memory_edge(uint i) const { + assert(i < _num_strong_memory_edges, "bounds check"); + return _memory_edges[i]; + } + + int weak_memory_edge(uint i) const { + assert(i < _num_weak_memory_edges, "bounds check"); + return _memory_edges[_num_strong_memory_edges + i]; } }; @@ -649,27 +681,40 @@ public: Node* _current; bool _is_current_memory_edge; + bool _is_current_weak_memory_edge; - // Iterate in node->in(i) - int _next_pred; - int _end_pred; + // Iterate in data edges, i.e. iterate node->in(i), excluding control and memory edges. + int _next_data_edge; + int _end_data_edge; + + // Iterate in dependency_node->strong_memory_edges() + int _next_strong_memory_edge; + int _end_strong_memory_edge; + + // Iterate in dependency_node->weak_memory_edge() + int _next_weak_memory_edge; + int _end_weak_memory_edge; - // Iterate in dependency_node->memory_pred_edge(i) - int _next_memory_pred; - int _end_memory_pred; public: PredsIterator(const VLoopDependencyGraph& dependency_graph, const Node* node); NONCOPYABLE(PredsIterator); void next(); bool done() const { return _current == nullptr; } + Node* current() const { assert(!done(), "not done yet"); return _current; } + bool is_current_memory_edge() const { assert(!done(), "not done yet"); return _is_current_memory_edge; } + + bool is_current_weak_memory_edge() const { + assert(!done(), "not done yet"); + return _is_current_weak_memory_edge; + } }; }; @@ -934,6 +979,43 @@ public: return mem_pointer().never_overlaps_with(other.mem_pointer()); } + // Delegate to MemPointer::always_overlaps_with, but guard for invalid cases + // where we must return a conservative answer: unknown overlap, return false. + bool always_overlaps_with(const VPointer& other) const { + if (!is_valid() || !other.is_valid()) { +#ifndef PRODUCT + if (_vloop.mptrace().is_trace_overlap()) { + tty->print_cr("VPointer::always_overlaps_with: invalid VPointer, overlap unknown."); + } +#endif + return false; + } + return mem_pointer().always_overlaps_with(other.mem_pointer()); + } + + static int cmp_summands(const VPointer& vp1, const VPointer& vp2) { + return MemPointer::cmp_summands(vp1.mem_pointer(), vp2.mem_pointer()); + } + + static int cmp_con(const VPointer& vp1, const VPointer& vp2) { + // We use two comparisons, because a subtraction could underflow. + jint con1 = vp1.con(); + jint con2 = vp2.con(); + if (con1 < con2) { return -1; } + if (con1 > con2) { return 1; } + return 0; + } + + static int cmp_summands_and_con(const VPointer& vp1, const VPointer& vp2) { + int cmp = cmp_summands(vp1, vp2); + if (cmp != 0) { return cmp; } + return cmp_con(vp1, vp2); + } + + bool can_make_speculative_aliasing_check_with(const VPointer& other) const; + Node* make_pointer_expression(Node* iv_value) const; + BoolNode* make_speculative_aliasing_check_with(const VPointer& other) const; + NOT_PRODUCT( void print_on(outputStream* st, bool end_with_cr = true) const; ) private: diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 8a9d4aed13e..1675b8d9fdb 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -23,6 +23,7 @@ #include "opto/castnode.hpp" #include "opto/convertnode.hpp" +#include "opto/vectorization.hpp" #include "opto/vectornode.hpp" #include "opto/vtransform.hpp" @@ -57,7 +58,7 @@ bool VTransformGraph::schedule() { VectorSet pre_visited; VectorSet post_visited; - collect_nodes_without_req_or_dependency(stack); + collect_nodes_without_strong_in_edges(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. @@ -72,8 +73,11 @@ bool VTransformGraph::schedule() { // No -> we are mid-visit. bool all_uses_already_visited = true; - for (int i = 0; i < vtn->outs(); i++) { - VTransformNode* use = vtn->out(i); + // We only need to respect the strong edges (data edges and strong memory edges). + // Violated weak memory edges are allowed, but require a speculative aliasing + // runtime check, see VTransform::apply_speculative_aliasing_runtime_checks. + for (uint i = 0; i < vtn->out_strong_edges(); i++) { + VTransformNode* use = vtn->out_strong_edge(i); if (post_visited.test(use->_idx)) { continue; } if (pre_visited.test(use->_idx)) { // Cycle detected! @@ -109,11 +113,11 @@ bool VTransformGraph::schedule() { 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 { +// Push all "root" nodes, i.e. those that have no strong input edges (data edges and strong memory edges): +void VTransformGraph::collect_nodes_without_strong_in_edges(GrowableArray& stack) const { for (int i = 0; i < _vtnodes.length(); i++) { VTransformNode* vtn = _vtnodes.at(i); - if (!vtn->has_req_or_dependency()) { + if (!vtn->has_strong_in_edge()) { stack.push(vtn); } } @@ -144,11 +148,11 @@ void VTransformApplyResult::trace(VTransformNode* vtnode) const { } #endif -void VTransform::apply_speculative_runtime_checks() { +void VTransform::apply_speculative_alignment_runtime_checks() { if (VLoop::vectors_should_be_aligned()) { #ifdef ASSERT if (_trace._align_vector || _trace._speculative_runtime_checks) { - tty->print_cr("\nVTransform::apply_speculative_runtime_checks: native memory alignment"); + tty->print_cr("\nVTransform::apply_speculative_alignment_runtime_checks: native memory alignment"); } #endif @@ -216,6 +220,206 @@ void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { add_speculative_check(bol_alignment); } +class VPointerWeakAliasingPair : public StackObj { +private: + // Using references instead of pointers would be preferrable, but GrowableArray + // requires a default constructor, and we do not have a default constructor for + // VPointer. + const VPointer* _vp1 = nullptr; + const VPointer* _vp2 = nullptr; + + VPointerWeakAliasingPair(const VPointer& vp1, const VPointer& vp2) : _vp1(&vp1), _vp2(&vp2) { + assert(vp1.is_valid(), "sanity"); + assert(vp2.is_valid(), "sanity"); + assert(!vp1.never_overlaps_with(vp2), "otherwise no aliasing"); + assert(!vp1.always_overlaps_with(vp2), "otherwise must be strong"); + assert(VPointer::cmp_summands_and_con(vp1, vp2) <= 0, "must be sorted"); + } + +public: + // Default constructor to make GrowableArray happy. + VPointerWeakAliasingPair() : _vp1(nullptr), _vp2(nullptr) {} + + static VPointerWeakAliasingPair make(const VPointer& vp1, const VPointer& vp2) { + if (VPointer::cmp_summands_and_con(vp1, vp2) <= 0) { + return VPointerWeakAliasingPair(vp1, vp2); + } else { + return VPointerWeakAliasingPair(vp2, vp1); + } + } + + const VPointer& vp1() const { return *_vp1; } + const VPointer& vp2() const { return *_vp2; } + + // Sort by summands, so that pairs with same summands (summand1, summands2) are adjacent. + static int cmp_for_sort(VPointerWeakAliasingPair* pair1, VPointerWeakAliasingPair* pair2) { + int cmp_summands1 = VPointer::cmp_summands(pair1->vp1(), pair2->vp1()); + if (cmp_summands1 != 0) { return cmp_summands1; } + return VPointer::cmp_summands(pair1->vp2(), pair2->vp2()); + } +}; + +void VTransform::apply_speculative_aliasing_runtime_checks() { + + if (_vloop.use_speculative_aliasing_checks()) { + +#ifdef ASSERT + if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { + tty->print_cr("\nVTransform::apply_speculative_aliasing_runtime_checks: speculative aliasing analysis runtime checks"); + } +#endif + + // It would be nice to add a ResourceMark here. But it would collide with resource allocation + // in PhaseIdealLoop::set_idom for _idom and _dom_depth. See also JDK-8337015. + VectorSet visited; + GrowableArray weak_aliasing_pairs; + + const GrowableArray& schedule = _graph.get_schedule(); + for (int i = 0; i < schedule.length(); i++) { + VTransformNode* vtn = schedule.at(i); + for (uint i = 0; i < vtn->out_weak_edges(); i++) { + VTransformNode* use = vtn->out_weak_edge(i); + if (visited.test(use->_idx)) { + // The use node was already visited, i.e. is higher up in the schedule. + // The "out" edge thus points backward, i.e. it is violated. + const VPointer& vp1 = vtn->vpointer(_vloop_analyzer); + const VPointer& vp2 = use->vpointer(_vloop_analyzer); +#ifdef ASSERT + if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { + tty->print_cr("\nViolated Weak Edge:"); + vtn->print(); + vp1.print_on(tty); + use->print(); + vp2.print_on(tty); + } +#endif + + // We could generate checks for the pair (vp1, vp2) directly. But in + // some graphs, this generates quadratically many checks. Example: + // + // set1: a[i+0] a[i+1] a[i+2] a[i+3] + // set2: b[i+0] b[i+1] b[i+2] b[i+3] + // + // We may have a weak memory edge between every memory access from + // set1 to every memory access from set2. In this example, this would + // be 4 * 4 = 16 checks. But instead, we can create a union VPointer + // for set1 and set2 each, and only create a single check. + // + // set1: a[i+0, size = 4] + // set1: b[i+0, size = 4] + // + // For this, we add all pairs to an array, and process it below. + weak_aliasing_pairs.push(VPointerWeakAliasingPair::make(vp1, vp2)); + } + } + visited.set(vtn->_idx); + } + + // Sort so that all pairs with the same summands (summands1, summands2) + // are consecutive, i.e. in the same group. This allows us to do a linear + // walk over all pairs of a group and create the union VPointers. + weak_aliasing_pairs.sort(VPointerWeakAliasingPair::cmp_for_sort); + + int group_start = 0; + while (group_start < weak_aliasing_pairs.length()) { + // New group: pick the first pair as the reference. + const VPointer* vp1 = &weak_aliasing_pairs.at(group_start).vp1(); + const VPointer* vp2 = &weak_aliasing_pairs.at(group_start).vp2(); + jint size1 = vp1->size(); + jint size2 = vp2->size(); + int group_end = group_start + 1; + while (group_end < weak_aliasing_pairs.length()) { + const VPointer* vp1_next = &weak_aliasing_pairs.at(group_end).vp1(); + const VPointer* vp2_next = &weak_aliasing_pairs.at(group_end).vp2(); + jint size1_next = vp1_next->size(); + jint size2_next = vp2_next->size(); + + // Different summands -> different group. + if (VPointer::cmp_summands(*vp1, *vp1_next) != 0) { break; } + if (VPointer::cmp_summands(*vp2, *vp2_next) != 0) { break; } + + // Pick the one with the lower con as the reference. + if (vp1->con() > vp1_next->con()) { + swap(vp1, vp1_next); + swap(size1, size1_next); + } + if (vp2->con() > vp2_next->con()) { + swap(vp2, vp2_next); + swap(size2, size2_next); + } + + // Compute the distance from vp1 to vp1_next + size, to get a size that would include vp1_next. + NoOverflowInt new_size1 = NoOverflowInt(vp1_next->con()) + NoOverflowInt(size1_next) - NoOverflowInt(vp1->con()); + NoOverflowInt new_size2 = NoOverflowInt(vp2_next->con()) + NoOverflowInt(size2_next) - NoOverflowInt(vp2->con()); + if (new_size1.is_NaN() || new_size2.is_NaN()) { break; /* overflow -> new group */ } + + // The "next" VPointer indeed belong to the group. + // + // vp1: |--------------> + // vp1_next: |----------------> + // result: |--------------------------> + // + // vp1: |--------------------------> + // vp1_next: |-------> + // result: |--------------------------> + // + size1 = MAX2(size1, new_size1.value()); + size2 = MAX2(size2, new_size2.value()); + group_end++; + } + // Create "union" VPointer that cover all VPointer from the group. + const VPointer vp1_union = vp1->make_with_size(size1); + const VPointer vp2_union = vp2->make_with_size(size2); + +#ifdef ASSERT + if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { + tty->print_cr("\nUnion of %d weak aliasing edges:", group_end - group_start); + vp1_union.print_on(tty); + vp2_union.print_on(tty); + } + + // Verification - union must contain all VPointer of the group. + for (int i = group_start; i < group_end; i++) { + const VPointer& vp1_i = weak_aliasing_pairs.at(i).vp1(); + const VPointer& vp2_i = weak_aliasing_pairs.at(i).vp2(); + assert(vp1_union.con() <= vp1_i.con(), "must start before"); + assert(vp2_union.con() <= vp2_i.con(), "must start before"); + assert(vp1_union.size() >= vp1_i.size(), "must end after"); + assert(vp2_union.size() >= vp2_i.size(), "must end after"); + } +#endif + + BoolNode* bol = vp1_union.make_speculative_aliasing_check_with(vp2_union); + add_speculative_check(bol); + + group_start = group_end; + } + } +} + +// Runtime Checks: +// Some required properties cannot be proven statically, and require a +// runtime check: +// - Alignment: +// See VTransform::add_speculative_alignment_check +// - Aliasing: +// See VTransform::apply_speculative_aliasing_runtime_checks +// There is a two staged approach for compilation: +// - AutoVectorization Predicate: +// See VM flag UseAutoVectorizationPredicate and documentation in predicates.hpp +// We speculate that the checks pass, and only compile a vectorized loop. +// We expect the checks to pass in almost all cases, and so we only need +// to compile and cache the vectorized loop. +// If the predicate ever fails, we deoptimize, and eventually compile +// without predicate. This means we will recompile with multiversioning. +// - Multiversioning: +// See VM Flag LoopMultiversioning and documentaiton in loopUnswitch.cpp +// If the predicate is not available or previously failed, then we compile +// a vectorized and a scalar loop. If the runtime check passes we take the +// vectorized loop, else the scalar loop. +// Multiversioning takes more compile time and code cache, but it also +// produces fast code for when the runtime check passes (vectorized) and +// when it fails (scalar performance). void VTransform::add_speculative_check(BoolNode* bol) { assert(_vloop.are_speculative_checks_possible(), "otherwise we cannot make speculative assumptions"); ParsePredicateSuccessProj* parse_predicate_proj = _vloop.auto_vectorization_parse_predicate_proj(); @@ -494,7 +698,7 @@ bool VTransformGraph::has_store_to_load_forwarding_failure(const VLoopAnalyzer& } 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); + Node* n = vnode_idx_to_transformed_node.at(in_req(i)->_idx); assert(n != nullptr, "must find input IR node"); return n; } @@ -616,7 +820,7 @@ VTransformApplyResult VTransformBoolVectorNode::apply(const VLoopAnalyzer& vloop BasicType bt = vloop_analyzer.types().velt_basic_type(first); // Cmp + Bool -> VectorMaskCmp - VTransformElementWiseVectorNode* vtn_cmp = in(1)->isa_ElementWiseVector(); + VTransformElementWiseVectorNode* vtn_cmp = in_req(1)->isa_ElementWiseVector(); assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), "bool vtn expects cmp vtn as input"); @@ -750,15 +954,27 @@ void VTransformNode::print() const { print_node_idx(_in.at(i)); } if ((uint)_in.length() > _req) { - tty->print(" |"); - for (int i = _req; i < _in.length(); i++) { + tty->print(" | strong:"); + for (uint i = _req; i < _in_end_strong_memory_edges; i++) { + print_node_idx(_in.at(i)); + } + } + if ((uint)_in.length() > _in_end_strong_memory_edges) { + tty->print(" | weak:"); + for (uint i = _in_end_strong_memory_edges; i < (uint)_in.length(); i++) { print_node_idx(_in.at(i)); } } tty->print(") ["); - for (int i = 0; i < _out.length(); i++) { + for (uint i = 0; i < _out_end_strong_edges; i++) { print_node_idx(_out.at(i)); } + if ((uint)_out.length() > _out_end_strong_edges) { + tty->print(" | weak:"); + for (uint i = _out_end_strong_edges; i < (uint)_out.length(); i++) { + print_node_idx(_out.at(i)); + } + } tty->print("] "); print_spec(); tty->cr(); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 555f565360d..397d712366b 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -109,19 +109,22 @@ public: const bool _verbose; const bool _rejections; const bool _align_vector; + const bool _speculative_aliasing_analysis; const bool _speculative_runtime_checks; const bool _info; VTransformTrace(const VTrace& vtrace, const bool is_trace_rejections, const bool is_trace_align_vector, + const bool is_trace_speculative_aliasing_analysis, const bool is_trace_speculative_runtime_checks, 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), - _speculative_runtime_checks(_verbose | is_trace_vtransform(vtrace) | is_trace_speculative_runtime_checks), - _info (_verbose | is_trace_vtransform(vtrace) | is_trace_info) {} + _rejections (_verbose | is_trace_vtransform(vtrace) | is_trace_rejections), + _align_vector (_verbose | is_trace_vtransform(vtrace) | is_trace_align_vector), + _speculative_aliasing_analysis (_verbose | is_trace_vtransform(vtrace) | is_trace_speculative_aliasing_analysis), + _speculative_runtime_checks (_verbose | is_trace_vtransform(vtrace) | is_trace_speculative_runtime_checks), + _info (_verbose | is_trace_vtransform(vtrace) | is_trace_info) {} static bool is_trace_vtransform(const VTrace& vtrace) { return vtrace.is_trace(TraceAutoVectorizationTag::VTRANSFORM); @@ -161,6 +164,7 @@ public: 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; } + const GrowableArray& get_schedule() const { return _schedule; } bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; @@ -173,7 +177,7 @@ private: 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; + void collect_nodes_without_strong_in_edges(GrowableArray& stack) const; template void for_each_memop_in_schedule(Callback callback) const; @@ -248,7 +252,8 @@ private: void determine_mem_ref_and_aw_for_main_loop_alignment(); void adjust_pre_loop_limit_to_align_main_loop_vectors(); - void apply_speculative_runtime_checks(); + void apply_speculative_alignment_runtime_checks(); + void apply_speculative_aliasing_runtime_checks(); void add_speculative_alignment_check(Node* node, juint alignment); void add_speculative_check(BoolNode* bol); @@ -259,22 +264,52 @@ private: // 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. +// +// There are 3 tyes of edges: +// - data edges (req): corresponding to C2 IR Node data edges, except control +// and memory. +// - strong memory edges: memory edges that must be respected when scheduling. +// - weak memory edges: memory edges that can be violated, but if violated then +// corresponding aliasing analysis runtime checks must be +// inserted. +// +// Strong edges: union of data edges and strong memory edges. +// These must be respected by scheduling in all cases. +// +// The C2 IR Node memory edges essentially define a linear order of all memory operations +// (only Loads with the same memory input can be executed in an arbitrary order). This is +// efficient, because it means every Load and Store has exactly one input memory edge, +// which keeps the memory edge count linear. This is approach is too restrictive for +// vectorization, for example, we could never vectorize stores, since they are all in a +// dependency chain. Instead, we model the memory edges between all memory nodes, which +// could be quadratic in the worst case. For vectorization, we must essentially reorder the +// instructions in the graph. For this we must model all memory dependencies. class VTransformNode : public ArenaObj { public: const VTransformNodeIDX _idx; private: - // _in is split into required inputs (_req, i.e. all data dependencies), - // and memory dependencies. + // We split _in into 3 sections: + // - data edges (req): _in[0 .. _req-1] + // - strong memory edges: _in[_req .. _in_end_strong_memory_edges-1] + // - weak memory edges: _in[_in_end_strong_memory_edges .. ] const uint _req; + uint _in_end_strong_memory_edges; GrowableArray _in; + + // We split _out into 2 sections: + // - strong edges: _out[0 .. _out_end_strong_edges-1] + // - weak memory edges: _out[_out_end_strong_edges .. _len-1] + uint _out_end_strong_edges; GrowableArray _out; public: VTransformNode(VTransform& vtransform, const uint req) : _idx(vtransform.graph().new_idx()), _req(req), + _in_end_strong_memory_edges(req), _in(vtransform.arena(), req, req, nullptr), + _out_end_strong_edges(0), _out(vtransform.arena(), 4, 0, nullptr) { vtransform.graph().add_vtnode(this); @@ -284,7 +319,7 @@ public: 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); + n->add_out_strong_edge(this); } void swap_req(uint i, uint j) { @@ -295,23 +330,67 @@ public: _in.at_put(j, tmp); } - void add_memory_dependency(VTransformNode* n) { + void add_strong_memory_edge(VTransformNode* n) { assert(n != nullptr, "no need to add nullptr"); - _in.push(n); - n->add_out(this); + if (_in_end_strong_memory_edges < (uint)_in.length()) { + // Put n in place of first weak memory edge, and move + // the weak memory edge to the end. + VTransformNode* first_weak = _in.at(_in_end_strong_memory_edges); + _in.at_put(_in_end_strong_memory_edges, n); + _in.push(first_weak); + } else { + _in.push(n); + } + _in_end_strong_memory_edges++; + n->add_out_strong_edge(this); } - void add_out(VTransformNode* n) { + void add_weak_memory_edge(VTransformNode* n) { + assert(n != nullptr, "no need to add nullptr"); + _in.push(n); + n->add_out_weak_memory_edge(this); + } + +private: + void add_out_strong_edge(VTransformNode* n) { + if (_out_end_strong_edges < (uint)_out.length()) { + // Put n in place of first weak memory edge, and move + // the weak memory edge to the end. + VTransformNode* first_weak = _out.at(_out_end_strong_edges); + _out.at_put(_out_end_strong_edges, n); + _out.push(first_weak); + } else { + _out.push(n); + } + _out_end_strong_edges++; + } + + void add_out_weak_memory_edge(VTransformNode* n) { _out.push(n); } +public: 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); } + uint out_strong_edges() const { return _out_end_strong_edges; } + uint out_weak_edges() const { return _out.length() - _out_end_strong_edges; } - bool has_req_or_dependency() const { - for (int i = 0; i < _in.length(); i++) { + VTransformNode* in_req(uint i) const { + assert(i < _req, "must be a req"); + return _in.at(i); + } + + VTransformNode* out_strong_edge(uint i) const { + assert(i < out_strong_edges(), "must be a strong memory edge or data edge"); + return _out.at(i); + } + + VTransformNode* out_weak_edge(uint i) const { + assert(i < out_weak_edges(), "must be a strong memory edge"); + return _out.at(_out_end_strong_edges + i); + } + + bool has_strong_in_edge() const { + for (uint i = 0; i < _in_end_strong_memory_edges; i++) { if (_in.at(i) != nullptr) { return true; } } return false; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java index 20e6d631ffd..7d474f942a4 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java @@ -31,6 +31,7 @@ import jdk.internal.misc.Unsafe; import java.util.Random; import java.util.Arrays; import java.nio.ByteOrder; +import java.util.List; /* * @test @@ -50,19 +51,24 @@ public class TestVectorizationMismatchedAccess { private final static WhiteBox wb = WhiteBox.getWhiteBox(); public static void main(String[] args) { - // Cross-product: +-AlignVector and +-UseCompactObjectHeaders - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:-UseCompactObjectHeaders", - "-XX:-AlignVector"); - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:-UseCompactObjectHeaders", - "-XX:+AlignVector"); - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UseCompactObjectHeaders", - "-XX:-AlignVector"); - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UseCompactObjectHeaders", - "-XX:+AlignVector"); + TestFramework framework = new TestFramework(); + framework.addFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "-XX:+UnlockExperimentalVMOptions"); + + // Cross-product: + // +-AlignVector + // +-UseCompactObjectHeaders + // +-UseAutoVectorizationSpeculativeAliasingChecks + int idx = 0; + for (String av : List.of("-XX:-AlignVector", "-XX:+AlignVector")) { + for (String coh : List.of("-XX:-UseCompactObjectHeaders", "-XX:+UseCompactObjectHeaders")) { + for (String sac : List.of("-XX:-UseAutoVectorizationSpeculativeAliasingChecks", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks")) { + framework.addScenarios(new Scenario(idx++, av, coh, sac)); + } + } + } + + framework.start(); } static int size = 1024; @@ -126,7 +132,7 @@ public class TestVectorizationMismatchedAccess { } } for (; i < Math.min(byteArray.length + offset, byteArray.length); i++) { - int val = offset > 0 ? verifyByteArray[(i-offset) % 8] : verifyByteArray[i-offset]; + int val = offset >=1 ? verifyByteArray[(i-offset) % 8] : verifyByteArray[i-offset]; if (byteArray[i] != val) { throw new RuntimeException("Incorrect result at " + i + " " + byteArray[i] + " != " + verifyByteArray[i-offset]); } @@ -479,7 +485,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte3a(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8 - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); @@ -487,7 +500,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte3b(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8 - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); @@ -501,7 +521,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte4a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); @@ -509,7 +536,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte4b(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); @@ -524,7 +558,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte5a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); @@ -532,7 +573,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte5b(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java new file mode 100644 index 00000000000..33cef6e5e6b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8324751 + * @summary Test Speculative Aliasing checks in SuperWord + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestAliasing nCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing nCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing nCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestAliasing nCOH_yAV_nSAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_yAV_nSAC + */ + +package compiler.loopopts.superword; + +import jdk.test.lib.Utils; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import static compiler.lib.generators.Generators.G; +import compiler.lib.generators.Generator; + +/** + * More complicated test cases can be found in {@link TestAliasingFuzzing}. + */ +public class TestAliasing { + static int SIZE = 1024*8; + private static final Random RANDOM = Utils.getRandomInstance(); + private static final Generator INT_GEN = G.ints(); + + // Invariants used in tests. + public static int INVAR_ZERO = 0; + + // Original data. + public static byte[] ORIG_AB = fillRandom(new byte[SIZE]); + public static byte[] ORIG_BB = fillRandom(new byte[SIZE]); + public static int[] ORIG_AI = fillRandom(new int[SIZE]); + public static int[] ORIG_BI = fillRandom(new int[SIZE]); + + // The data we use in the tests. It is initialized from ORIG_* every time. + public static byte[] AB = new byte[SIZE]; + public static byte[] BB = new byte[SIZE]; + public static int[] AI = new int[SIZE]; + public static int[] BI = new int[SIZE]; + + // Parallel to data above, but for use in reference methods. + public static byte[] AB_REFERENCE = new byte[SIZE]; + public static byte[] BB_REFERENCE = new byte[SIZE]; + public static int[] AI_REFERENCE = new int[SIZE]; + public static int[] BI_REFERENCE = new int[SIZE]; + + interface TestFunction { + void run(); + } + + // Map of goldTests, i.e. tests that work with a golds value generated from the same test method, + // at the beginning when we are still executing in the interpreter. + Map goldTests = new HashMap(); + + // Map of gold, the results from the first run before compilation, one per goldTests entry. + Map golds = new HashMap(); + + // Map of referenceTests, i.e. tests that have a reference implementation that is run with the interpreter. + // The TestFunction must run both the test and reference methods. + Map referenceTests = new HashMap(); + + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestAliasing.class); + switch (args[0]) { + case "nCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } + }; + framework.start(); + } + + public TestAliasing() { + // Add all goldTests to list + goldTests.put("copy_B_sameIndex_noalias", () -> { copy_B_sameIndex_noalias(AB, BB); }); + goldTests.put("copy_B_sameIndex_alias", () -> { copy_B_sameIndex_alias(AB, AB); }); + goldTests.put("copy_B_differentIndex_noalias", () -> { copy_B_differentIndex_noalias(AB, BB); }); + goldTests.put("copy_B_differentIndex_noalias_v2", () -> { copy_B_differentIndex_noalias_v2(); }); + goldTests.put("copy_B_differentIndex_alias", () -> { copy_B_differentIndex_alias(AB, AB); }); + + goldTests.put("copy_I_sameIndex_noalias", () -> { copy_I_sameIndex_noalias(AI, BI); }); + goldTests.put("copy_I_sameIndex_alias", () -> { copy_I_sameIndex_alias(AI, AI); }); + goldTests.put("copy_I_differentIndex_noalias", () -> { copy_I_differentIndex_noalias(AI, BI); }); + goldTests.put("copy_I_differentIndex_alias", () -> { copy_I_differentIndex_alias(AI, AI); }); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + init(); + test.run(); + Object gold = snapshotCopy(); + golds.put(name, gold); + } + + referenceTests.put("fill_B_sameArray_alias", () -> { + int invar1 = RANDOM.nextInt(64); + int invar2 = RANDOM.nextInt(64); + test_fill_B_sameArray_alias(AB, AB, invar1, invar2); + reference_fill_B_sameArray_alias(AB_REFERENCE, AB_REFERENCE, invar1, invar2); + }); + referenceTests.put("fill_B_sameArray_noalias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // But they never overlap. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle; + int invar2 = middle; + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_B_sameArray_noalias(AB, AB, invar1, invar2, limit); + reference_fill_B_sameArray_noalias(AB_REFERENCE, AB_REFERENCE, invar1, invar2, limit); + }); + } + + public static void init() { + System.arraycopy(ORIG_AB, 0, AB, 0, SIZE); + System.arraycopy(ORIG_BB, 0, BB, 0, SIZE); + System.arraycopy(ORIG_AI, 0, AI, 0, SIZE); + System.arraycopy(ORIG_BI, 0, BI, 0, SIZE); + } + + public static void initReference() { + System.arraycopy(ORIG_AB, 0, AB_REFERENCE, 0, SIZE); + System.arraycopy(ORIG_BB, 0, BB_REFERENCE, 0, SIZE); + System.arraycopy(ORIG_AI, 0, AI_REFERENCE, 0, SIZE); + System.arraycopy(ORIG_BI, 0, BI_REFERENCE, 0, SIZE); + } + + public static Object snapshotCopy() { + return new Object[] { + AB.clone(), BB.clone(), + AI.clone(), BI.clone() + }; + } + + public static Object snapshot() { + return new Object[] { + AB, BB, + AI, BI + }; + } + + public static Object snapshotReference() { + return new Object[] { + AB_REFERENCE, BB_REFERENCE, + AI_REFERENCE, BI_REFERENCE + }; + } + + @Warmup(100) + @Run(test = {"copy_B_sameIndex_noalias", + "copy_B_sameIndex_alias", + "copy_B_differentIndex_noalias", + "copy_B_differentIndex_noalias_v2", + "copy_B_differentIndex_alias", + "copy_I_sameIndex_noalias", + "copy_I_sameIndex_alias", + "copy_I_differentIndex_noalias", + "copy_I_differentIndex_alias", + "test_fill_B_sameArray_alias", + "test_fill_B_sameArray_noalias"}) + public void runTests() { + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object gold = golds.get(name); + // Compute new result + init(); + test.run(); + Object result = snapshot(); + // Compare gold and new result + try { + Verify.checkEQ(gold, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + + for (Map.Entry entry : referenceTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Init data for test and reference + init(); + initReference(); + // Run test and reference + test.run(); + // Capture results from test and reference + Object result = snapshot(); + Object expected = snapshotReference(); + // Compare expected and new result + try { + Verify.checkEQ(expected, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + } + + static byte[] fillRandom(byte[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = (byte)(int)INT_GEN.next(); + } + return a; + } + + static int[] fillRandom(int[] a) { + G.fill(INT_GEN, a); + return a; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_B_sameIndex_noalias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_B_sameIndex_alias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, they never fail, so no multiversioning required. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_B_differentIndex_noalias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, they never fail, so no multiversioning required. + // With AlignVector we cannot prove that both accesses are alignable. + // + // Same as "copy_B_differentIndex_noalias, but somehow loading from fields rather + // than arguments does not lead to vectorization. + static void copy_B_differentIndex_noalias_v2() { + for (int i = 0; i < AB.length; i++) { + BB[i] = AB[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*pre .* multiversion_fast.*", "= 1", + ".*main .* multiversion_fast.*", "= 1", + ".*post .* multiversion_fast.*", "= 2", // vectorized and scalar versions + ".*multiversion_slow.*", "= 2", // main and post (pre-loop only has a single iteration) + ".*multiversion.*", "= 6"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, it fails and so we do need multiversioning. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_B_differentIndex_alias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_I_sameIndex_noalias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_I_sameIndex_alias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, they never fail, so no multiversioning required. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_I_differentIndex_noalias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*pre .* multiversion_fast.*", "= 1", + ".*main .* multiversion_fast.*", "= 1", + ".*post .* multiversion_fast.*", "= 2", // vectorized and scalar versions + ".*multiversion_slow.*", "= 2", // main and post (pre-loop only has a single iteration) + ".*multiversion.*", "= 6"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, it fails and so we do need multiversioning. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_I_differentIndex_alias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + ".*pre .* multiversion_fast.*", "= 1", + ".*main .* multiversion_fast.*", "= 1", + ".*post .* multiversion_fast.*", "= 2", // vectorized and scalar versions + ".*multiversion_slow.*", "= 2", // main and post (pre-loop only has a single iteration) + ".*multiversion.*", "= 6"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, it fails and so we do need multiversioning. + // With AlignVector we cannot prove that both accesses are alignable. + // + // FYI: invar1 and invar2 are small values, only used to test that everything runs + // correctly with at different offsets / with different alignment. + static void test_fill_B_sameArray_alias(byte[] a, byte[] b, int invar1, int invar2) { + for (int i = 0; i < a.length - 100; i++) { + a[i + invar1] = (byte)0x0a; + b[a.length - i - 1 - invar2] = (byte)0x0b; + } + } + + @DontCompile + static void reference_fill_B_sameArray_alias(byte[] a, byte[] b, int invar1, int invar2) { + for (int i = 0; i < a.length - 100; i++) { + a[i + invar1] = (byte)0x0a; + b[a.length - i - 1 - invar2] = (byte)0x0b; + } + } + + @Test + @IR(counts = {IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, and they should not fail, so no multiversioning. + static void test_fill_B_sameArray_noalias(byte[] a, byte[] b, int invar1, int invar2, int limit) { + for (int i = 0; i < limit; i++) { + a[invar1 + i] = (byte)0x0a; + b[invar2 - i] = (byte)0x0b; + } + } + + @DontCompile + static void reference_fill_B_sameArray_noalias(byte[] a, byte[] b, int invar1, int invar2, int limit) { + for (int i = 0; i < limit; i++) { + a[invar1 + i] = (byte)0x0a; + b[invar2 - i] = (byte)0x0b; + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java new file mode 100644 index 00000000000..e13baf6882b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java @@ -0,0 +1,1284 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * 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=vanilla + * @bug 8324751 + * @summary Test Speculative Aliasing checks in SuperWord + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../../compiler/lib/ir_framework/TestFramework.java + * @compile ../../../compiler/lib/generators/Generators.java + * @compile ../../../compiler/lib/verify/Verify.java + * @run driver compiler.loopopts.superword.TestAliasingFuzzer vanilla + */ + +/* + * @test id=random-flags + * @bug 8324751 + * @summary Test Speculative Aliasing checks in SuperWord + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../../compiler/lib/ir_framework/TestFramework.java + * @compile ../../../compiler/lib/generators/Generators.java + * @compile ../../../compiler/lib/verify/Verify.java + * @run driver compiler.loopopts.superword.TestAliasingFuzzer random-flags + */ + +package compiler.loopopts.superword; + +import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.Random; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import jdk.test.lib.Utils; + +import compiler.lib.compile_framework.*; +import compiler.lib.generators.Generators; +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import static compiler.lib.template_framework.Template.body; +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.$; + +import compiler.lib.template_framework.library.TestFrameworkClass; + +/** + * Simpler test cases can be found in {@link TestAliasing}. + * + * We randomly generate tests to verify the behavior of the aliasing runtime checks. We feature: + * - Different primitive types: + * - for access type (primitive, we can have multiple types in a single loop) + * - for backing type (primitive and additionally we have native memory) + * - Different AccessScenarios: + * - copy (load and store) + * - fill (using two stores) + * - Different Aliasing: in some cases we never alias at runtime, in other cases we might + * -> Should exercise both the predicate and the multiversioning approach with the + * aliasing runtime checks. + * - Backing memory + * - Arrays: using int-index + * - MemorySegment (backed by primitive array or native memory): + * - Using long-index with MemorySegment::getAtIndex + * - Using byte-offset with MemorySegment::get + * - Loop iv: + * - forward (counting up) and backward (counting down) + * - Different iv stride: + * - inc/dec by one, and then scale with ivScale: for (..; i++) { access(i * 4); } + * - abs(ivScale) == 1, but use iv stride instead: for (..; i+=4) { access(i); } + * - type of index, invars, and bounds (see isLongIvType) + * - int: for array and MemorySegment + * - long: for MemorySegment + * - IR rules: + * - Verify that verification does (not) happen as expected. + * - Verify that we do not use multiversioning when no aliasing is expected at runtime. + * -> verify that the aliasing runtime check is not overly sensitive, so that the + * predicate does not fail unnecessarily and we have to recompile with multiversioning. + * + * Possible extensions (Future Work): + * - Access with Unsafe + * - Backing memory with Buffers + * - AccessScenario: + * - More than two accesses + * - Improve IR rules, once more cases vectorize (see e.g. JDK-8359688) + * - Aliasing: + * - MemorySegment on same backing memory, creating different MemorySegments + * via slicing. Possibly overlapping MemorySegments. + * - CONTAINER_UNKNOWN_ALIASING_NEVER: currently always has different + * memory and split ranges. But we could alternate between same memory + * and split ranges, and then different memory but overlapping ranges. + * This would also be never aliasing. + * + */ +public class TestAliasingFuzzer { + private static final Random RANDOM = Utils.getRandomInstance(); + + public record MyType(String name, int byteSize, String con1, String con2, String layout) { + @Override + public String toString() { return name(); } + + public String letter() { return name().substring(0, 1).toUpperCase(); } + } + public static final String con1 = "0x0102030405060708L"; + public static final String con2 = "0x0910111213141516L"; + public static final String con1F = "Float.intBitsToFloat(0x01020304)"; + public static final String con2F = "Float.intBitsToFloat(0x09101112)"; + public static final String con1D = "Double.longBitsToDouble(" + con1 + ")"; + public static final String con2D = "Double.longBitsToDouble(" + con2 + ")"; + + // List of primitive types for accesses and arrays. + public static final MyType myByte = new MyType("byte", 1, con1, con2, "ValueLayout.JAVA_BYTE"); + public static final MyType myChar = new MyType("char", 2, con1, con2, "ValueLayout.JAVA_CHAR_UNALIGNED"); + public static final MyType myShort = new MyType("short", 2, con1, con2, "ValueLayout.JAVA_SHORT_UNALIGNED"); + public static final MyType myInt = new MyType("int", 4, con1, con2, "ValueLayout.JAVA_INT_UNALIGNED"); + public static final MyType myLong = new MyType("long", 8, con1, con2, "ValueLayout.JAVA_LONG_UNALIGNED"); + public static final MyType myFloat = new MyType("float", 4, con1F, con2F, "ValueLayout.JAVA_FLOAT_UNALIGNED"); + public static final MyType myDouble = new MyType("double", 8, con1D, con2D, "ValueLayout.JAVA_DOUBLE_UNALIGNED"); + public static final List primitiveTypes + = List.of(myByte, myChar, myShort, myInt, myLong, myFloat, myDouble); + + // For native memory, we use this "fake" type. It has a byteSize of 1, since we measure the memory in bytes. + public static final MyType myNative = new MyType("native", 1, null, null, null); + public static final List primitiveTypesAndNative + = List.of(myByte, myChar, myShort, myInt, myLong, myFloat, myDouble, myNative); + + // Do the containers (array, MemorySegment, etc) ever overlap? + enum Aliasing { + CONTAINER_DIFFERENT, + CONTAINER_SAME_ALIASING_NEVER, + CONTAINER_SAME_ALIASING_UNKNOWN, + CONTAINER_UNKNOWN_ALIASING_NEVER, + CONTAINER_UNKNOWN_ALIASING_UNKNOWN, + } + + enum AccessScenario { + COPY_LOAD_STORE, // a[i1] = b[i2]; + FILL_STORE_STORE, // a[i1] = x; b[i2] = y; + } + + enum ContainerKind { + ARRAY, + MEMORY_SEGMENT_LONG_ADR_SCALE, // for (..; i++) { access(i * 4); } + MEMORY_SEGMENT_LONG_ADR_STRIDE, // for (..; i+=4) { access(i); } + MEMORY_SEGMENT_AT_INDEX, + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + long t0 = System.nanoTime(); + // Add a java source file. + comp.addJavaSourceCode("compiler.loopopts.superword.templated.AliasingFuzzer", generate(comp)); + + long t1 = System.nanoTime(); + // Compile the source file. + comp.compile(); + + long t2 = System.nanoTime(); + + String[] flags = switch(args[0]) { + case "vanilla" -> new String[] {}; + case "random-flags" -> randomFlags(); + default -> throw new RuntimeException("unknown run id=" + args[0]); + }; + // Run the tests without any additional VM flags. + // compiler.loopopts.superword.templated.AliasingFuzzer.main(new String[] {}); + comp.invoke("compiler.loopopts.superword.templated.AliasingFuzzer", "main", new Object[] {flags}); + long t3 = System.nanoTime(); + + System.out.println("Code Generation: " + (t1-t0) * 1e-9f); + System.out.println("Code Compilation: " + (t2-t1) * 1e-9f); + System.out.println("Running Tests: " + (t3-t2) * 1e-9f); + } + + public static String[] randomFlags() { + // We don't want to always run with all flags, that is too expensive. + // But let's make sure things don't completely, rot by running with some + // random flags that are relevant. + // We set the odds towards the "default" we are targetting. + return new String[] { + // Default disabled. + "-XX:" + randomPlusMinus(1, 5) + "AlignVector", + // Default enabled. + "-XX:" + randomPlusMinus(5, 1) + "UseAutoVectorizationSpeculativeAliasingChecks", + "-XX:" + randomPlusMinus(5, 1) + "UseAutoVectorizationPredicate", + "-XX:" + randomPlusMinus(5, 1) + "ShortRunningLongLoop", + // Either way is ok. + "-XX:" + randomPlusMinus(1, 1) + "UseCompactObjectHeaders", + "-XX:SuperWordAutomaticAlignment=" + RANDOM.nextInt(0,3) + }; + } + + public static String randomPlusMinus(int plus, int minus) { + return (RANDOM.nextInt(plus + minus) < plus) ? "+" : "-"; + } + + public static T sample(List list) { + int r = RANDOM.nextInt(list.size()); + return list.get(r); + } + + public static String generate(CompileFramework comp) { + // Create a list to collect all tests. + List testTemplateTokens = new ArrayList<>(); + + // Add some basic functionalities. + testTemplateTokens.add(generateIndexForm()); + + // Array tests + for (int i = 0; i < 10; i++) { + testTemplateTokens.add(TestGenerator.makeArray().generate()); + } + + // MemorySegment with getAtIndex / setAtIndex + for (int i = 0; i < 20; i++) { + testTemplateTokens.add(TestGenerator.makeMemorySegment().generate()); + } + + // Create the test class, which runs all testTemplateTokens. + return TestFrameworkClass.render( + // package and class name. + "compiler.loopopts.superword.templated", "AliasingFuzzer", + // List of imports. + Set.of("compiler.lib.generators.*", + "compiler.lib.verify.*", + "java.lang.foreign.*", + "java.util.Random", + "jdk.test.lib.Utils"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + testTemplateTokens); + } + + // The IndexForm is used to model the index. We can use it for arrays, but also by + // restricting the MemorySegment index to a simple index. + // + // Form: + // index = con + iv * ivScale + invar0 * invar0Scale + invarRest + // [err] + // + // The index has a size >= 1, so that the index refers to a region: + // [index, index + size] + // + // The idea is that invarRest is always close to zero, with some small range [-err .. err]. + // The invar variables for invarRest must be in the range [-1, 0, 1], so that we can + // estimate the error range from the invarRestScales. + // + // At runtime, we will have to generate inputs for the iv.lo/iv.hi, as well as the invar0, + // so that the index range lays in some predetermined range [range.lo, range.hi] and the + // ivStride: + // + // for (int iv = iv.lo; iv < iv.hi; iv += ivStride) { + // assert: range.lo <= index(iv) + // index(iv) + size <= range.hi + // } + // + // Since there are multiple memory accesses, we may have multiple indices to compute. + // Since they are all in the same loop, the indices share the same iv.lo and iv.hi. Hence, + // we fix either iv.lo or iv.hi, and compute the other via the constraints. + // + // Fix iv.lo, assume ivScale > 0: + // index(iv) is smallest for iv = iv.lo, so we must satisfy + // range.lo <= con + iv.lo * ivScale + invar0 * invar0Scale + invarRest + // <= con + iv.lo * ivScale + invar0 * invar0Scale - err + // It follows: + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + // This allows us to pick a invar0. + // Now, we can compute the largest iv.lo possible. + // index(iv) is largest for iv = iv.hi, so we must satisfy: + // range.hi >= con + iv.hi * ivScale + invar0 * invar0Scale + invarRest + size + // >= con + iv.hi * ivScale + invar0 * invar0Scale + err + size + // It follows: + // iv.hi * ivScale <= range.hi - con - invar0 * invar0Scale - err - size + // This allows us to pick a iv.hi. + // + // More details can be found in the implementation below. + // + public static record IndexForm(int con, int ivScale, int invar0Scale, int[] invarRestScales, int size) { + public static IndexForm random(int numInvarRest, int size, int ivStrideAbs) { + int con = RANDOM.nextInt(-100_000, 100_000); + int ivScale = randomScale(size / ivStrideAbs); + int invar0Scale = randomScale(size); + int[] invarRestScales = new int[numInvarRest]; + // Sample values [-1, 0, 1] + for (int i = 0; i < invarRestScales.length; i++) { + invarRestScales[i] = RANDOM.nextInt(-1, 2); + } + return new IndexForm(con, ivScale, invar0Scale, invarRestScales, size); + } + + public static int randomScale(int size) { + int scale = switch(RANDOM.nextInt(10)) { + case 0 -> RANDOM.nextInt(1, 4 * size + 1); // any strided access + default -> size; // in most cases, we do not want it to be strided + }; + return RANDOM.nextBoolean() ? scale : -scale; + } + + public String generate() { + return "new IndexForm(" + con() + ", " + ivScale() + ", " + invar0Scale() + ", new int[] {" + + Arrays.stream(invarRestScales) + .mapToObj(String::valueOf) + .collect(Collectors.joining(", ")) + + "}, " + size() + ")"; + } + + public TemplateToken index(String invar0, String[] invarRest) { + var template = Template.make(() -> body( + let("con", con), + let("ivScale", ivScale), + let("invar0Scale", invar0Scale), + let("invar0", invar0), + "#con + #ivScale * i + #invar0Scale * #invar0", + IntStream.range(0, invarRestScales.length).mapToObj( + i -> List.of(" + ", invarRestScales[i], " * ", invarRest[i]) + ).toList() + )); + return template.asToken(); + } + + // MemorySegment need to be long-addressed, otherwise there can be int-overflow + // in the index, and that prevents RangeCheck Elimination and Vectorization. + public TemplateToken indexLong(String invar0, String[] invarRest) { + var template = Template.make(() -> body( + let("con", con), + let("ivScale", ivScale), + let("invar0Scale", invar0Scale), + let("invar0", invar0), + "#{con}L + #{ivScale}L * i + #{invar0Scale}L * #invar0", + IntStream.range(0, invarRestScales.length).mapToObj( + i -> List.of(" + ", invarRestScales[i], "L * ", invarRest[i]) + ).toList() + )); + return template.asToken(); + } + } + + // Mirror the IndexForm from the generator to the test. + public static TemplateToken generateIndexForm() { + var template = Template.make(() -> body( + """ + private static final Random RANDOM = Utils.getRandomInstance(); + + public static record IndexForm(int con, int ivScale, int invar0Scale, int[] invarRestScales, int size) { + public IndexForm { + if (ivScale == 0 || invar0Scale == 0) { + throw new RuntimeException("Bad scales: " + ivScale + " " + invar0Scale); + } + } + + public static record Range(int lo, int hi) { + public Range { + if (lo >= hi) { throw new RuntimeException("Bad range: " + lo + " " + hi); } + } + } + + public int err() { + int sum = 0; + for (int scale : invarRestScales) { sum += Math.abs(scale); } + return sum; + } + + public int invar0ForIvLo(Range range, int ivLo) { + if (ivScale > 0) { + // index(iv) is smallest for iv = ivLo, so we must satisfy: + // range.lo <= con + iv.lo * ivScale + invar0 * invar0Scale + invarRest + // <= con + iv.lo * ivScale + invar0 * invar0Scale - err + // It follows: + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + int rhs = range.lo() - con - ivLo * ivScale + err(); + int invar0 = (invar0Scale > 0) + ? + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + // invar0 >= (range.lo - con - iv.lo * ivScale + err) / invar0Scale + Math.floorDiv(rhs + invar0Scale - 1, invar0Scale) // round up division + : + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + // invar0 <= (range.lo - con - iv.lo * ivScale + err) / invar0Scale + Math.floorDiv(rhs, invar0Scale); // round down division + if (range.lo() > con + ivLo * ivScale + invar0 * invar0Scale - err()) { + throw new RuntimeException("sanity check failed (1)"); + } + return invar0; + } else { + // index(iv) is largest for iv = ivLo, so we must satisfy: + // range.hi >= con + iv.lo * ivScale + invar0 * invar0Scale + invarRest + size + // >= con + iv.lo * ivScale + invar0 * invar0Scale + err + size + // It follows: + // invar0 * invar0Scale <= range.hi - con - iv.lo * ivScale - err - size + int rhs = range.hi() - con - ivLo * ivScale - err() - size(); + int invar0 = (invar0Scale > 0) + ? + // invar0 * invar0Scale <= rhs + // invar0 <= rhs / invar0Scale + Math.floorDiv(rhs, invar0Scale) // round down division + : + // invar0 * invar0Scale <= rhs + // invar0 >= rhs / invar0Scale + Math.floorDiv(rhs + invar0Scale + 1, invar0Scale); // round up division + if (range.hi() < con + ivLo * ivScale + invar0 * invar0Scale + err() + size()) { + throw new RuntimeException("sanity check failed (2)"); + } + return invar0; + + } + } + + public int ivHiForInvar0(Range range, int invar0) { + if (ivScale > 0) { + // index(iv) is largest for iv = ivHi, so we must satisfy: + // range.hi >= con + iv.hi * ivScale + invar0 * invar0Scale + invarRest + size + // >= con + iv.hi * ivScale + invar0 * invar0Scale + err + size + // It follows: + // iv.hi * ivScale <= range.hi - con - invar0 * invar0Scale - err - size + // iv.hi <= (range.hi - con - invar0 * invar0Scale - err - size) / ivScale + int rhs = range.hi() - con - invar0 * invar0Scale - err() - size(); + int ivHi = Math.floorDiv(rhs, ivScale); // round down division + if (range.hi() < con + ivHi * ivScale + invar0 * invar0Scale + err() + size()) { + throw new RuntimeException("sanity check failed (3)"); + } + return ivHi; + } else { + // index(iv) is smallest for iv = ivHi, so we must satisfy: + // range.lo <= con + iv.hi * ivScale + invar0 * invar0Scale + invarRest + // <= con + iv.hi * ivScale + invar0 * invar0Scale - err + // It follows: + // iv.hi * ivScale >= range.lo - con - invar0 * invar0Scale + err + // iv.hi <= (range.lo - con - invar0 * invar0Scale + err) / ivScale + int rhs = range.lo() - con - invar0 * invar0Scale + err(); + int ivHi = Math.floorDiv(rhs, ivScale); // round down division + if (range.lo() > con + ivHi * ivScale + invar0 * invar0Scale - err()) { + throw new RuntimeException("sanity check failed (4)"); + } + return ivHi; + + } + } + } + """ + )); + return template.asToken(); + } + + public static record TestGenerator( + // The containers. + int numContainers, + int containerByteSize, + ContainerKind containerKind, + MyType containerElementType, + + // Do we count up or down, iterate over the containers forward or backward? + boolean loopForward, + int ivStrideAbs, + boolean isLongIvType, + + // For all index forms: number of invariants in the rest, i.e. the [err] term. + int numInvarRest, + + // Each access has an index form and a type. + IndexForm[] accessIndexForm, + MyType[] accessType, + + // The scenario. + Aliasing aliasing, + AccessScenario accessScenario) { + + public static TestGenerator makeArray() { + // Sample some random parameters: + Aliasing aliasing = sample(Arrays.asList(Aliasing.values())); + AccessScenario accessScenario = sample(Arrays.asList(AccessScenario.values())); + MyType type = sample(primitiveTypes); + + // size must be large enough for: + // - scale = 4 + // - range with size / 4 + // -> need at least size 16_000 to ensure we have 1000 iterations + // We want there to be a little variation, so alignment is not always the same. + int numElements = Generators.G.safeRestrict(Generators.G.ints(), 18_000, 20_000).next(); + int containerByteSize = numElements * type.byteSize(); + boolean loopForward = RANDOM.nextBoolean(); + + int numInvarRest = RANDOM.nextInt(5); + int ivStrideAbs = 1; + boolean isLongIvType = false; // int index + var form0 = IndexForm.random(numInvarRest, 1, ivStrideAbs); + var form1 = IndexForm.random(numInvarRest, 1, ivStrideAbs); + + return new TestGenerator( + 2, + containerByteSize, + ContainerKind.ARRAY, + type, + loopForward, + ivStrideAbs, + isLongIvType, + numInvarRest, + new IndexForm[] {form0, form1}, + new MyType[] {type, type}, + aliasing, + accessScenario); + } + + public static int alignUp(int value, int align) { + return Math.ceilDiv(value, align) * align; + } + + public static TestGenerator makeMemorySegment() { + // Sample some random parameters: + Aliasing aliasing = sample(Arrays.asList(Aliasing.values())); + AccessScenario accessScenario = sample(Arrays.asList(AccessScenario.values())); + // Backing memory can be native, access must be primitive. + MyType containerElementType = sample(primitiveTypesAndNative); + MyType accessType0 = sample(primitiveTypes); + MyType accessType1 = sample(primitiveTypes); + ContainerKind containerKind = sample(List.of( + ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE + )); + + if (containerKind == ContainerKind.MEMORY_SEGMENT_AT_INDEX) { + // The access types must be the same, it is a limitation of the index computation. + accessType1 = accessType0; + } + + final int minAccessSize = Math.min(accessType0.byteSize(), accessType1.byteSize()); + final int maxAccessSize = Math.max(accessType0.byteSize(), accessType1.byteSize()); + + // size must be large enough for: + // - scale = 4 + // - range with size / 4 + // -> need at least size 16_000 to ensure we have 1000 iterations + // We want there to be a little variation, so alignment is not always the same. + final int numAccessElements = Generators.G.safeRestrict(Generators.G.ints(), 18_000, 20_000).next(); + final int align = Math.max(maxAccessSize, containerElementType.byteSize()); + // We need to align up, so the size is divisible exactly by all involved type sizes. + final int containerByteSize = alignUp(numAccessElements * maxAccessSize, align); + final boolean loopForward = RANDOM.nextBoolean(); + + final int numInvarRest = RANDOM.nextInt(5); + int indexSize0 = accessType0.byteSize(); + int indexSize1 = accessType1.byteSize(); + if (containerKind == ContainerKind.MEMORY_SEGMENT_AT_INDEX) { + // These are int-indeces for getAtIndex, so we index by element and not bytes. + indexSize0 = 1; + indexSize1 = 1; + } + + boolean withAbsOneIvScale = containerKind == ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE; + int ivStrideAbs = containerKind == ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE ? minAccessSize : 1; + boolean isLongIvType = RANDOM.nextBoolean(); + var form0 = IndexForm.random(numInvarRest, indexSize0, ivStrideAbs); + var form1 = IndexForm.random(numInvarRest, indexSize1, ivStrideAbs); + + return new TestGenerator( + 2, + containerByteSize, + containerKind, + containerElementType, + loopForward, + ivStrideAbs, + isLongIvType, + numInvarRest, + new IndexForm[] {form0, form1}, + new MyType[] {accessType0, accessType1}, + aliasing, + accessScenario); + } + + public TemplateToken generate() { + var testTemplate = Template.make(() -> { + // Let's generate the variable names that are to be shared for the nested Templates. + String[] invarRest = new String[numInvarRest]; + for (int i = 0; i < invarRest.length; i++) { + invarRest[i] = $("invar" + i); + } + String[] containerNames = new String[numContainers]; + for (int i = 0; i < numContainers; i++) { + containerNames[i] = $("container" + i); + } + String[] indexFormNames = new String[accessIndexForm.length]; + for (int i = 0; i < indexFormNames.length; i++) { + indexFormNames[i] = $("index" + i); + } + return body( + """ + // --- $test start --- + """, + generateTestFields(invarRest, containerNames, indexFormNames), + """ + // Count the run invocations. + private static int $iterations = 0; + + @Run(test = "$test") + @Warmup(100) + public static void $run(RunInfo info) { + + // Once warmup is over (100x), repeat 10x to get reasonable coverage of the + // randomness in the tests. + int reps = info.isWarmUp() ? 10 : 1; + for (int r = 0; r < reps; r++) { + + $iterations++; + """, + generateContainerInit(containerNames), + generateContainerAliasing(containerNames, $("iterations")), + generateRanges(), + generateBoundsAndInvariants(indexFormNames, invarRest), + """ + // Run test and compare with interpreter results. + """, + generateCallMethod("result", $("test"), "test"), + generateCallMethod("expected", $("reference"), "reference"), + """ + Verify.checkEQ(result, expected); + } // end reps + } // end $run + + @Test + """, + generateIRRules(), + generateTestMethod($("test"), invarRest), + """ + @DontCompile + """, + generateTestMethod($("reference"), invarRest), + """ + + // --- $test end --- + """ + ); + }); + return testTemplate.asToken(); + } + + private TemplateToken generateArrayField(String name, MyType type) { + var template = Template.make(() -> body( + let("size", containerByteSize / type.byteSize()), + let("name", name), + let("type", type), + """ + private static #type[] original_#name = new #type[#size]; + private static #type[] test_#name = new #type[#size]; + private static #type[] reference_#name = new #type[#size]; + """ + )); + return template.asToken(); + } + + private TemplateToken generateMemorySegmentField(String name, MyType type) { + var template = Template.make(() -> body( + let("size", containerByteSize / type.byteSize()), + let("byteSize", containerByteSize), + let("name", name), + let("type", type), + (type == myNative + ? """ + private static MemorySegment original_#name = Arena.ofAuto().allocate(#byteSize); + private static MemorySegment test_#name = Arena.ofAuto().allocate(#byteSize); + private static MemorySegment reference_#name = Arena.ofAuto().allocate(#byteSize); + """ + : """ + private static MemorySegment original_#name = MemorySegment.ofArray(new #type[#size]); + private static MemorySegment test_#name = MemorySegment.ofArray(new #type[#size]); + private static MemorySegment reference_#name = MemorySegment.ofArray(new #type[#size]); + """ + ) + )); + return template.asToken(); + } + + private TemplateToken generateIndexField(String name, IndexForm form) { + var template = Template.make(() -> body( + let("name", name), + let("form", form.generate()), + """ + private static IndexForm #name = #form; + """ + )); + return template.asToken(); + } + + private TemplateToken generateTestFields(String[] invarRest, String[] containerNames, String[] indexFormNames) { + var template = Template.make(() -> body( + let("ivType", isLongIvType ? "long" : "int"), + """ + // invarRest fields: + """, + Arrays.stream(invarRest).map(invar -> + List.of("private static #ivType ", invar, " = 0;\n") + ).toList(), + """ + // Containers fields: + """, + Arrays.stream(containerNames).map(name -> + switch (containerKind) { + case ContainerKind.ARRAY -> + generateArrayField(name, containerElementType); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateMemorySegmentField(name, containerElementType); + } + ).toList(), + """ + // Index forms for the accesses: + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + generateIndexField(indexFormNames[i], accessIndexForm[i]) + ).toList() + )); + return template.asToken(); + } + + private TemplateToken generateContainerInitArray(String name) { + var template = Template.make(() -> body( + let("size", containerByteSize / containerElementType.byteSize()), + let("name", name), + """ + System.arraycopy(original_#name, 0, test_#name, 0, #size); + System.arraycopy(original_#name, 0, reference_#name, 0, #size); + """ + )); + return template.asToken(); + } + + private TemplateToken generateContainerInitMemorySegment(String name) { + var template = Template.make(() -> body( + let("size", containerByteSize / containerElementType.byteSize()), + let("name", name), + """ + test_#name.copyFrom(original_#name); + reference_#name.copyFrom(original_#name); + """ + )); + return template.asToken(); + } + + private TemplateToken generateContainerInit(String[] containerNames) { + var template = Template.make(() -> body( + """ + // Init containers from original data: + """, + Arrays.stream(containerNames).map(name -> + switch (containerKind) { + case ContainerKind.ARRAY -> + generateContainerInitArray(name); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateContainerInitMemorySegment(name); + } + ).toList() + )); + return template.asToken(); + } + + private TemplateToken generateContainerAliasingAssignment(int i, String name1, String name2, String iterations) { + var template = Template.make(() -> body( + let("i", i), + let("name1", name1), + let("name2", name2), + let("iterations", iterations), + """ + var test_#i = (#iterations % 2 == 0) ? test_#name1 : test_#name2; + var reference_#i = (#iterations % 2 == 0) ? reference_#name1 : reference_#name2; + """ + )); + return template.asToken(); + } + + private TemplateToken generateContainerAliasing(String[] containerNames, String iterations) { + var template = Template.make(() -> body( + """ + // Container aliasing: + """, + IntStream.range(0, containerNames.length).mapToObj(i -> + switch(aliasing) { + case Aliasing.CONTAINER_DIFFERENT -> + generateContainerAliasingAssignment(i, containerNames[i], containerNames[i], iterations); + case Aliasing.CONTAINER_SAME_ALIASING_NEVER, + Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN -> + generateContainerAliasingAssignment(i, containerNames[0], containerNames[0], iterations); + case Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER, + Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + generateContainerAliasingAssignment(i, containerNames[i], containerNames[0], iterations); + } + ).toList() + )); + return template.asToken(); + } + + private TemplateToken generateRanges() { + int size = switch (containerKind) { + case ContainerKind.ARRAY, + ContainerKind.MEMORY_SEGMENT_AT_INDEX -> + // Access with element index + containerByteSize / accessType[0].byteSize(); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + // Access with byte offset + containerByteSize; + }; + + if (accessIndexForm.length != 2) { throw new RuntimeException("not yet implemented"); } + + var templateSplitRanges = Template.make(() -> body( + let("size", size), + """ + int middle = RANDOM.nextInt(#size / 3, #size * 2 / 3); + int rnd = Math.min(256, #size / 10); + int range = #size / 3 - RANDOM.nextInt(rnd); + """, + (RANDOM.nextBoolean() + // Maximal range + ? """ + var r0 = new IndexForm.Range(0, middle); + var r1 = new IndexForm.Range(middle, #size); + """ + // Same size range + // If the accesses run towards each other, and the runtime + // check is too relaxed, we may fail the checks even though + // there is no overlap. Having same size ranges makes this + // more likely, and we could detect it if we get multiversioning + // unexpectedly. + : """ + var r0 = new IndexForm.Range(middle - range, middle); + var r1 = new IndexForm.Range(middle, middle + range); + """ + ), + """ + if (RANDOM.nextBoolean()) { + var tmp = r0; + r0 = r1; + r1 = tmp; + } + """ + )); + + var templateWholeRanges = Template.make(() -> body( + let("size", size), + """ + var r0 = new IndexForm.Range(0, #size); + var r1 = new IndexForm.Range(0, #size); + """ + )); + + var templateRandomRanges = Template.make(() -> body( + let("size", size), + """ + int lo0 = RANDOM.nextInt(0, #size * 3 / 4); + int lo1 = RANDOM.nextInt(0, #size * 3 / 4); + var r0 = new IndexForm.Range(lo0, lo0 + #size / 4); + var r1 = new IndexForm.Range(lo1, lo1 + #size / 4); + """ + )); + + var templateSmallOverlapRanges = Template.make(() -> body( + // Idea: same size ranges, with size "range". A small overlap, + // so that bad runtime checks would create wrong results. + let("size", size), + """ + int rnd = Math.min(256, #size / 10); + int middle = #size / 2 + RANDOM.nextInt(-rnd, rnd); + int range = #size / 3 - RANDOM.nextInt(rnd); + int overlap = RANDOM.nextInt(-rnd, rnd); + var r0 = new IndexForm.Range(middle - range + overlap, middle + overlap); + var r1 = new IndexForm.Range(middle, middle + range); + if (RANDOM.nextBoolean()) { + var tmp = r0; + r0 = r1; + r1 = tmp; + } + """ + // Can this go out of bounds? Assume worst case on lower end: + // middle - range + overlap + // (size/2 - rnd) - (size/3 - rnd) - rnd + // size/6 - rnd + // -> safe with rnd = size/10 + )); + + var templateAnyRanges = Template.make(() -> body( + switch(RANDOM.nextInt(4)) { + case 0 -> templateSplitRanges.asToken(); + case 1 -> templateWholeRanges.asToken(); + case 2 -> templateRandomRanges.asToken(); + case 3 -> templateSmallOverlapRanges.asToken(); + default -> throw new RuntimeException("impossible"); + } + )); + + var template = Template.make(() -> body( + """ + // Generate ranges: + """, + switch(aliasing) { + case Aliasing.CONTAINER_DIFFERENT -> + templateAnyRanges.asToken(); + case Aliasing.CONTAINER_SAME_ALIASING_NEVER -> + templateSplitRanges.asToken(); + case Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN -> + templateAnyRanges.asToken(); + case Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER -> + templateSplitRanges.asToken(); + case Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + templateAnyRanges.asToken(); + } + )); + return template.asToken(); + } + + private TemplateToken generateBoundsAndInvariants(String[] indexFormNames, String[] invarRest) { + // We want there to be at least 1000 iterations. + final int minIvRange = ivStrideAbs * 1000; + + var template = Template.make(() -> body( + let("containerByteSize", containerByteSize), + """ + // Compute loop bounds and loop invariants. + int ivLo = RANDOM.nextInt(-1000, 1000); + int ivHi = ivLo + #containerByteSize; + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + Template.make(() -> body( + let("i", i), + let("form", indexFormNames[i]), + """ + int invar0_#i = #form.invar0ForIvLo(r#i, ivLo); + ivHi = Math.min(ivHi, #form.ivHiForInvar0(r#i, invar0_#i)); + """ + )).asToken() + ).toList(), + let("minIvRange", minIvRange), + """ + // Let's check that the range is large enough, so that the vectorized + // main loop can even be entered. + if (ivLo + #minIvRange > ivHi) { throw new RuntimeException("iv range too small: " + ivLo + " " + ivHi); } + """, + Arrays.stream(invarRest).map(invar -> + List.of(invar, " = RANDOM.nextInt(-1, 2);\n") + ).toList(), + """ + // Verify the bounds we just created, just to be sure there is no unexpected aliasing! + int i = ivLo; + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + List.of("int lo_", i, " = (int)(", accessIndexForm[i].index("invar0_" + i, invarRest), ");\n") + ).toList(), + """ + i = ivHi; + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + List.of("int hi_", i, " = (int)(", accessIndexForm[i].index("invar0_" + i, invarRest), ");\n") + ).toList(), + switch(aliasing) { + case Aliasing.CONTAINER_SAME_ALIASING_NEVER, + Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER -> // could fail in the future if we make it smarter + List.of( + """ + // Bounds should not overlap. + if (false + """, + IntStream.range(0, indexFormNames.length).mapToObj(i1 -> + IntStream.range(0, i1).mapToObj(i2 -> + Template.make(() -> body( + let("i1", i1), + let("i2", i2), + // i1 < i2 or i1 > i2 + """ + || (lo_#i1 < lo_#i2 && lo_#i1 < hi_#i2 && hi_#i1 < lo_#i2 && hi_#i1 < hi_#i2) + || (lo_#i1 > lo_#i2 && lo_#i1 > hi_#i2 && hi_#i1 > lo_#i2 && hi_#i1 > hi_#i2) + """ + )).asToken() + ).toList() + ).toList(), + """ + ) { + // pass + } else { + throw new RuntimeException("bounds overlap!"); + } + """); + case Aliasing.CONTAINER_DIFFERENT, + Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN, + Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + """ + // Aliasing unknown, cannot verify bounds. + """; + } + )); + return template.asToken(); + } + + + private TemplateToken generateCallMethod(String output, String methodName, String containerPrefix) { + var template = Template.make(() -> body( + let("output", output), + let("methodName", methodName), + "var #output = #methodName(", + IntStream.range(0, numContainers).mapToObj(i -> + List.of(containerPrefix, "_", i, ", invar0_", i, ", ") + ).toList(), + "ivLo, ivHi);\n" + )); + return template.asToken(); + } + + private TemplateToken generateIRRules() { + var template = Template.make(() -> body( + switch (containerKind) { + case ContainerKind.ARRAY -> + generateIRRulesArray(); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX -> + generateIRRulesMemorySegmentAtIndex(); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE -> + generateIRRulesMemorySegmentLongAdrScale(); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateIRRulesMemorySegmentLongAdrStride(); + }, + // In same scnearios, we know that a aliasing runtime check will never fail. + // That means if we have UseAutoVectorizationPredicate enabled, that predicate + // will never fail, and we will not have to do multiversioning. + switch(aliasing) { + case Aliasing.CONTAINER_DIFFERENT, + Aliasing.CONTAINER_SAME_ALIASING_NEVER, + Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER -> + // We would have liked to check that there is no multiversioning. + // + // But sadly there are some cases that have issues with RCE and/or + // predicates, and so we end up using multiversioning anyway. We + // should fix those cases eventually, to strengthen the checks here. + // + // The array cases are a little more tame, and do not have the same + // issues as the MemorySegment cases. + (containerKind == ContainerKind.ARRAY) + ? """ + // Aliasing check should never fail at runtime, so the predicate + // should never fail, and we do not have to use multiversioning. + // Failure could have a few causes: + // - issues with doing RCE / missing predicates + // -> other loop-opts need to be fixed + // - predicate fails: recompile with multiversioning + // -> logic in runtime check may be wrong + @IR(counts = {".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationPredicate", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """ + : """ + // Due to cases like JDK-8360204 and JDK-8365982, there can be issues + // with RCE leading cases where we remove predicates and then unroll again + // and then end up multiversioning. These cases seem relatively rare but + // prevent us from asserting that there is never multiversioning in these cases. + """; + case Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN, + Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + """ + // Aliasing unknown, we may use the predicate or multiversioning. + """; + } + )); + return template.asToken(); + } + + // Regular array-accesses are vectorized quite predictably, and we can create nice + // IR rules - even for cases where we do not expect vectorization. + private TemplateToken generateIRRulesArray() { + var template = Template.make(() -> body( + let("T", containerElementType.letter()), + switch (accessScenario) { + case COPY_LOAD_STORE -> + // Currently, we do not allow strided access or shuffle. + // Since the load and store are connected, we either vectorize both or none. + (accessIndexForm[0].ivScale() == accessIndexForm[1].ivScale() && + Math.abs(accessIndexForm[0].ivScale()) == 1) + ? """ + // Good ivScales, vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """ + : """ + // Bad ivScales, no vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """; + case FILL_STORE_STORE -> + // Currently, we do not allow strided access. + // We vectorize any contiguous pattern. Possibly only one is vectorized. + (Math.abs(accessIndexForm[0].ivScale()) == 1 || + Math.abs(accessIndexForm[1].ivScale()) == 1) + ? """ + // Good ivScales, vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "= 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """ + : """ + // Bad ivScales, no vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """; + } + )); + return template.asToken(); + } + + private TemplateToken generateIRRulesMemorySegmentAtIndex() { + var template = Template.make(() -> body( + """ + // Unfortunately, there are some issues that prevent RangeCheck elimination. + // The cases are currently quite unpredictable, so we cannot create any IR + // rules - sometimes there are vectors sometimes not. + """ + // JDK-8359688: it seems we only vectorize with ivScale=1, and not ivScale=-1 + // The issue seems to be RangeCheck elimination + )); + return template.asToken(); + } + + private TemplateToken generateIRRulesMemorySegmentLongAdrStride() { + var template = Template.make(() -> body( + """ + // Unfortunately, there are some issues that prevent RangeCheck elimination. + // The cases are currently quite unpredictable, so we cannot create any IR + // rules - sometimes there are vectors sometimes not. + """ + )); + return template.asToken(); + } + + private TemplateToken generateIRRulesMemorySegmentLongAdrScale() { + var template = Template.make(() -> body( + """ + // Unfortunately, there are some issues that prevent RangeCheck elimination. + // The cases are currently quite unpredictable, so we cannot create any IR + // rules - sometimes there are vectors sometimes not. + """ + )); + return template.asToken(); + } + + private TemplateToken generateTestMethod(String methodName, String[] invarRest) { + var template = Template.make(() -> body( + let("methodName", methodName), + let("containerElementType", containerElementType), + let("ivStrideAbs", ivStrideAbs), + let("ivType", isLongIvType ? "long" : "int"), + // Method head / signature. + "public static Object #methodName(", + IntStream.range(0, numContainers).mapToObj(i -> + switch (containerKind) { + case ContainerKind.ARRAY -> + List.of("#containerElementType[] container_", i, ", #ivType invar0_", i, ", "); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + List.of("MemorySegment container_", i, ", #ivType invar0_", i, ", "); + } + ).toList(), + "#ivType ivLo, #ivType ivHi) {\n", + // Method loop body. + (loopForward + ? "for (#ivType i = ivLo; i < ivHi; i+=#ivStrideAbs) {\n" + : "for (#ivType i = ivHi-#ivStrideAbs; i >= ivLo; i-=#ivStrideAbs) {\n"), + // Loop iteration. + switch (containerKind) { + case ContainerKind.ARRAY -> + generateTestLoopIterationArray(invarRest); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX -> + generateTestLoopIterationMemorySegmentAtIndex(invarRest); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateTestLoopIterationMemorySegmentLongAdr(invarRest); + }, + """ + } + return new Object[] { + """, + // Return a list of all containers that are involved in the test. + // The caller can then compare the results of the test and reference method. + IntStream.range(0, numContainers).mapToObj(i -> + "container_" + i + ).collect(Collectors.joining(", ")), "\n", + """ + }; + } + """ + )); + return template.asToken(); + } + + private TemplateToken generateTestLoopIterationArray(String[] invarRest) { + var template = Template.make(() -> body( + let("type", containerElementType), + switch (accessScenario) { + case COPY_LOAD_STORE -> + List.of("container_0[", accessIndexForm[0].index("invar0_0", invarRest), "] = ", + "container_1[", accessIndexForm[1].index("invar0_1", invarRest), "];\n"); + case FILL_STORE_STORE -> + List.of("container_0[", accessIndexForm[0].index("invar0_0", invarRest), "] = (#type)0x0102030405060708L;\n", + "container_1[", accessIndexForm[1].index("invar0_1", invarRest), "] = (#type)0x1112131415161718L;\n"); + } + )); + return template.asToken(); + } + + private TemplateToken generateTestLoopIterationMemorySegmentAtIndex(String[] invarRest) { + var template = Template.make(() -> body( + let("type0", accessType[0]), + let("type1", accessType[1]), + let("type0Layout", accessType[0].layout()), + let("type1Layout", accessType[1].layout()), + switch (accessScenario) { + case COPY_LOAD_STORE -> + // Conversion not implemented, index bound computation is too limited for this currently. + List.of("var v = ", + "container_0.getAtIndex(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ");\n", + "container_1.setAtIndex(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", v);\n"); + case FILL_STORE_STORE -> + List.of("container_0.setAtIndex(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ", (#type0)0x0102030405060708L);\n", + "container_1.setAtIndex(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", (#type1)0x1112131415161718L);\n"); + } + )); + return template.asToken(); + } + + private TemplateToken generateTestLoopIterationMemorySegmentLongAdr(String[] invarRest) { + var template = Template.make(() -> body( + let("type0", accessType[0]), + let("type1", accessType[1]), + let("type0Layout", accessType[0].layout()), + let("type1Layout", accessType[1].layout()), + switch (accessScenario) { + case COPY_LOAD_STORE -> + // We allow conversions here. + List.of("#type1 v = (#type1)", + "container_0.get(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ");\n", + "container_1.set(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", v);\n"); + case FILL_STORE_STORE -> + List.of("container_0.set(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ", (#type0)0x0102030405060708L);\n", + "container_1.set(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", (#type1)0x1112131415161718L);\n"); + } + )); + return template.asToken(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java index 74152645a48..b7e62c394ec 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java @@ -31,12 +31,12 @@ * @run driver TestCyclicDependency */ +import java.util.List; import jdk.test.lib.Asserts; import compiler.lib.ir_framework.*; public class TestCyclicDependency { static final int RANGE = 512; - static final int ITER = 100; int[] goldI0 = new int[RANGE]; float[] goldF0 = new float[RANGE]; int[] goldI1 = new int[RANGE]; @@ -73,12 +73,28 @@ public class TestCyclicDependency { float[] goldF9 = new float[RANGE]; public static void main(String args[]) { - TestFramework.runWithFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-AlignVector", "-XX:-VerifyAlignVector"); - TestFramework.runWithFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlignVector", "-XX:-VerifyAlignVector"); - TestFramework.runWithFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlignVector", "-XX:+VerifyAlignVector"); + // Cross-product: + // - AlignVector (+VerifyAlignVector) + // - UseAutoVectorizationSpeculativeAliasingChecks + List avList = List.of( + new String[] {"-XX:-AlignVector", "-XX:-VerifyAlignVector"}, + new String[] {"-XX:+AlignVector", "-XX:-VerifyAlignVector"}, + new String[] {"-XX:+AlignVector", "-XX:+VerifyAlignVector"} + ); + List sacList = List.of( + new String[] {"-XX:-UseAutoVectorizationSpeculativeAliasingChecks"}, + new String[] {"-XX:+UseAutoVectorizationSpeculativeAliasingChecks"} + ); + for (String[] av : avList) { + for (String[] sac : sacList) { + TestFramework framework = new TestFramework(); + framework.addFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", + "-XX:+IgnoreUnrecognizedVMOptions"); + framework.addFlags(av); + framework.addFlags(sac); + framework.start(); + } + } } TestCyclicDependency() { @@ -134,7 +150,7 @@ public class TestCyclicDependency { } @Run(test = "test0") - @Warmup(100) + @Warmup(1000) public void runTest0() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -145,7 +161,7 @@ public class TestCyclicDependency { } @Run(test = "test1") - @Warmup(100) + @Warmup(1000) public void runTest1() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -156,7 +172,7 @@ public class TestCyclicDependency { } @Run(test = "test2") - @Warmup(100) + @Warmup(1000) public void runTest2() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -167,7 +183,7 @@ public class TestCyclicDependency { } @Run(test = "test3") - @Warmup(100) + @Warmup(1000) public void runTest3() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -178,7 +194,7 @@ public class TestCyclicDependency { } @Run(test = "test4") - @Warmup(100) + @Warmup(1000) public void runTest4() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -189,7 +205,7 @@ public class TestCyclicDependency { } @Run(test = "test5a") - @Warmup(100) + @Warmup(1000) public void runTest5a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -200,7 +216,7 @@ public class TestCyclicDependency { } @Run(test = "test5b") - @Warmup(100) + @Warmup(1000) public void runTest5b() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -211,7 +227,7 @@ public class TestCyclicDependency { } @Run(test = "test6a") - @Warmup(100) + @Warmup(1000) public void runTest6a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -222,7 +238,7 @@ public class TestCyclicDependency { } @Run(test = "test6b") - @Warmup(100) + @Warmup(1000) public void runTest6b() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -233,7 +249,7 @@ public class TestCyclicDependency { } @Run(test = "test7a") - @Warmup(100) + @Warmup(1000) public void runTest7a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -244,7 +260,7 @@ public class TestCyclicDependency { } @Run(test = "test7b") - @Warmup(100) + @Warmup(1000) public void runTest7b() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -257,7 +273,7 @@ public class TestCyclicDependency { } @Run(test = "test7c") - @Warmup(100) + @Warmup(1000) public void runTest7c() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -268,7 +284,7 @@ public class TestCyclicDependency { } @Run(test = "test8a") - @Warmup(100) + @Warmup(1000) public void runTest8a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -279,7 +295,7 @@ public class TestCyclicDependency { } @Run(test = "test8b") - @Warmup(100) + @Warmup(1000) public void runTest8b() { int[] dataI = new int[RANGE]; int[] dataI_2 = new int[RANGE]; @@ -292,7 +308,7 @@ public class TestCyclicDependency { } @Run(test = "test8c") - @Warmup(100) + @Warmup(1000) public void runTest8c() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -303,7 +319,7 @@ public class TestCyclicDependency { } @Run(test = "test9") - @Warmup(100) + @Warmup(1000) public void runTest9() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -430,11 +446,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "> 0", - IRNode.ADD_VF, "= 0"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VF, "= 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -445,10 +471,14 @@ public class TestCyclicDependency { dataI[i + 32] = v + 5; // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always different. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two float-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataF and dataF_2 do not alias -> full vectorization. + // Note: at runtime the float-arrays are always different -> predicate suffices, no multiversioning. float f = dataF[i]; dataF_2[i + 3] = f + 3.5f; } @@ -456,11 +486,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.ADD_VF, "= 0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -471,10 +511,15 @@ public class TestCyclicDependency { dataI[i + 32] = v + 5; // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always the same. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two float-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataF and dataF_2 do not alias -> full vectorization. + // multiversion_slow loop can still vectorize, but only with 2 elements. + // Note: at runtime the float-arrays are always the same -> predicate fails -> multiversioning. float f = dataF[i]; dataF_2[i + 3] = f + 3.5f; } @@ -508,11 +553,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE + "2", "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "= 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -520,10 +575,14 @@ public class TestCyclicDependency { for (int i = 0; i < RANGE - 32; i++) { // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always different. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two int-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataI and dataI_2 do not alias -> full vectorization. + // Note: at runtime the int-arrays are always different -> predicate suffices, no multiversioning. int v = dataI[i]; dataI_2[i + 3] = v + 5; // write forward 32 -> more than vector size -> can vectorize @@ -534,11 +593,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE + "2", "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "2", "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", ">0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "= 0", IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -546,10 +615,15 @@ public class TestCyclicDependency { for (int i = 0; i < RANGE - 32; i++) { // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always the same. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two int-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataF and dataF_2 do not alias -> full vectorization. + // multiversion_slow loop can still vectorize, but only with 2 elements. + // Note: at runtime the int-arrays are always the same -> predicate fails -> multiversioning. int v = dataI[i]; dataI_2[i + 3] = v + 5; // write forward 32 -> more than vector size -> can vectorize diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index 24a8581434f..d760c87ad19 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -751,11 +751,13 @@ public class TestDependencyOffsets { // we use shorter vectors to avoid cycles and still vectorize. Vector lengths have to // be powers-of-2, and smaller or equal to the byteOffset. So we round down to the next // power of two. + // If we have two array references, then we can speculate that they do not alias, and + // still produce full vectorization. int infinity = 256; // No vector size is ever larger than this. int maxVectorWidth = infinity; // no constraint by default int log2 = 31 - Integer.numberOfLeadingZeros(offset); int floorPow2Offset = 1 << log2; - if (0 < byteOffset && byteOffset < maxVectorWidth) { + if (isSingleArray && 0 < byteOffset && byteOffset < maxVectorWidth) { maxVectorWidth = Math.min(maxVectorWidth, floorPow2Offset * type.size); builder.append(" // Vectors must have at most " + floorPow2Offset + " elements: maxVectorWidth = " + maxVectorWidth + diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java index 502fad5be96..a2b5434a5a2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java @@ -47,6 +47,22 @@ import java.lang.foreign.*; * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray AlignVector */ +/* + * @test id=byte-array-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=byte-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray AlignVector NoSpeculativeAliasingCheck + */ + /* * @test id=byte-array-NoShortRunningLongLoop * @bug 8329273 8342692 @@ -63,6 +79,13 @@ import java.lang.foreign.*; * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray AlignVector NoShortRunningLongLoop */ +/* + * @test id=byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8329273 8348263 8342692 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ /* * @test id=char-array @@ -160,6 +183,46 @@ import java.lang.foreign.*; * @run driver compiler.loopopts.superword.TestMemorySegment Native AlignVector */ +/* + * @test id=native-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-AlignVector-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-NoShortRunningLongLoop + * @bug 8329273 8342692 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native NoShortRunningLongLoop + */ + +/* + * @test id=native-AlignVector-NoShortRunningLongLoop + * @bug 8329273 8348263 8342692 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native AlignVector NoShortRunningLongLoop + */ + +/* + * @test id=native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8329273 8348263 8342692 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + // FAILS: mixed providers currently do not vectorize. Maybe there is some inlining issue. // /* // * @test id=mixed-array @@ -193,12 +256,14 @@ public class TestMemorySegment { String tag = args[i]; switch (tag) { case "AlignVector" -> framework.addFlags("-XX:+AlignVector"); + case "NoSpeculativeAliasingCheck" -> framework.addFlags("-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); + // Disabling the ShortRunningLongLoop optimization changes the shape of the loop. + // Testing both with and without it allows us to simulate long running loops with short running loops, + // i.e. we don't need to allocate massive amounts of memory. case "NoShortRunningLongLoop" -> framework.addFlags("-XX:-ShortRunningLongLoop"); + default -> throw new RuntimeException("Bad tag: " + tag); } } - if (args.length > 1 && args[1].equals("AlignVector")) { - framework.addFlags("-XX:+AlignVector"); - } framework.setDefaultWarmup(100); framework.start(); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java new file mode 100644 index 00000000000..c956ac9a0d4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.loopopts.superword; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import jdk.test.lib.Utils; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; +import java.lang.foreign.*; + +/* + * @test id=byte-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray + */ + +/* + * @test id=byte-array-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector + */ + +/* + * @test id=byte-array-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=byte-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=byte-array-NoAutoAlignment + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoAutoAlignment + */ + +/* + * @test id=byte-array-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoShortRunningLongLoop + */ + +/* + * @test id=byte-array-AlignVector-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector NoShortRunningLongLoop + */ + +/* + * @test id=byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + +/* + * @test id=char-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing CharArray + */ + +/* + * @test id=short-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ShortArray + */ + +/* + * @test id=int-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray + */ + +/* + * @test id=int-array-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray AlignVector + */ + +/* + * @test id=int-array-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=int-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=int-array-NoAutoAlignment + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoAutoAlignment + */ + +/* + * @test id=int-array-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoShortRunningLongLoop + */ + +/* + * @test id=int-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + +/* + * @test id=long-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray + */ + +/* + * @test id=long-array-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray AlignVector + */ + +/* + * @test id=long-array-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=long-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=float-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing FloatArray + */ + +/* + * @test id=double-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing DoubleArray + */ + +/* + * @test id=byte-buffer + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteBuffer + */ + +/* + * @test id=byte-buffer-direct + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteBufferDirect + */ + +/* + * @test id=native + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native + */ + +/* + * @test id=native-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector + */ + +/* + * @test id=native-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoShortRunningLongLoop + */ + +/* + * @test id=native-AlignVector-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector NoShortRunningLongLoop + */ + +/* + * @test id=native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + +public class TestMemorySegmentAliasing { + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestMemorySegmentAliasingImpl.class); + framework.addFlags("-DmemorySegmentProviderNameForTestVM=" + args[0]); + for (int i = 1; i < args.length; i++) { + String tag = args[i]; + switch (tag) { + case "AlignVector" -> framework.addFlags("-XX:+AlignVector"); + case "NoSpeculativeAliasingCheck" -> framework.addFlags("-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); + // automatic alignment has an impact on where the main-loop starts, and that affects init and limit + // of the main loop. + case "NoAutoAlignment" -> framework.addFlags("-XX:SuperWordAutomaticAlignment=0"); + // Disabling the ShortRunningLongLoop optimization changes the shape of the loop. + // Testing both with and without it allows us to simulate long running loops with short running loops, + // i.e. we don't need to allocate massive amounts of memory. + case "NoShortRunningLongLoop" -> framework.addFlags("-XX:-ShortRunningLongLoop"); + default -> throw new RuntimeException("Bad tag: " + tag); + } + } + framework.setDefaultWarmup(100); + framework.start(); + } +} + +class TestMemorySegmentAliasingImpl { + static final int BACKING_SIZE = 1024 * 8; + static final Random RANDOM = Utils.getRandomInstance(); + + + interface TestFunction { + void run(); + } + + interface MemorySegmentProvider { + MemorySegment newMemorySegment(); + } + + public static MemorySegmentProvider provider; + + static { + String providerName = System.getProperty("memorySegmentProviderNameForTestVM"); + provider = switch (providerName) { + case "ByteArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteArray; + case "CharArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfCharArray; + case "ShortArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfShortArray; + case "IntArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfIntArray; + case "LongArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfLongArray; + case "FloatArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfFloatArray; + case "DoubleArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfDoubleArray; + case "ByteBuffer" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteBuffer; + case "ByteBufferDirect" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteBufferDirect; + case "Native" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfNative; + case "MixedArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixedArray; + case "MixedBuffer" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixedBuffer; + case "Mixed" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixed; + default -> throw new RuntimeException("Test argument not recognized: " + providerName); + }; + } + + // Map of goldTests + public static Map goldTests = new HashMap<>(); + + // Map of gold for the goldTests, the results from the first run before compilation + public static Map golds = new HashMap<>(); + + // Map of referenceTests, i.e. tests that have a reference implementation that is run with the interpreter. + // The TestFunction must run both the test and reference methods. + public static Map referenceTests = new HashMap<>(); + + // Original data. + public static MemorySegment ORIG_A = fillRandom(newMemorySegment()); + public static MemorySegment ORIG_B = fillRandom(newMemorySegment()); + public static MemorySegment ORIG_C = fillRandom(newMemorySegment()); + + // The data we use in the tests. It is initialized from ORIG_* every time. + public static MemorySegment A = newMemorySegment(); + public static MemorySegment B = newMemorySegment(); + public static MemorySegment C = newMemorySegment(); + + // Parallel to data above, but for use in reference methods. + public static MemorySegment A_REFERENCE = newMemorySegment(); + public static MemorySegment B_REFERENCE = newMemorySegment(); + public static MemorySegment C_REFERENCE = newMemorySegment(); + + public TestMemorySegmentAliasingImpl () { + // Add all goldTests to list + goldTests.put("test_byte_incr_noaliasing", () -> test_byte_incr_noaliasing(A, B)); + goldTests.put("test_byte_incr_aliasing", () -> test_byte_incr_aliasing(A, A)); + goldTests.put("test_byte_incr_aliasing_fwd3", () -> { + MemorySegment x = A.asSlice(0, BACKING_SIZE - 3); + MemorySegment y = A.asSlice(3, BACKING_SIZE - 3); + test_byte_incr_aliasing_fwd3(x, y); + }); + goldTests.put("test_byte_incr_noaliasing_fwd128", () -> { + MemorySegment x = A.asSlice(0, BACKING_SIZE - 128); + MemorySegment y = A.asSlice(120, BACKING_SIZE - 128); + test_byte_incr_noaliasing_fwd128(x, y); + }); + + goldTests.put("test_int_to_long_noaliasing", () -> test_int_to_long_noaliasing(A, B)); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + init(); + test.run(); + Object gold = snapshotCopy(); + golds.put(name, gold); + } + + referenceTests.put("test_fill_byte_sameMS_alias", () -> { + int invar1 = RANDOM.nextInt(64); + int invar2 = RANDOM.nextInt(64); + test_fill_byte_sameMS_alias(A, A, invar1, invar2); + reference_fill_byte_sameMS_alias(A_REFERENCE, A_REFERENCE, invar1, invar2); + }); + referenceTests.put("test_fill_byte_sameMS_noalias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // But they never overlap. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle; + int invar2 = middle; + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_byte_sameMS_noalias(A, A, invar1, invar2, limit); + reference_fill_byte_sameMS_noalias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + referenceTests.put("test_fill_byte_sameMS_maybeAlias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // In the middle, sometimes we overlap and sometimes not. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle + RANDOM.nextInt(-256, 256); + int invar2 = middle + RANDOM.nextInt(-256, 256); + // Are the bounds safe? Assume extreme values: + // invar1 = 8k/2 + 256 + 256 + // limit = 8k/3 + 256 + // invar1 + limit = 8k * 5/6 + 3 * 256 + // = 8k * 5/6 + 3/4 * 1k = 7.41k < 8k + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_byte_sameMS_maybeAlias(A, A, invar1, invar2, limit); + reference_fill_byte_sameMS_maybeAlias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + referenceTests.put("test_fill_int_sameMS_alias", () -> { + int invar1 = RANDOM.nextInt(64); + int invar2 = RANDOM.nextInt(64); + test_fill_int_sameMS_alias(A, A, invar1, invar2); + reference_fill_int_sameMS_alias(A_REFERENCE, A_REFERENCE, invar1, invar2); + }); + referenceTests.put("test_fill_int_sameMS_noalias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // But they never overlap. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle; + int invar2 = middle; + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_int_sameMS_noalias(A, A, invar1, invar2, limit); + reference_fill_int_sameMS_noalias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + referenceTests.put("test_fill_int_sameMS_maybeAlias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // In the middle, sometimes we overlap and sometimes not. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle + RANDOM.nextInt(-256, 256); + int invar2 = middle + RANDOM.nextInt(-256, 256); + // Are the bounds safe? Assume extreme values: + // invar1 = 8k/2 + 256 + 256 + // limit = 8k/3 + 256 + // invar1 + limit = 8k * 5/6 + 3 * 256 + // = 8k * 5/6 + 3/4 * 1k = 7.41k < 8k + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_int_sameMS_maybeAlias(A, A, invar1, invar2, limit); + reference_fill_int_sameMS_maybeAlias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + } + + static MemorySegment newMemorySegment() { + return provider.newMemorySegment(); + } + + static MemorySegment copy(MemorySegment src) { + MemorySegment dst = newMemorySegment(); + dst.copyFrom(src); + return dst; + } + + static MemorySegment newMemorySegmentOfByteArray() { + return MemorySegment.ofArray(new byte[BACKING_SIZE]); + } + + static MemorySegment newMemorySegmentOfCharArray() { + return MemorySegment.ofArray(new char[BACKING_SIZE / 2]); + } + + static MemorySegment newMemorySegmentOfShortArray() { + return MemorySegment.ofArray(new short[BACKING_SIZE / 2]); + } + + static MemorySegment newMemorySegmentOfIntArray() { + return MemorySegment.ofArray(new int[BACKING_SIZE / 4]); + } + + static MemorySegment newMemorySegmentOfLongArray() { + return MemorySegment.ofArray(new long[BACKING_SIZE / 8]); + } + + static MemorySegment newMemorySegmentOfFloatArray() { + return MemorySegment.ofArray(new float[BACKING_SIZE / 4]); + } + + static MemorySegment newMemorySegmentOfDoubleArray() { + return MemorySegment.ofArray(new double[BACKING_SIZE / 8]); + } + + static MemorySegment newMemorySegmentOfByteBuffer() { + return MemorySegment.ofBuffer(ByteBuffer.allocate(BACKING_SIZE)); + } + + static MemorySegment newMemorySegmentOfByteBufferDirect() { + return MemorySegment.ofBuffer(ByteBuffer.allocateDirect(BACKING_SIZE)); + } + + static MemorySegment newMemorySegmentOfNative() { + // Auto arena: GC decides when there is no reference to the MemorySegment, + // and then it deallocates the backing memory. + return Arena.ofAuto().allocate(BACKING_SIZE, 1); + } + + static MemorySegment newMemorySegmentOfMixedArray() { + switch(RANDOM.nextInt(7)) { + case 0 -> { return newMemorySegmentOfByteArray(); } + case 1 -> { return newMemorySegmentOfCharArray(); } + case 2 -> { return newMemorySegmentOfShortArray(); } + case 3 -> { return newMemorySegmentOfIntArray(); } + case 4 -> { return newMemorySegmentOfLongArray(); } + case 5 -> { return newMemorySegmentOfFloatArray(); } + default -> { return newMemorySegmentOfDoubleArray(); } + } + } + + static MemorySegment newMemorySegmentOfMixedBuffer() { + switch (RANDOM.nextInt(2)) { + case 0 -> { return newMemorySegmentOfByteBuffer(); } + default -> { return newMemorySegmentOfByteBufferDirect(); } + } + } + + static MemorySegment newMemorySegmentOfMixed() { + switch (RANDOM.nextInt(3)) { + case 0 -> { return newMemorySegmentOfMixedArray(); } + case 1 -> { return newMemorySegmentOfMixedBuffer(); } + default -> { return newMemorySegmentOfNative(); } + } + } + + static MemorySegment fillRandom(MemorySegment data) { + for (int i = 0; i < (int)data.byteSize(); i += 8) { + data.set(ValueLayout.JAVA_LONG_UNALIGNED, i, RANDOM.nextLong()); + } + return data; + } + + public static void init() { + A.copyFrom(ORIG_A); + B.copyFrom(ORIG_B); + C.copyFrom(ORIG_C); + } + + public static void initReference() { + A_REFERENCE.copyFrom(ORIG_A); + B_REFERENCE.copyFrom(ORIG_B); + C_REFERENCE.copyFrom(ORIG_C); + } + + public static Object snapshotCopy() { + return new Object[]{copy(A), copy(B), copy(C)}; + } + + public static Object snapshot() { + return new Object[]{A, B, C}; + } + + public static Object snapshotReference() { + return new Object[]{A_REFERENCE, B_REFERENCE, C_REFERENCE}; + } + + @Run(test = {"test_byte_incr_noaliasing", + "test_byte_incr_aliasing", + "test_byte_incr_aliasing_fwd3", + "test_byte_incr_noaliasing_fwd128", + "test_int_to_long_noaliasing", + "test_fill_byte_sameMS_alias", + "test_fill_byte_sameMS_noalias", + "test_fill_byte_sameMS_maybeAlias", + "test_fill_int_sameMS_alias", + "test_fill_int_sameMS_noalias", + "test_fill_int_sameMS_maybeAlias"}) + void runTests(RunInfo info) { + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object gold = golds.get(name); + // Compute new result + init(); + test.run(); + Object result = snapshot(); + // Compare gold and new result + try { + Verify.checkEQ(gold, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + + // Once warmup is over (100x), repeat 10x to get reasonable coverage of the + // randomness in the tests. + int reps = info.isWarmUp() ? 10 : 1; + for (int r = 0; r < reps; r++) { + for (Map.Entry entry : referenceTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Init data for test and reference + init(); + initReference(); + // Run test and reference + test.run(); + // Capture results from test and reference + Object result = snapshot(); + Object expected = snapshotReference(); + // Compare expected and new result + try { + Verify.checkEQ(expected, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_noaliasing(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_aliasing(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_aliasing_fwd3(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_noaliasing_fwd128(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // In this case, the limit is pre-loop independent, but its assigned + // ctrl sits between main and pre loop. Only the early ctrl is before + // the pre loop. + static void test_int_to_long_noaliasing(MemorySegment a, MemorySegment b) { + long limit = a.byteSize() / 8L; + for (long i = 0; i < limit; i++) { + int v = a.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i); + b.set(ValueLayout.JAVA_LONG_UNALIGNED, 8L * i, v); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + static void test_fill_byte_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i++) { + a.set(ValueLayout.JAVA_BYTE, i + invar1, (byte)0x0a); + b.set(ValueLayout.JAVA_BYTE, a.byteSize() - i - 1 - invar2, (byte)0x0b); + } + } + + @DontCompile + static void reference_fill_byte_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i++) { + a.set(ValueLayout.JAVA_BYTE, i + invar1, (byte)0x0a); + b.set(ValueLayout.JAVA_BYTE, a.byteSize() - i - 1 - invar2, (byte)0x0b); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // For now, we just assert that there is never multiversioning, which holds with or without vectorization: + @IR(counts = {".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_fill_byte_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @DontCompile + static void reference_fill_byte_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0"}, + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // Note: we may or may not use multiversioning, depending if we alias or not at runtime. + static void test_fill_byte_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @DontCompile + static void reference_fill_byte_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + static void test_fill_int_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, i + invar1, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, a.byteSize() - i - 4 - invar2, 0x11121314); + } + } + + @DontCompile + static void reference_fill_int_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, i + invar1, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, a.byteSize() - i - 4 - invar2, 0x11121314); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // For now, we just assert that there is never multiversioning, which holds with or without vectorization: + @IR(counts = {".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_fill_int_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } + + @DontCompile + static void reference_fill_int_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0"}, + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // Note: we may or may not use multiversioning, depending if we alias or not at runtime. + static void test_fill_int_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } + + @DontCompile + static void reference_fill_int_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java new file mode 100644 index 00000000000..cac69901a32 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.loopopts.superword; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8324751 + * @summary Reported issue: JDK-8359688: C2 SuperWord: missing RCE with MemorySegment + * The examples are generated from TestAliasingFuzzer.java + * So if you see something change here, you may want to investigate if we + * can also tighten up the IR rules there. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment_8359688 + */ + + +public class TestMemorySegment_8359688 { + + public static MemorySegment b = MemorySegment.ofArray(new long[4 * 30_000]); + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Setup + static Object[] setup() { + return new Object[] { b, 0, 5_000, 0 }; + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.STORE_VECTOR, "= 0", + IRNode.REPLICATE_L, "= 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES, there is no aliasing + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // Does not manage to remove all RangeChecks -> no vectorization + // If you see this IR rule fail: investigate JDK-8359688, possibly close it and fix this IR rule! + // Also: consider renaming the file to something more descriptive: what have you fixed with this? + // And: you may now be able to tighten IR rules in TestAliasingFuzzer.java + public static void test1(MemorySegment b, int ivLo, int ivHi, int invar) { + for (int i = ivLo; i < ivHi; i++) { + b.setAtIndex(ValueLayout.JAVA_LONG_UNALIGNED, 30_000L - (long)i + (long)invar, 42); + // ^ subtraction here + } + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + IRNode.REPLICATE_L, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES, there is no aliasing + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // Is fully RFE'd and vectorized + public static void test2(MemorySegment b, int ivLo, int ivHi, int invar) { + for (int i = ivLo; i < ivHi; i++) { + b.setAtIndex(ValueLayout.JAVA_LONG_UNALIGNED, 1_000L + 1L * i + (long)invar, 42); + // ^ addition here + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java new file mode 100644 index 00000000000..ecefcec8afa --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.loopopts.superword; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8324751 + * @summary Reported issue: JDK-8360204: C2 SuperWord: missing RCE with MemorySegment.getAtIndex + * The examples are generated from TestAliasingFuzzer.java + * So if you see something change here, you may want to investigate if we + * can also tighten up the IR rules there. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment_8360204 + */ + +public class TestMemorySegment_8360204 { + + public static MemorySegment a = Arena.ofAuto().allocate(10_000); + public static MemorySegment b = Arena.ofAuto().allocate(10_000); + + private static long invar0_1159 = 0; + private static long invar1_1159 = 0; + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Setup + static Object[] setup() { + return new Object[] { a, -19125L, b, 71734L + 2_000L, 0, 1_000 }; + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "> 0"}, // Sadly, we now multiversion + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // There is no aliasing, so we should compile without multiversioning. + // But currently, there seems to be some issue with RCE, we peel and lose the predicate. + // Then we multiversion. + // We could imagine that this would eventually vectorize, but since one counts up, and the other down, + // we would have to implement shuffle first. + // + // If you see this IR rule fail: investigate JDK-8360204, possibly close it and fix this IR rule! + // Also: consider renaming the file to something more descriptive: what have you fixed with this? + // And: you may now be able to tighten IR rules in TestAliasingFuzzer.java + public static void test(MemorySegment container_0, long invar0_0, MemorySegment container_1, long invar0_1, long ivLo, long ivHi) { + for (long i = ivLo; i < ivHi; i+=1) { + var v = container_0.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED, 19125L + 1L * i + 1L * invar0_0 + 0L * invar0_1159 + 1L * invar1_1159); + container_1.setAtIndex(ValueLayout.JAVA_INT_UNALIGNED, -71734L + -1L * i + 1L * invar0_1 + 1L * invar0_1159 + 0L * invar1_1159, v); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java new file mode 100644 index 00000000000..65fd3861174 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.loopopts.superword; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8324751 + * @summary Reported issue: JDK-8365982: C2 SuperWord: missing RCE / strange Multiversioning with MemorySegment.set + * The examples are generated from TestAliasingFuzzer.java + * So if you see something change here, you may want to investigate if we + * can also tighten up the IR rules there. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment_8365982 + */ + +public class TestMemorySegment_8365982 { + + public static MemorySegment a = MemorySegment.ofArray(new short[100_000]); + public static MemorySegment b = MemorySegment.ofArray(new short[100_000]); + + private static long invar0_853 = 0; + private static long invar1_853 = 0; + private static long invar2_853 = 0; + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Setup + static Object[] setup() { + return new Object[] { a, -50_000, b, -30_000, 0, 10_000 }; + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + IRNode.REPLICATE_S, "> 0", + ".*multiversion.*", "= 0"}, // Good: The AutoVectorization predicate suffices. + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "ShortRunningLongLoop", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + IRNode.REPLICATE_S, "> 0", + ".*multiversion.*", "> 0"}, // Bad: Sadly, we now multiversion + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "ShortRunningLongLoop", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // Some but not all predicates are RCE'd at the beginning. After unrolling, we multiversion (why?). + // After PreMainPost, we can do more RangeCheck. Now the main-loop of the multiversion_fast loop + // does not have any range checks any more. + // Now it vectorizes. That's good, but we should be able to vectorize without multiversioning. + // + // If you see this IR rule fail: investigate JDK-8365982, possibly close it and fix this IR rule! + // Also: consider renaming the file to something more descriptive: what have you fixed with this? + // And: you may now be able to tighten IR rules in TestAliasingFuzzer.java + public static void test(MemorySegment container_0, long invar0_0, MemorySegment container_1, long invar0_1, long ivLo, long ivHi) { + for (long i = ivHi-1; i >= ivLo; i-=1) { + container_0.set(ValueLayout.JAVA_CHAR_UNALIGNED, -47143L + -2L * i + -2L * invar0_0 + -1L * invar0_853 + -1L * invar1_853 + 0L * invar2_853, (char)0x0102030405060708L); + container_1.set(ValueLayout.JAVA_CHAR_UNALIGNED, 74770L + 2L * i + 2L * invar0_1 + 0L * invar0_853 + 0L * invar1_853 + 0L * invar2_853, (char)0x1112131415161718L); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java index 80a877bfce5..631b55fc65f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java @@ -37,10 +37,14 @@ import java.nio.ByteOrder; * @bug 8326139 8348659 * @summary Test splitting packs in SuperWord * @library /test/lib / - * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV - * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_yAV - * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_nAV - * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_yAV + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_yAV_nSAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_yAV_nSAC */ public class TestSplitPacks { @@ -76,10 +80,14 @@ public class TestSplitPacks { TestFramework framework = new TestFramework(TestSplitPacks.class); framework.addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:LoopUnrollLimit=1000"); switch (args[0]) { - case "nCOH_nAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "nCOH_yAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"); } - case "yCOH_nAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "yCOH_yAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"); } + case "nCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } }; framework.start(); @@ -114,6 +122,13 @@ public class TestSplitPacks { tests.put("test4e", () -> { return test4e(aS.clone(), bS.clone()); }); tests.put("test4f", () -> { return test4f(aS.clone(), bS.clone()); }); tests.put("test4g", () -> { return test4g(aS.clone(), bS.clone()); }); + tests.put("test4a_alias",() -> { short[] x = aS.clone(); return test4a_alias(x, x); }); + tests.put("test4b_alias",() -> { short[] x = aS.clone(); return test4b_alias(x, x); }); + tests.put("test4c_alias",() -> { short[] x = aS.clone(); return test4c_alias(x, x); }); + tests.put("test4d_alias",() -> { short[] x = aS.clone(); return test4d_alias(x, x); }); + tests.put("test4e_alias",() -> { short[] x = aS.clone(); return test4e_alias(x, x); }); + tests.put("test4f_alias",() -> { short[] x = aS.clone(); return test4f_alias(x, x); }); + tests.put("test4g_alias",() -> { short[] x = aS.clone(); return test4g_alias(x, x); }); tests.put("test5a", () -> { return test5a(aS.clone(), bS.clone(), mS); }); tests.put("test6a", () -> { return test6a(aI.clone(), bI.clone()); }); tests.put("test7a", () -> { return test7a(aI.clone(), bI.clone()); }); @@ -145,6 +160,13 @@ public class TestSplitPacks { "test4e", "test4f", "test4g", + "test4a_alias", + "test4b_alias", + "test4c_alias", + "test4d_alias", + "test4e_alias", + "test4f_alias", + "test4g_alias", "test5a", "test6a", "test7a"}) @@ -711,10 +733,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", - IRNode.STORE_VECTOR, "> 0"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true"}) // Cyclic dependency with distance 2 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4a(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+2] = a[i+0]; @@ -724,11 +757,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true"}) // Cyclic dependency with distance 3 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4b(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+3] = a[i+0]; @@ -738,11 +781,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIf = {"MaxVectorSize", ">=8"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 4 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4c(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+4] = a[i+0]; @@ -752,11 +805,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 5 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4d(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+5] = a[i+0]; @@ -766,11 +829,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 6 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4e(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+6] = a[i+0]; @@ -780,11 +853,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 7 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4f(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+7] = a[i+0]; @@ -794,11 +877,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIf = {"MaxVectorSize", ">=32"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 8 -> split into 8-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4g(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+8] = a[i+0]; @@ -806,6 +899,181 @@ public class TestSplitPacks { return new Object[]{ a, b }; } + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Cyclic dependency with distance 2 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4a_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+2] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Cyclic dependency with distance 3 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4b_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+3] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 4 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4c_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+4] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 5 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4d_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+5] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 6 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4e_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+6] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 7 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4f_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+7] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 8 -> split into 8-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4g_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+8] = a[i+0]; + } + return new Object[]{ a, b }; + } + @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java index 8df1e03e3f4..8d4822ade57 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java @@ -31,10 +31,18 @@ * compiler.vectorization.runner.VectorizationTestRunner * * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI - * compiler.vectorization.runner.LoopArrayIndexComputeTest + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest nAV_ySAC + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest yAV_ySAC + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest nAV_nSAC + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest yAV_nSAC * * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") * @requires vm.compiler2.enabled @@ -48,6 +56,18 @@ import java.util.Random; public class LoopArrayIndexComputeTest extends VectorizationTestRunner { + // We must pass the flags directly to the test-VM, and not the driver vm in the @run above. + @Override + protected String[] testVMFlags(String[] args) { + return switch (args[0]) { + case "nAV_ySAC" -> new String[]{"-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"}; + case "yAV_ySAC" -> new String[]{"-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"}; + case "nAV_nSAC" -> new String[]{"-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"}; + case "yAV_nSAC" -> new String[]{"-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"}; + default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } + }; + } + private static final int SIZE = 6543; private int[] ints; @@ -175,7 +195,16 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.LOAD_VECTOR_I, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public int[] indexWithDifferentConstantsNeg() { int[] res = new int[SIZE]; for (int i = 1; i < SIZE / 4; i++) { @@ -186,7 +215,16 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.LOAD_VECTOR_I, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public int[] indexWithDifferentInvariants() { int[] res = new int[SIZE]; for (int i = SIZE / 4; i < SIZE / 2; i++) { @@ -276,7 +314,17 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.MUL_VS, ">0", + IRNode.LOAD_VECTOR_S, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public short[] shortArrayWithDependenceNeg() { short[] res = new short[SIZE]; System.arraycopy(shorts, 0, res, 0, SIZE); @@ -304,8 +352,11 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Data dependency at distance 2: restrict vector size to 2 @IR(applyIfCPUFeatureOr = {"sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + phase = CompilePhase.PRINT_IDEAL, counts = {IRNode.STORE_VECTOR, ">0", - IRNode.MUL_VS, IRNode.VECTOR_SIZE_2, ">0"}) // size 2 only + IRNode.MUL_VS, IRNode.VECTOR_SIZE_2, ">0", // size 2 only + ".*multiversion.*", "= 0"}) public char[] charArrayWithDependenceNeg() { char[] res = new char[SIZE]; System.arraycopy(chars, 0, res, 0, SIZE); @@ -332,12 +383,22 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + failOn = {IRNode.STORE_VECTOR}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.ADD_VB, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public byte[] byteArrayWithDependenceNeg() { byte[] res = new byte[SIZE]; System.arraycopy(bytes, 0, res, 0, SIZE); for (int i = 3; i < SIZE / 2; i++) { - res[i] *= bytes[i - 3]; + res[i] += bytes[i - 3]; } return res; } @@ -359,8 +420,19 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Data dependency at distance 4: restrict vector size to 4 @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + phase = CompilePhase.PRINT_IDEAL, counts = {IRNode.STORE_VECTOR, ">0", - IRNode.OR_VB, IRNode.VECTOR_SIZE_4, ">0"}) // size 4 only + IRNode.OR_VB, IRNode.VECTOR_SIZE_4, ">0", // size 4 only + ".*multiversion.*", "= 0"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.OR_VB, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public boolean[] booleanArrayWithDependenceNeg() { boolean[] res = new boolean[SIZE]; System.arraycopy(booleans, 0, res, 0, SIZE); @@ -386,7 +458,16 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.LOAD_VECTOR_I, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public int[] differentIndexWithSameType() { int[] res1 = new int[SIZE]; int[] res2 = new int[SIZE]; diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java new file mode 100644 index 00000000000..9c8270e4660 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java @@ -0,0 +1,308 @@ +/* + * 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. + */ +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 = 1, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1) +public abstract class VectorAliasing { + @Param({/*"512", "1024", */ "10000"}) + public int SIZE; + + public static int INVAR_ZERO = 0; + + // For all types we have an "a" and "b" series. Each series is an alias to the same array. + private byte[] aB; + private byte[] bB; + + private int[] aI; + private int[] bI; + + private long[] aL; + private long[] bL; + + private int iteration = 0; + + @Param("0") + private int seed; + private Random r = new Random(seed); + + @Setup + public void init() { + aB = new byte[SIZE]; + bB = new byte[SIZE]; + + aI = new int[SIZE]; + bI = new int[SIZE]; + + aL = new long[SIZE]; + bL = new long[SIZE]; + + for (int i = 0; i < SIZE; i++) { + aB[i] = (byte) r.nextInt(); + bB[i] = (byte) r.nextInt(); + + aI[i] = r.nextInt(); + bI[i] = r.nextInt(); + + aL[i] = r.nextLong(); + bL[i] = r.nextLong(); + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_B(byte[] a, byte b[]) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_B(byte[] a, byte b[], int aOffset, int bOffset, int size) { + for (int i = 0; i < size; i++) { + b[i + bOffset] = a[i + aOffset]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_I(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_I(int[] a, int[] b, int aOffset, int bOffset, int size) { + for (int i = 0; i < size; i++) { + b[i + bOffset] = a[i + aOffset]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_L(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_L(long[] a, long[] b, int aOffset, int bOffset, int size) { + for (int i = 0; i < size; i++) { + b[i + bOffset] = a[i + aOffset]; + } + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_B_sameIndex_noalias() { + copy_B(bB, aB); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_B_sameIndex_alias() { + copy_B(aB, aB); + } + + @Benchmark + // Vectorizes if has at least one of: predicate or multiversioning + public void bench_copy_array_B_differentIndex_noalias() { + copy_B(bB, aB, 0, 0, aB.length); + } + + @Benchmark + // never vectorizes, with our without runtime check + public void bench_copy_array_B_differentIndex_alias() { + copy_B(aB, aB, 0, 0, aB.length); + } + + @Benchmark + // Requires multiversioning for vectorization. + // With only the predicate, we will eventually deopt and compile without vectorization. + public void bench_copy_array_B_differentIndex_mixed() { + if ((iteration++) % 2 == 0) { + copy_B(bB, aB, 0, 0, aB.length); // noalias + } else { + copy_B(aB, aB, 0, 0, aB.length); // alias + } + } + + // No overlap -> expect vectoirzation. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_B_half() { + copy_B(aB, aB, 0, aB.length / 2, aB.length / 2); + } + + // Overlap, but never alias -> expect vectorization. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_B_partial_overlap() { + copy_B(aB, aB, 0, aB.length / 4, aB.length / 4 * 3); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_I_sameIndex_noalias() { + copy_I(bI, aI); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_I_sameIndex_alias() { + copy_I(aI, aI); + } + + @Benchmark + // Vectorizes if has at least one of: predicate or multiversioning + public void bench_copy_array_I_differentIndex_noalias() { + copy_I(bI, aI, 0, 0, aI.length); + } + + @Benchmark + // never vectorizes, with our without runtime check + public void bench_copy_array_I_differentIndex_alias() { + copy_I(aI, aI, 0, 0, aI.length); + } + + @Benchmark + // Requires multiversioning for vectorization. + // With only the predicate, we will eventually deopt and compile without vectorization. + public void bench_copy_array_I_differentIndex_mixed() { + if ((iteration++) % 2 == 0) { + copy_I(bI, aI, 0, 0, aI.length); // noalias + } else { + copy_I(aI, aI, 0, 0, aI.length); // alias + } + } + + // No overlap -> expect vectoirzation. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_I_half() { + copy_I(aI, aI, 0, aI.length / 2, aI.length / 2); + } + + // Overlap, but never alias -> expect vectorization. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_I_partial_overlap() { + copy_I(aI, aI, 0, aI.length / 4, aI.length / 4 * 3); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_L_sameIndex_noalias() { + copy_L(bL, aL); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_L_sameIndex_alias() { + copy_L(aL, aL); + } + + @Benchmark + // Vectorizes if has at least one of: predicate or multiversioning + public void bench_copy_array_L_differentIndex_noalias() { + copy_L(bL, aL, 0, 0, aL.length); + } + + @Benchmark + // never vectorizes, with our without runtime check + public void bench_copy_array_L_differentIndex_alias() { + copy_L(aL, aL, 0, 0, aL.length); + } + + @Benchmark + // Requires multiversioning for vectorization. + // With only the predicate, we will eventually deopt and compile without vectorization. + public void bench_copy_array_L_differentIndex_mixed() { + if ((iteration++) % 2 == 0) { + copy_L(bL, aL, 0, 0, aL.length); // noalias + } else { + copy_L(aL, aL, 0, 0, aL.length); // alias + } + } + + // No overlap -> expect vectoirzation. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_L_half() { + copy_L(aL, aL, 0, aL.length / 2, aL.length / 2); + } + + // Overlap, but never alias -> expect vectorization. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_L_partial_overlap() { + copy_L(aL, aL, 0, aL.length / 4, aL.length / 4 * 3); + } + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseAutoVectorizationSpeculativeAliasingChecks" + }) + public static class VectorAliasingSuperWordWithoutSpeculativeAliasingChecks extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseAutoVectorizationPredicate" + }) + public static class VectorAliasingSuperWordWithoutAutoVectorizationPredicate extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-LoopMultiversioning" + }) + public static class VectorAliasingSuperWordWithoutMultiversioning extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:AutoVectorizationOverrideProfitability=0" + }) + public static class VectorAliasingSuperWordPretendNotProfitable extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord" + }) + public static class VectorAliasingSuperWord extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:-UseSuperWord" + }) + public static class VectorAliasingNoSuperWord extends VectorAliasing {} +} From 57df267e4269b26f7450309b54c55ddee458f75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 28 Aug 2025 06:30:25 +0000 Subject: [PATCH 025/295] 8365262: [IR-Framework] Add simple way to add cross-product of flags Reviewed-by: bmaillard, epeter --- .../jtreg/compiler/lib/ir_framework/README.md | 2 +- .../lib/ir_framework/TestFramework.java | 67 +++++++ .../TestFloatConversionsVector.java | 16 +- .../tests/TestScenariosCrossProduct.java | 164 ++++++++++++++++++ 4 files changed, 237 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index 6bdae262599..2a454f2990d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -146,7 +146,7 @@ More information about IR matching can be found in the Javadocs of [IR](./IR.jav ### 2.3 Test VM Flags and Scenarios The recommended way to use the framework is by defining a single `@run driver` statement in the JTreg header which, however, does not allow the specification of additional test VM flags. Instead, the user has the possibility to provide VM flags by calling `TestFramework.runWithFlags()` or by creating a `TestFramework` builder object on which `addFlags()` can be called. -If a user wants to provide multiple flag combinations for a single test, he or she has the option to provide different scenarios. A scenario based flag will always have precedence over other user defined flags. More information about scenarios can be found in the Javadocs of [Scenario](./Scenario.java). +If a user wants to provide multiple flag combinations for a single test, he or she has the option to provide different scenarios. A scenario based flag will always have precedence over other user defined flags. More information about scenarios can be found in the Javadocs of [Scenario](./Scenario.java). If a user wants to test all combinations of multiple sets of flags, they can use `TestFramework.addCrossProductScenarios()`. ### 2.4 Compiler Controls The framework allows the use of additional compiler control annotations for helper method and classes in the same fashion as JMH does. The following annotations are supported and described in the referenced Javadocs for the annotation class: diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 8e509c66c9a..85c52ef33da 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -46,7 +46,9 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This class represents the main entry point to the test framework whose main purpose is to perform regex-based checks on @@ -333,6 +335,71 @@ public class TestFramework { return this; } + /** + * Add the cross-product (cartesian product) of sets of flags as Scenarios. Unlike when when constructing + * scenarios directly a string can contain multiple flags separated with a space. This allows grouping + * flags that have to be specified togeher. Further, an empty string in a set stands in for "no flag". + *

      + * Example: + *

      +     *     addCrossProductScenarios(Set.of("", "-Xint", "-Xbatch -XX:-TieredCompilation"),
      +     *                              Set.of("-XX:+UseNewCode", "-XX:UseNewCode2"))
      +     * 
      + * produces the following Scenarios + *
      +     *     Scenario(0, "-XX:+UseNewCode")
      +     *     Scenario(1, "-XX:+UseNewCode2")
      +     *     Scenario(2, "-Xint", "-XX:+UseNewCode")
      +     *     Scenario(3, "-Xint", "-XX:+UseNewCode2")
      +     *     Scenario(4, "-Xbatch -XX:-TieredCompilation", "-XX:+UseNewCode")
      +     *     Scenario(5, "-Xbatch -XX:-TieredCompilation", "-XX:+UseNewCode2")
      +     * 
      + * + * @param sets sets of flags to generate the cross product for. + * @return the same framework instance. + */ + @SafeVarargs + final public TestFramework addCrossProductScenarios(Set... flagSets) { + TestFormat.checkAndReport(flagSets != null && + Arrays.stream(flagSets).noneMatch(Objects::isNull) && + Arrays.stream(flagSets).flatMap(Set::stream).noneMatch(Objects::isNull), + "Flags must not be null"); + if (flagSets.length == 0) { + return this; + } + + int initIdx = 0; + if (this.scenarioIndices != null && !this.scenarioIndices.isEmpty()) { + initIdx = this.scenarioIndices.stream().max(Comparator.comparingInt(Integer::intValue)).get() + 1; + } + AtomicInteger idx = new AtomicInteger(initIdx); + + Stream> crossProduct = Arrays.stream(flagSets) + .reduce( + Stream.of(Collections.emptyList()), // Initialize Stream> acc with a Stream containing an empty list of Strings. + (Stream> acc, Set set) -> + acc.flatMap(lAcc -> // For each List> lAcc in acc... + set.stream().map(flag -> { // ...and each flag in the current set... + List newList = new ArrayList<>(lAcc); // ...create a new list containing lAcc... + newList.add(flag); // ...and append the flag. + return newList; + }) // This results in one List> for each lAcc... + ), // ...that get flattend into one big List>. + (a, b) -> Stream.concat(a, b)); // combiner; if any reduction steps are executed in parallel, just concat two streams. + + Scenario[] newScenarios = crossProduct + .map(flags -> new Scenario( // For each List flags in crossProduct create a new Scenario. + idx.getAndIncrement(), + flags.stream() // Process flags + .map(s -> Set.of(s.split("[ ]"))) // Split muliple flags in the same string into separate strings. + .flatMap(Collection::stream) // Flatten the Stream> into Stream>. + .filter(s -> !s.isEmpty()) // Remove empty string flags. + .collect(Collectors.toList()) + .toArray(new String[0]))) + .collect(Collectors.toList()).toArray(new Scenario[0]); + return addScenarios(newScenarios); + } + /** * Add test classes to boot classpath. This adds all classes found on path {@link jdk.test.lib.Utils#TEST_CLASSES} * to the boot classpath with "-Xbootclasspath/a". This is useful when trying to run tests in a privileged mode. diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java index 482dcf934c5..3ba9fe7472c 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java @@ -27,14 +27,13 @@ * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs * @requires vm.compiler2.enabled * @library /test/lib / - * @run driver compiler.vectorization.TestFloatConversionsVector nCOH_nAV - * @run driver compiler.vectorization.TestFloatConversionsVector nCOH_yAV - * @run driver compiler.vectorization.TestFloatConversionsVector yCOH_nAV - * @run driver compiler.vectorization.TestFloatConversionsVector yCOH_yAV + * @run driver compiler.vectorization.TestFloatConversionsVector */ package compiler.vectorization; +import java.util.Set; + import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -49,13 +48,8 @@ public class TestFloatConversionsVector { public static void main(String args[]) { TestFramework framework = new TestFramework(TestFloatConversionsVector.class); framework.addFlags("-XX:-TieredCompilation", "-XX:CompileThresholdScaling=0.3"); - switch (args[0]) { - case "nCOH_nAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "nCOH_yAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"); } - case "yCOH_nAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "yCOH_yAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"); } - default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } - }; + framework.addCrossProductScenarios(Set.of("-XX:-UseCompactObjectHeaders", "-XX:+UseCompactObjectHeaders"), + Set.of("-XX:-AlignVector", "-XX:+AlignVector")); framework.start(); System.out.println("PASSED"); } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java new file mode 100644 index 00000000000..496fcbddb0f --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 ir_framework.tests; + +import java.util.Set; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.shared.TestRunException; +import compiler.lib.ir_framework.shared.TestFormatException; +import jdk.test.lib.Asserts; + +/* + * @test + * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler2.enabled & vm.flagless + * @summary Test cross product scenarios with the framework. + * @library /test/lib /testlibrary_tests / + * @run driver ir_framework.tests.TestScenariosCrossProduct + */ + +public class TestScenariosCrossProduct { + static void hasNFailures(String s, int count) { + if (!s.matches("The following scenarios have failed: (#[0-9](, )?){" + count + "}. Please check stderr for more information.")) { + throw new RuntimeException("Expected " + count + " failures in \"" + s + "\""); + } + } + + public static void main(String[] args) { + // Test argument handling + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios((Set[]) null); + Asserts.fail("Should have thrown exception"); + } catch (TestFormatException e) {} + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios(Set.of("foo", "bar"), null); + Asserts.fail("Should have thrown exception"); + } catch (TestFormatException e) {} + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios(Set.of("blub"), Set.of("foo", null)); + Asserts.fail("Should have thrown exception"); + } catch (NullPointerException e) {} // Set.of prevents null elements + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios(); + } catch (TestFormatException e) { + Asserts.fail("Should not have thrown exception"); + } + + // Single set should test all flags in the set by themselves. + try { + TestFramework t1 = new TestFramework(); + t1.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=51", + "-XX:TLABRefillWasteFraction=53", + "-XX:TLABRefillWasteFraction=64")); + t1.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 3); + } + + // The cross product of a set with one element and a set with three elements is three sets. + try { + TestFramework t2 = new TestFramework(); + t2.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=53"), + Set.of("-XX:+UseNewCode", "-XX:+UseNewCode2", "-XX:+UseNewCode3")); + t2.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 3); + } + + // The cross product of two sets with two elements is four sets. + try { + TestFramework t3 = new TestFramework(); + t3.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=53", "-XX:TLABRefillWasteFraction=64"), + Set.of("-XX:+UseNewCode", "-XX:-UseNewCode")); + t3.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 4); + } + + // Test with a pair of flags. + try { + TestFramework t4 = new TestFramework(); + t4.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=50 -XX:+UseNewCode", "-XX:TLABRefillWasteFraction=40"), + Set.of("-XX:+UseNewCode2")); + t4.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 1); + } + + // Test with an empty string. All 6 scenarios fail because 64 is the default value for TLABRefillWasteFraction. + try { + TestFramework t5 = new TestFramework(); + t5.addCrossProductScenarios(Set.of("", "-XX:TLABRefillWasteFraction=51", "-XX:TLABRefillWasteFraction=53"), + Set.of("-XX:+UseNewCode", "-XX:+UseNewCode2")); + t5.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 6); + } + + try { + TestFramework t6 = new TestFramework(); + t6.addScenarios(new Scenario(0, "-XX:TLABRefillWasteFraction=50", "-XX:+UseNewCode")); // failPair + t6.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=51", "-XX:TLABRefillWasteFraction=53"), + Set.of("-XX:+UseNewCode", "-XX:+UseNewCode2")); + try { + t6.addScenarios(new Scenario(4, "-XX:+UseNewCode3")); // fails because index 4 is already used + Asserts.fail("Should have thrown exception"); + } catch (TestFormatException e) {} + t6.addScenarios(new Scenario(5, "-XX:+UseNewCode3")); // fail default + t6.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 6); + } + } + + @Test + @IR(applyIf = {"TLABRefillWasteFraction", "64"}, counts = {IRNode.CALL, "1"}) + public void failDefault() { + } + + @Test + @IR(applyIf = {"TLABRefillWasteFraction", "51"}, counts = {IRNode.CALL, "1"}) + public void fail1() { + } + + @Test + @IR(applyIf = {"TLABRefillWasteFraction", "53"}, counts = {IRNode.CALL, "1"}) + public void fail2() { + } + + @Test + @IR(applyIfAnd = {"TLABRefillWasteFraction", "50", "UseNewCode", "true"}, counts = {IRNode.CALL, "1"}) + public void failPair() { + } +} From ab1f2af4f0e9d3bea53f394413720c19fc7cae62 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 28 Aug 2025 06:57:57 +0000 Subject: [PATCH 026/295] 8366255: Remove 'package_to_module' function from imageFile.cpp Reviewed-by: rriggs, coleenp --- .../share/native/libjimage/imageFile.cpp | 84 +------------------ .../share/native/libjimage/imageFile.hpp | 21 +---- .../share/native/libjimage/jimage.cpp | 19 +---- .../share/native/libjimage/jimage.hpp | 21 +---- 4 files changed, 6 insertions(+), 139 deletions(-) diff --git a/src/java.base/share/native/libjimage/imageFile.cpp b/src/java.base/share/native/libjimage/imageFile.cpp index 4a8f35cd6fa..d97a8f95a60 100644 --- a/src/java.base/share/native/libjimage/imageFile.cpp +++ b/src/java.base/share/native/libjimage/imageFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -148,65 +148,6 @@ void ImageLocation::clear_data() { memset(_attributes, 0, sizeof(_attributes)); } -// ImageModuleData constructor maps out sub-tables for faster access. -ImageModuleData::ImageModuleData(const ImageFileReader* image_file) : - _image_file(image_file), - _endian(image_file->endian()) { -} - -// Release module data resource. -ImageModuleData::~ImageModuleData() { -} - - -// Return the module in which a package resides. Returns NULL if not found. -const char* ImageModuleData::package_to_module(const char* package_name) { - // replace all '/' by '.' - char* replaced = new char[(int) strlen(package_name) + 1]; - assert(replaced != NULL && "allocation failed"); - int i; - for (i = 0; package_name[i] != '\0'; i++) { - replaced[i] = package_name[i] == '/' ? '.' : package_name[i]; - } - replaced[i] = '\0'; - - // build path /packages/ - const char* radical = "/packages/"; - char* path = new char[(int) strlen(radical) + (int) strlen(package_name) + 1]; - assert(path != NULL && "allocation failed"); - strcpy(path, radical); - strcat(path, replaced); - delete[] replaced; - - // retrieve package location - ImageLocation location; - bool found = _image_file->find_location(path, location); - delete[] path; - if (!found) { - return NULL; - } - - // retrieve offsets to module name - int size = (int)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED); - u1* content = new u1[size]; - assert(content != NULL && "allocation failed"); - _image_file->get_resource(location, content); - u1* ptr = content; - // sequence of sizeof(8) isEmpty|offset. Use the first module that is not empty. - u4 offset = 0; - for (i = 0; i < size; i+=8) { - u4 isEmpty = _endian->get(*((u4*)ptr)); - ptr += 4; - if (!isEmpty) { - offset = _endian->get(*((u4*)ptr)); - break; - } - ptr += 4; - } - delete[] content; - return _image_file->get_strings().get(offset); -} - // Manage a table of open image files. This table allows multiple access points // to share an open image. ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) { @@ -340,8 +281,7 @@ ImageFileReader* ImageFileReader::id_to_reader(u8 id) { } // Constructor initializes to a closed state. -ImageFileReader::ImageFileReader(const char* name, bool big_endian) : - _module_data(NULL) { +ImageFileReader::ImageFileReader(const char* name, bool big_endian) { // Copy the image file name. int len = (int) strlen(name) + 1; _name = new char[len]; @@ -362,10 +302,6 @@ ImageFileReader::~ImageFileReader() { delete[] _name; _name = NULL; } - - if (_module_data != NULL) { - delete _module_data; - } } // Open image file for read access. @@ -414,11 +350,7 @@ bool ImageFileReader::open() { _location_bytes = _index_data + location_bytes_offset; // Compute address of index string table. _string_bytes = _index_data + string_bytes_offset; - - // Initialize the module data - _module_data = new ImageModuleData(this); - // Successful open (if memory allocation succeeded). - return _module_data != NULL; + return true; } // Close image file. @@ -433,11 +365,6 @@ void ImageFileReader::close() { osSupport::close(_fd); _fd = -1; } - - if (_module_data != NULL) { - delete _module_data; - _module_data = NULL; - } } // Read directly from the file. @@ -567,8 +494,3 @@ void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_dat assert(is_read && "error reading from image or short read"); } } - -// Return the ImageModuleData for this image -ImageModuleData * ImageFileReader::get_image_module_data() { - return _module_data; -} diff --git a/src/java.base/share/native/libjimage/imageFile.hpp b/src/java.base/share/native/libjimage/imageFile.hpp index 78b37a38b7f..5fb4ea3baaa 100644 --- a/src/java.base/share/native/libjimage/imageFile.hpp +++ b/src/java.base/share/native/libjimage/imageFile.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -302,20 +302,6 @@ public: } }; -// -// Manage the image module meta data. -class ImageModuleData { - const ImageFileReader* _image_file; // Source image file - Endian* _endian; // Endian handler - -public: - ImageModuleData(const ImageFileReader* image_file); - ~ImageModuleData(); - - // Return the module in which a package resides. Returns NULL if not found. - const char* package_to_module(const char* package_name); -}; - // Image file header, starting at offset 0. class ImageHeader { private: @@ -428,7 +414,6 @@ private: u4* _offsets_table; // Location offset table u1* _location_bytes; // Location attributes u1* _string_bytes; // String table - ImageModuleData *_module_data; // The ImageModuleData for this image ImageFileReader(const char* name, bool big_endian); ~ImageFileReader(); @@ -577,9 +562,5 @@ public: // Return the resource for the supplied path. void get_resource(ImageLocation& location, u1* uncompressed_data) const; - - // Return the ImageModuleData for this image - ImageModuleData * get_image_module_data(); - }; #endif // LIBJIMAGE_IMAGEFILE_HPP diff --git a/src/java.base/share/native/libjimage/jimage.cpp b/src/java.base/share/native/libjimage/jimage.cpp index 7b5eacd1fcb..10e85eb2520 100644 --- a/src/java.base/share/native/libjimage/jimage.cpp +++ b/src/java.base/share/native/libjimage/jimage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -86,23 +86,6 @@ JIMAGE_Close(JImageFile* image) { ImageFileReader::close((ImageFileReader*) image); } -/* - * JImagePackageToModule - Given an open image file (see JImageOpen) and the name - * of a package, return the name of module where the package resides. If the - * package does not exist in the image file, the function returns NULL. - * The resulting string does/should not have to be released. All strings are - * utf-8, zero byte terminated. - * - * Ex. - * const char* package = (*JImagePackageToModule)(image, "java/lang"); - * tty->print_cr(package); - * -> java.base - */ -extern "C" JNIEXPORT const char* -JIMAGE_PackageToModule(JImageFile* image, const char* package_name) { - return ((ImageFileReader*) image)->get_image_module_data()->package_to_module(package_name); -} - /* * JImageFindResource - Given an open image file (see JImageOpen), a module * name, a version string and the name of a class/resource, return location diff --git a/src/java.base/share/native/libjimage/jimage.hpp b/src/java.base/share/native/libjimage/jimage.hpp index 31e47bd67fe..a514e737b49 100644 --- a/src/java.base/share/native/libjimage/jimage.hpp +++ b/src/java.base/share/native/libjimage/jimage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -93,25 +93,6 @@ JIMAGE_Close(JImageFile* jimage); typedef void (*JImageClose_t)(JImageFile* jimage); -/* - * JImagePackageToModule - Given an open image file (see JImageOpen) and the name - * of a package, return the name of module where the package resides. If the - * package does not exist in the image file, the function returns NULL. - * The resulting string does/should not have to be released. All strings are - * utf-8, zero byte terminated. - * - * Ex. - * const char* package = (*JImagePackageToModule)(image, "java/lang"); - * tty->print_cr(package); - * -> java.base - */ - -extern "C" JNIEXPORT const char * -JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name); - -typedef const char* (*JImagePackageToModule_t)(JImageFile* jimage, const char* package_name); - - /* * JImageFindResource - Given an open image file (see JImageOpen), a module * name, a version string and the name of a class/resource, return location From d06c66f7f5a6d3c649c0a10ad735f0cc7c673b2a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 28 Aug 2025 09:21:26 +0000 Subject: [PATCH 027/295] 8365055: G1: Merge Heap Roots phase incorrectly clears young gen remembered set every time Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 6 ++++++ src/hotspot/share/gc/g1/g1CollectionSet.cpp | 5 ++++- src/hotspot/share/gc/g1/g1Policy.hpp | 4 ++-- src/hotspot/share/gc/g1/g1RemSet.cpp | 10 ---------- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 1 - 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 65d863f43ee..e9834736707 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2441,6 +2441,12 @@ void G1CollectedHeap::update_perf_counter_cpu_time() { } void G1CollectedHeap::start_new_collection_set() { + // Clear current young cset group to allow adding. + // It is fine to clear it this late - evacuation does not add any remembered sets + // by itself, but only marks cards. + // The regions had their association to this group already removed earlier. + young_regions_cset_group()->clear(); + collection_set()->start_incremental_building(); clear_region_attr(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 72033a1ce9a..1e836e3efa2 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -323,7 +323,10 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi verify_young_cset_indices(); - double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, _g1h->young_regions_cardset()->occupied()); + size_t num_young_cards = _g1h->young_regions_cardset()->occupied(); + _policy->record_card_rs_length(num_young_cards); + + double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, num_young_cards); // Base time already includes the whole remembered set related time, so do not add that here // again. double predicted_eden_time = _policy->predict_young_region_other_time_ms(eden_region_length) + diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 3571945d587..d449439df8c 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -129,8 +129,8 @@ public: hr->install_surv_rate_group(_survivor_surv_rate_group); } - void record_card_rs_length(size_t card_rs_length) { - _card_rs_length = card_rs_length; + void record_card_rs_length(size_t num_cards) { + _card_rs_length = num_cards; } double cur_pause_start_sec() const { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 6b7532a99aa..25790a00bd9 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1440,16 +1440,6 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) { workers->run_task(&cl, num_workers); } - { - size_t young_rs_length = g1h->young_regions_cardset()->occupied(); - // We only use young_rs_length statistics to estimate young regions length. - g1h->policy()->record_card_rs_length(young_rs_length); - - // Clear current young only collection set. Survivor regions will be added - // to the set during evacuation. - g1h->young_regions_cset_group()->clear(); - } - print_merge_heap_roots_stats(); if (initial_evacuation) { diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 29eab44d4a8..04197495033 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -519,7 +519,6 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats(); sampled_card_set_stats.add(_g1h->young_regions_card_set_memory_stats()); _g1h->set_young_gen_card_set_stats(sampled_card_set_stats); - _g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates()); phase_times()->record_register_regions(task_time.seconds() * 1000.0); From 7469a274bb70b2cdc8a47e62cc989f86766c605a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 28 Aug 2025 09:21:52 +0000 Subject: [PATCH 028/295] 8365939: [Redo] G1: Move collection set related full gc reset code into abandon_collection_set() method Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 ++ src/hotspot/share/gc/g1/g1FullCollector.cpp | 5 ----- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 4 +++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e9834736707..618e9b055fe 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2803,6 +2803,8 @@ void G1CollectedHeap::abandon_collection_set() { collection_set()->stop_incremental_building(); collection_set()->abandon_all_candidates(); + + young_regions_cset_group()->clear(true /* uninstall_group_cardset */); } bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 70cded3220a..33202658c46 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -244,11 +244,6 @@ void G1FullCollector::complete_collection(size_t allocation_word_size) { _heap->resize_all_tlabs(); - // We clear remembered sets for young regions this late in the full GC because - // G1HeapVerifier expects the remembered sets for all young regions to be complete - // throughout most of the collection process (e.g. G1FullCollector::verify_after_marking). - _heap->young_regions_cset_group()->clear(); - _heap->policy()->record_full_collection_end(); _heap->gc_epilogue(true); diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 4227a90960b..c5af7e34dd9 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -235,6 +235,8 @@ private: VerifyOption _vo; bool _failures; + bool is_in_full_gc() const { return G1CollectedHeap::heap()->collector_state()->in_full_gc(); } + public: VerifyRegionClosure(VerifyOption vo) : _vo(vo), @@ -246,7 +248,7 @@ public: bool do_heap_region(G1HeapRegion* r) { guarantee(!r->has_index_in_opt_cset(), "Region %u still has opt collection set index %u", r->hrm_index(), r->index_in_opt_cset()); - guarantee(!r->is_young() || r->rem_set()->is_complete(), "Remembered set for Young region %u must be complete, is %s", r->hrm_index(), r->rem_set()->get_state_str()); + guarantee(is_in_full_gc() || !r->is_young() || r->rem_set()->is_complete(), "Remembered set for Young region %u must be complete outside full gc, is %s", r->hrm_index(), r->rem_set()->get_state_str()); // Humongous and old regions regions might be of any state, so can't check here. guarantee(!r->is_free() || !r->rem_set()->is_tracked(), "Remembered set for free region %u must be untracked, is %s", r->hrm_index(), r->rem_set()->get_state_str()); From a5a234005414a58f66c7e646a8f9b0042e9f9eec Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 28 Aug 2025 09:28:58 +0000 Subject: [PATCH 029/295] 8365053: Refresh hotspot precompiled.hpp with headers based on current frequency Reviewed-by: shade, ihse, erikj, qamai --- make/scripts/update_pch.sh | 101 ++++++++++++++++++ src/hotspot/share/precompiled/precompiled.hpp | 66 ++++-------- .../jtreg/sources/TestIncludesAreSorted.java | 1 + 3 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 make/scripts/update_pch.sh diff --git a/make/scripts/update_pch.sh b/make/scripts/update_pch.sh new file mode 100644 index 00000000000..534525353fd --- /dev/null +++ b/make/scripts/update_pch.sh @@ -0,0 +1,101 @@ +#!/bin/sh +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# The output of this script may require some degree of human curation: +# - Redundant headers, e.g. both x.hpp, x.inline.hpp are included; +# - Headers relative to a non-default feature should be protected by an +# appropriate 'if' clause to make sure all variants can build without +# errors. + +# Time threshold for header compilation, if the time exceeds the +# threshold the header will be precompiled. +if [ -z "$MIN_MS" ]; then + MIN_MS=100000 +fi + +if [ -z "$CLEAN" ]; then + CLEAN=true +elif [ "$CLEAN" != "true" ] && [ "$CLEAN" != "false" ]; then + echo "Expected either 'true' or 'false' for CLEAN" +fi + +# CBA_PATH should point to a valid ClangBuildAnalyzer executable. +# Build steps: +# git clone --depth 1 git@github.com:aras-p/ClangBuildAnalyzer.git +# cd ClangBuildAnalyzer +# make -f projects/make/Makefile +if [ -z "$CBA_PATH" ]; then + CBA_PATH="./ClangBuildAnalyzer/build/ClangBuildAnalyzer" +fi + +set -eux + +PRECOMPILED_HPP="src/hotspot/share/precompiled/precompiled.hpp" +CBA_CONFIG="ClangBuildAnalyzer.ini" +TIMESTAMP="$(date +%Y%m%d-%H%M)" +RUN_NAME="pch_update_$TIMESTAMP" +CBA_OUTPUT="cba_out_$TIMESTAMP" + +if [ "$CLEAN" = "true" ]; then + trap 'rm -rf "build/'"$RUN_NAME"'" "$CBA_OUTPUT" "$CBA_CONFIG"' EXIT +fi + +sh configure --with-toolchain-type=clang \ + --with-conf-name="$RUN_NAME" \ + --disable-precompiled-headers \ + --with-extra-cxxflags="-ftime-trace" \ + --with-extra-cflags="-ftime-trace" + +make clean CONF_NAME="$RUN_NAME" +make hotspot CONF_NAME="$RUN_NAME" +"$CBA_PATH" --all "./build/$RUN_NAME/hotspot/variant-server/libjvm/objs" \ + "$CBA_OUTPUT" + +# Preserve license and comments on top +cat "$PRECOMPILED_HPP" | awk '/^#include/ {exit} {print}' > "$PRECOMPILED_HPP.tmp" + +if [ ! -f "$CBA_CONFIG" ]; then +cat < "$CBA_CONFIG" +[counts] +header=100 +headerChain=0 +template=0 +function=0 +fileCodegen=0 +fileParse=0 + +[misc] +onlyRootHeaders=true +EOF +fi + +"$CBA_PATH" --analyze "$CBA_OUTPUT" | \ + grep " ms: " | \ + # Keep the headers more expensive than ${1}ms + awk -v x="$MIN_MS" '$1 < x { exit } { print $3 }' | \ + # Filter away non-hotspot headers + grep hotspot/share | \ + awk -F "hotspot/share/" '{ printf "#include \"%s\"\n", $2 }' \ + >> "$PRECOMPILED_HPP.tmp" +mv "$PRECOMPILED_HPP.tmp" "$PRECOMPILED_HPP" + +java test/hotspot/jtreg/sources/SortIncludes.java --update "$PRECOMPILED_HPP" diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index a5f42a0fe86..670bd55e423 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -25,53 +25,27 @@ // Precompiled headers are turned off if the user passes // --disable-precompiled-headers to configure. -// These header files are included in at least 130 C++ files, as of -// measurements made in November 2018. This list excludes files named -// *.inline.hpp, since including them decreased build performance. +// These header files are selected using the output of Clang +// '-ftime-trace' as a measure of how much time we spend +// compiling them. -#include "classfile/classLoaderData.hpp" -#include "classfile/javaClasses.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc/shared/collectedHeap.hpp" -#include "gc/shared/gcCause.hpp" -#include "logging/log.hpp" +#include "classfile/javaClasses.inline.hpp" #include "memory/allocation.hpp" -#include "memory/iterator.hpp" -#include "memory/memRegion.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "nmt/memTracker.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/klass.hpp" -#include "oops/method.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/objArrayOop.hpp" -#include "oops/oop.hpp" -#include "oops/oopsHierarchy.hpp" -#include "runtime/atomic.hpp" -#include "runtime/globals.hpp" -#include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/mutex.hpp" -#include "runtime/orderAccess.hpp" -#include "runtime/os.hpp" -#include "runtime/timer.hpp" -#include "utilities/align.hpp" -#include "utilities/bitMap.hpp" -#include "utilities/copy.hpp" -#include "utilities/debug.hpp" -#include "utilities/exceptions.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/growableArray.hpp" -#include "utilities/macros.hpp" -#include "utilities/ostream.hpp" -#include "utilities/ticks.hpp" - -#ifdef TARGET_COMPILER_visCPP -// For Visual Studio, including the *.inline.hpp files actually -// increased performance. -#include "memory/allocation.inline.hpp" +#include "memory/iterator.inline.hpp" #include "oops/access.inline.hpp" +#include "oops/instanceStackChunkKlass.inline.hpp" +#include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/handles.inline.hpp" -#endif // TARGET_COMPILER_visCPP +#include "oops/oopHandle.inline.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/javaThread.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#if INCLUDE_SHENANDOAHGC +#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#endif +#if INCLUDE_ZGC +#include "gc/z/zBarrier.inline.hpp" +#include "gc/z/zGeneration.inline.hpp" +#include "gc/z/zHeap.inline.hpp" +#endif diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 74da9626bae..f7b70079673 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -59,6 +59,7 @@ public class TestIncludesAreSorted { "share/metaprogramming", "share/oops", "share/opto", + "share/precompiled", "share/services", "share/utilities" }; From b0f5b23ed2a2f3b9d97754ced5382bb3fb3e8f40 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 28 Aug 2025 11:37:48 +0000 Subject: [PATCH 030/295] 8366145: G1: Help diagnose ubsan division by zero in computing pause time ratios (g1Analytics.cpp) Reviewed-by: tschatzl, kbarrett --- src/hotspot/share/gc/g1/g1Analytics.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/g1/g1Analytics.cpp b/src/hotspot/share/gc/g1/g1Analytics.cpp index 686554ffaa4..8fe0b25ceb7 100644 --- a/src/hotspot/share/gc/g1/g1Analytics.cpp +++ b/src/hotspot/share/gc/g1/g1Analytics.cpp @@ -181,6 +181,7 @@ void G1Analytics::update_gc_time_ratios(double end_time_sec, double pause_time_m double short_interval_ms = (end_time_sec - most_recent_gc_end_time_sec()) * 1000.0; + assert(short_interval_ms != 0.0, "short_interval_ms should not be zero, calculated from %f and %f", end_time_sec, most_recent_gc_end_time_sec()); _short_term_gc_time_ratio = gc_time_ms / short_interval_ms; _short_term_gc_time_ratio = clamp(_short_term_gc_time_ratio, 0.0, 1.0); From 5c78c7cd83d2d1ca1ba19151d6be40f5bd6077c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 28 Aug 2025 12:15:03 +0000 Subject: [PATCH 031/295] 8366341: [BACKOUT] JDK-8365256: RelocIterator should use indexes instead of pointers Reviewed-by: ayang --- src/hotspot/share/code/codeBlob.cpp | 30 +++++++++------ src/hotspot/share/code/nmethod.cpp | 20 +++++----- src/hotspot/share/code/relocInfo.cpp | 55 +++++++++++++--------------- src/hotspot/share/code/relocInfo.hpp | 28 +++++++------- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 6d34204d074..9ec5478a071 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -128,7 +128,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size int mutable_data_size) : _oop_maps(nullptr), // will be set by set_oop_maps() call _name(name), - _mutable_data(nullptr), + _mutable_data(header_begin() + size), // default value is blob_end() _size(size), _relocation_size(align_up(cb->total_relocation_size(), oopSize)), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -158,8 +158,10 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } + } else { + // We need unique and valid not null address + assert(_mutable_data == blob_end(), "sanity"); } - assert(_mutable_data != nullptr || _mutable_data_size == 0, "No mutable data => mutable data size is 0"); set_oop_maps(oop_maps); } @@ -168,7 +170,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size) : _oop_maps(nullptr), _name(name), - _mutable_data(nullptr), + _mutable_data(header_begin() + size), // default value is blob_end() _size(size), _relocation_size(0), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -182,9 +184,9 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade _kind(kind), _caller_must_gc_arguments(false) { - assert(_mutable_data == nullptr && _mutable_data_size == 0, "invariant"); assert(is_aligned(size, oopSize), "unaligned size"); assert(is_aligned(header_size, oopSize), "unaligned size"); + assert(_mutable_data == blob_end(), "sanity"); } void CodeBlob::restore_mutable_data(address reloc_data) { @@ -195,7 +197,7 @@ void CodeBlob::restore_mutable_data(address reloc_data) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } } else { - _mutable_data = nullptr; + _mutable_data = blob_end(); // default value } if (_relocation_size > 0) { assert(_mutable_data_size > 0, "relocation is part of mutable data section"); @@ -204,13 +206,17 @@ void CodeBlob::restore_mutable_data(address reloc_data) { } void CodeBlob::purge() { - os::free(_mutable_data); - _mutable_data = nullptr; - _mutable_data_size = 0; - delete _oop_maps; - _oop_maps = nullptr; - _relocation_size = 0; - + assert(_mutable_data != nullptr, "should never be null"); + if (_mutable_data != blob_end()) { + os::free(_mutable_data); + _mutable_data = blob_end(); // Valid not null address + _mutable_data_size = 0; + _relocation_size = 0; + } + if (_oop_maps != nullptr) { + delete _oop_maps; + _oop_maps = nullptr; + } NOT_PRODUCT(_asm_remarks.clear()); NOT_PRODUCT(_dbg_strings.clear()); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a45ca141455..b8b3a70bf58 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1327,8 +1327,8 @@ nmethod::nmethod( "wrong mutable data size: %d != %d + %d", _mutable_data_size, _relocation_size, metadata_size); - // native wrapper does not have read-only data - _immutable_data = nullptr; + // native wrapper does not have read-only data but we need unique not null address + _immutable_data = blob_end(); _immutable_data_size = 0; _nul_chk_table_offset = 0; _handler_table_offset = 0; @@ -1510,7 +1510,8 @@ nmethod::nmethod( assert(immutable_data != nullptr, "required"); _immutable_data = immutable_data; } else { - _immutable_data = nullptr; + // We need unique not null address + _immutable_data = blob_end(); } CHECKED_CAST(_nul_chk_table_offset, uint16_t, (align_up((int)dependencies->size_in_bytes(), oopSize))); CHECKED_CAST(_handler_table_offset, uint16_t, (_nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize))); @@ -2146,14 +2147,15 @@ void nmethod::purge(bool unregister_nmethod) { delete ec; ec = next; } - - delete _pc_desc_container; + if (_pc_desc_container != nullptr) { + delete _pc_desc_container; + } delete[] _compiled_ic_data; - os::free(_immutable_data); - _immutable_data = nullptr; - _immutable_data_size = 0; - + if (_immutable_data != blob_end()) { + os::free(_immutable_data); + _immutable_data = blob_end(); // Valid not null address + } if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index fb24844000d..8fc22596d01 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -116,6 +116,9 @@ void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, re // ---------------------------------------------------------------------------------------------------- // Implementation of RelocIterator +// A static dummy to serve as a safe pointer when there is no relocation info. +static relocInfo dummy_relocInfo = relocInfo(relocInfo::none, 0); + void RelocIterator::initialize(nmethod* nm, address begin, address limit) { initialize_misc(); @@ -127,9 +130,14 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { guarantee(nm != nullptr, "must be able to deduce nmethod from other arguments"); _code = nm; - _base = nm->relocation_begin(); - _current = -1; - _len = nm->relocation_end() - _base; + if (nm->relocation_size() == 0) { + _current = &dummy_relocInfo - 1; + _end = &dummy_relocInfo; + } else { + assert(((nm->relocation_begin() != nullptr) && (nm->relocation_end() != nullptr)), "valid start and end pointer"); + _current = nm->relocation_begin() - 1; + _end = nm->relocation_end(); + } _addr = nm->content_begin(); // Initialize code sections. @@ -148,21 +156,11 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { } -RelocIterator::RelocIterator(relocInfo& ri) { - initialize_misc(); - _base = &ri; - _len = 1; - _current = -1; - _limit = nullptr; - _addr = 0; -} - RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { initialize_misc(); assert(((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr)), "valid start and end pointer"); - _base = cs->locs_start(); - _len = cs->locs_end() - _base; - _current = -1; + _current = cs->locs_start() - 1; + _end = cs->locs_end(); _addr = cs->start(); _code = nullptr; // Not cb->blob(); @@ -188,9 +186,8 @@ RelocIterator::RelocIterator(CodeBlob* cb) { } else { _code = nullptr; } - _base = cb->relocation_begin(); - _len = cb->relocation_end() - _base; - _current = -1; + _current = cb->relocation_begin() - 1; + _end = cb->relocation_end(); _addr = cb->content_begin(); _section_start[CodeBuffer::SECT_CONSTS] = cb->content_begin(); @@ -219,7 +216,7 @@ void RelocIterator::set_limits(address begin, address limit) { // the limit affects this next stuff: if (begin != nullptr) { - int backup; + relocInfo* backup; address backup_addr; while (true) { backup = _current; @@ -241,12 +238,12 @@ void RelocIterator::set_limits(address begin, address limit) { // very efficiently (a single extra halfword). Larger chunks of // relocation data need a halfword header to hold their size. void RelocIterator::advance_over_prefix() { - if (current()->is_datalen()) { - _data = (short*) current()->data(); - _datalen = current()->datalen(); + if (_current->is_datalen()) { + _data = (short*) _current->data(); + _datalen = _current->datalen(); _current += _datalen + 1; // skip the embedded data & header } else { - _databuf = current()->immediate(); + _databuf = _current->immediate(); _data = &_databuf; _datalen = 1; _current++; // skip the header @@ -353,9 +350,9 @@ void Relocation::const_verify_data_value(address x) { RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; - relocInfo ri(rtype, 0); - RelocIterator itr(ri); - itr.next(); + relocInfo ri = relocInfo(rtype, 0); + RelocIterator itr; + itr.set_current(ri); itr.reloc(); return itr._rh; } @@ -842,7 +839,7 @@ void RelocIterator::print_current_on(outputStream* st) { return; } st->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - p2i(current()), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), current()->addr_offset()); + p2i(_current), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); if (current()->format() != 0) st->print(" format=%d", current()->format()); if (datalen() == 1) { @@ -993,7 +990,7 @@ void RelocIterator::print_current_on(outputStream* st) { void RelocIterator::print_on(outputStream* st) { RelocIterator save_this = (*this); - relocInfo* scan = current_no_check(); + relocInfo* scan = _current; if (!has_current()) scan += 1; // nothing to scan here! bool skip_next = has_current(); @@ -1003,7 +1000,7 @@ void RelocIterator::print_on(outputStream* st) { skip_next = false; st->print(" @" INTPTR_FORMAT ": ", p2i(scan)); - relocInfo* newscan = current_no_check()+1; + relocInfo* newscan = _current+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { st->print("%04x", *(short*)scan & 0xFFFF); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 58dbf61abbe..714a964b28d 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -562,13 +562,12 @@ class RelocIterator : public StackObj { private: address _limit; // stop producing relocations after this _addr - relocInfo* _base; // base pointer into relocInfo array - int _current; // current index - int _len; // length + relocInfo* _current; // the current relocation information + relocInfo* _end; // end marker; we're done iterating when _current == _end nmethod* _code; // compiled method containing _addr address _addr; // instruction to which the relocation applies - short* _data; // pointer to the relocation's data short _databuf; // spare buffer for compressed data + short* _data; // pointer to the relocation's data short _datalen; // number of halfwords in _data // Base addresses needed to compute targets of section_word_type relocs. @@ -579,14 +578,15 @@ class RelocIterator : public StackObj { _datalen = !b ? -1 : 0; DEBUG_ONLY(_data = nullptr); } + void set_current(relocInfo& ri) { + _current = &ri; + set_has_current(true); + } RelocationHolder _rh; // where the current relocation is allocated - relocInfo* current_no_check() const { return &_base[_current]; } - relocInfo* current() const { - assert(has_current(), "must have current"); - return current_no_check(); - } + relocInfo* current() const { assert(has_current(), "must have current"); + return _current; } void set_limits(address begin, address limit); @@ -597,7 +597,6 @@ class RelocIterator : public StackObj { void initialize(nmethod* nm, address begin, address limit); RelocIterator() { initialize_misc(); } - RelocIterator(relocInfo& ri); public: // constructor @@ -608,24 +607,25 @@ class RelocIterator : public StackObj { // get next reloc info, return !eos bool next() { _current++; - assert(_current <= _len, "must not overrun relocInfo"); - if (_current == _len) { + assert(_current <= _end, "must not overrun relocInfo"); + if (_current == _end) { set_has_current(false); return false; } set_has_current(true); - if (current()->is_prefix()) { + if (_current->is_prefix()) { advance_over_prefix(); assert(!current()->is_prefix(), "only one prefix at a time"); } - _addr += current()->addr_offset(); + _addr += _current->addr_offset(); if (_limit != nullptr && _addr >= _limit) { set_has_current(false); return false; } + return true; } From 8f864fd5637762153f26af5121cabdf21e1ad798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 28 Aug 2025 12:48:29 +0000 Subject: [PATCH 032/295] 8366222: TestCompileTaskTimeout causes asserts after JDK-8365909 Reviewed-by: chagedorn, thartmann --- .../jtreg/compiler/arguments/TestCompileTaskTimeout.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java index 141522744f4..4204f7be92e 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -49,7 +49,7 @@ public class TestCompileTaskTimeout { .shouldHaveExitValue(134) .shouldContain("timed out after"); - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=2000", "--version") .shouldHaveExitValue(0); } -} \ No newline at end of file +} From 79d8a34a92350680848052717c8a1d2a4c4331aa Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 28 Aug 2025 13:09:46 +0000 Subject: [PATCH 033/295] 8365708: Add missing @Override annotations to WindowsMenuItemUIAccessor Reviewed-by: serb, kizune --- .../sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java | 1 + .../com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java | 3 ++- .../classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java | 1 + .../java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index 02054575d77..f28ae2a9326 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -52,6 +52,7 @@ public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { return menuItem; } + @Override public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index aa90b2f35b3..a9b09085ad1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -69,13 +69,14 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { private PropertyChangeListener changeListener; final WindowsMenuItemUIAccessor accessor = - new WindowsMenuItemUIAccessor() { + new WindowsMenuItemUIAccessor() { @Override public JMenuItem getMenuItem() { return menuItem; } + @Override public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 1476c6fc152..a20b8eba98a 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -62,6 +62,7 @@ public final class WindowsMenuUI extends BasicMenuUI { return menuItem; } + @Override public State getState(JMenuItem menu) { State state = menu.isEnabled() ? State.NORMAL : State.DISABLED; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index 628a4be1637..06ef5db23a1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -52,6 +52,7 @@ public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItem return menuItem; } + @Override public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } From 22ae137400c711a4a991153b04b360a0df57bf0b Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 28 Aug 2025 13:11:20 +0000 Subject: [PATCH 034/295] 8365711: Declare menuBarHeight and hotTrackingOn private Reviewed-by: serb, prr, kizune --- .../com/sun/java/swing/plaf/windows/WindowsMenuUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index a20b8eba98a..754b394d4ac 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -51,8 +51,8 @@ import com.sun.java.swing.plaf.windows.TMSchema.State; * Windows rendition of the component. */ public final class WindowsMenuUI extends BasicMenuUI { - protected Integer menuBarHeight; - protected boolean hotTrackingOn; + private Integer menuBarHeight; + private boolean hotTrackingOn; final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { From afa8e79ba1a76066cf969cb3b5f76ea804780872 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 28 Aug 2025 13:13:10 +0000 Subject: [PATCH 035/295] 8365615: Improve JMenuBar/RightLeftOrientation.java Reviewed-by: prr, psadhukhan --- .../swing/JMenuBar/RightLeftOrientation.java | 93 ++++++++++--------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java index 80779c9ce1d..8308034d060 100644 --- a/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java +++ b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,75 +20,76 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 4211731 4214512 * @summary * This test checks if menu bars lay out correctly when their - * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is - * manual. The tester is asked to compare left-to-right and - * right-to-left menu bars and judge whether they are mirror images of each - * other. + * ComponentOrientation property is set to RIGHT_TO_LEFT. + * The tester is asked to compare left-to-right and + * right-to-left menu bars and decide whether they are mirror + * images of each other. * @library /test/jdk/java/awt/regtesthelpers * @build PassFailJFrame * @run main/manual RightLeftOrientation */ import java.awt.ComponentOrientation; -import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.List; + import javax.swing.ButtonGroup; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; -public class RightLeftOrientation { +public final class RightLeftOrientation { - static JFrame ltrFrame; - static JFrame rtlFrame; + private static List frames; private static final String INSTRUCTIONS = """ - This test checks menu bars for correct Right-To-Left Component Orientation. + This test checks menu bars for correct Right-To-Left component orientation. - You should see two frames, each containing a menu bar. - - One frame will be labelled "Left To Right" and will contain + You should see two frames, each contains a menu bar. + One frame is labelled "Left To Right" and contains a menu bar with menus starting on its left side. - The other frame will be labelled "Right To Left" and will - contain a menu bar with menus starting on its right side. + The other frame is labelled "Right To Left" and + contains a menu bar with menus starting on its right side. - The test will also contain radio buttons that can be used to set - the look and feel of the menu bars. - For each look and feel, you should compare the two menu - bars and make sure they are mirror images of each other. """; + The test also displays a frame with radio buttons + to change the look and feel of the menu bars. + For each look and feel, compare the two menu bars + in LTR and RTL orientation and make sure they are mirror + images of each other."""; public static void main(String[] args) throws Exception { PassFailJFrame.builder() - .title("RTL test Instructions") + .title("Menu Bar RTL Instructions") .instructions(INSTRUCTIONS) - .rows((int) INSTRUCTIONS.lines().count() + 2) .columns(30) .testUI(RightLeftOrientation::createTestUI) + .positionTestUIRightColumn() .build() .awaitAndCheck(); } - private static JFrame createTestUI() { - JFrame frame = new JFrame("RightLeftOrientation"); + private static JFrame createPlafChangerFrame() { + JFrame frame = new JFrame("Change Look and Feel"); JPanel panel = new JPanel(); ButtonGroup group = new ButtonGroup(); - JRadioButton rb; ActionListener plafChanger = new PlafChanger(); UIManager.LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < lafInfos.length; i++) { - rb = new JRadioButton(lafInfos[i].getName()); + JRadioButton rb = new JRadioButton(lafInfos[i].getName()); rb.setActionCommand(lafInfos[i].getClassName()); rb.addActionListener(plafChanger); group.add(rb); @@ -99,33 +100,39 @@ public class RightLeftOrientation { } frame.add(panel); - - ltrFrame = new JFrame("Left To Right"); - ltrFrame.setJMenuBar(createMenuBar(ComponentOrientation.LEFT_TO_RIGHT)); - ltrFrame.setSize(400, 100); - ltrFrame.setLocation(new Point(10, 10)); - ltrFrame.setVisible(true); - - rtlFrame = new JFrame("Right To Left"); - rtlFrame.setJMenuBar(createMenuBar(ComponentOrientation.RIGHT_TO_LEFT)); - rtlFrame.setSize(400, 100); - rtlFrame.setLocation(new Point(10, 120)); - rtlFrame.setVisible(true); frame.pack(); return frame; } - static class PlafChanger implements ActionListener { + private static List createTestUI() { + JFrame plafFrame = createPlafChangerFrame(); + + JFrame ltrFrame = new JFrame("Left To Right"); + ltrFrame.setJMenuBar(createMenuBar(ComponentOrientation.LEFT_TO_RIGHT)); + ltrFrame.setSize(400, 100); + + JFrame rtlFrame = new JFrame("Right To Left"); + rtlFrame.setJMenuBar(createMenuBar(ComponentOrientation.RIGHT_TO_LEFT)); + rtlFrame.setSize(400, 100); + + return (frames = List.of(plafFrame, ltrFrame, rtlFrame)); + } + + private static final class PlafChanger implements ActionListener { + @Override public void actionPerformed(ActionEvent e) { String lnfName = e.getActionCommand(); try { UIManager.setLookAndFeel(lnfName); - SwingUtilities.updateComponentTreeUI(ltrFrame); - SwingUtilities.updateComponentTreeUI(rtlFrame); - } - catch (Exception exc) { - System.err.println("Could not load LookAndFeel: " + lnfName); + frames.forEach(SwingUtilities::updateComponentTreeUI); + } catch (Exception exc) { + String message = "Could not set Look and Feel to " + lnfName; + System.err.println(message); + JOptionPane.showMessageDialog(frames.get(0), + message, + "Look and Feel Error", + JOptionPane.ERROR_MESSAGE); } } From 8051aaf0685f7bb23bf3e23d32ad45b0bffbce7b Mon Sep 17 00:00:00 2001 From: Rui Li Date: Thu, 28 Aug 2025 13:54:03 +0000 Subject: [PATCH 036/295] 8342640: GenShen: Silently ignoring ShenandoahGCHeuristics considered poor user-experience Reviewed-by: ysr, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index df2cd18042f..1ff001c5abd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -194,6 +194,13 @@ void ShenandoahArguments::initialize() { err_msg("GCCardSizeInBytes ( %u ) must be >= %u\n", GCCardSizeInBytes, (unsigned int) ShenandoahMinCardSizeInBytes)); } + // Gen shen does not support any ShenandoahGCHeuristics value except for the default "adaptive" + if ((strcmp(ShenandoahGCMode, "generational") == 0) + && strcmp(ShenandoahGCHeuristics, "adaptive") != 0) { + log_warning(gc)("Ignoring -XX:ShenandoahGCHeuristics input: %s, because generational shenandoah only" + " supports adaptive heuristics", ShenandoahGCHeuristics); + } + FullGCForwarding::initialize_flags(MaxHeapSize); } From 993babb326f937dc1630a5a8fa5e469a64c51206 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 28 Aug 2025 13:54:21 +0000 Subject: [PATCH 037/295] 8365863: /test/jdk/sun/security/pkcs11/Cipher tests skip without SkippedException Reviewed-by: weijun, djelinski --- .../security/pkcs11/Cipher/ReinitCipher.java | 7 +- .../security/pkcs11/Cipher/Test4512704.java | 21 ++--- .../pkcs11/Cipher/TestCICOWithGCM.java | 27 ++++--- .../pkcs11/Cipher/TestCICOWithGCMAndAAD.java | 10 +-- .../pkcs11/Cipher/TestChaChaPoly.java | 7 +- .../pkcs11/Cipher/TestChaChaPolyKAT.java | 16 ++-- .../pkcs11/Cipher/TestChaChaPolyNoReuse.java | 15 ++-- .../Cipher/TestChaChaPolyOutputSize.java | 9 +-- .../pkcs11/Cipher/TestCipherMode.java | 37 ++++++--- .../pkcs11/Cipher/TestGCMKeyAndIvCheck.java | 27 ++++--- .../security/pkcs11/Cipher/TestKATForGCM.java | 9 ++- .../security/pkcs11/Cipher/TestRSACipher.java | 6 +- .../pkcs11/Cipher/TestRSACipherWrap.java | 6 +- .../pkcs11/Cipher/TestRawRSACipher.java | 6 +- .../pkcs11/Cipher/TestSymmCiphers.java | 78 +++++++++---------- .../pkcs11/Cipher/TestSymmCiphersNoPad.java | 62 +++++++-------- 16 files changed, 187 insertions(+), 156 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java b/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java index fe93dff5050..c54889fbdc4 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @run main/othervm ReinitCipher */ +import jtreg.SkippedException; + import java.security.Provider; import java.util.Random; import javax.crypto.Cipher; @@ -46,8 +48,7 @@ public class ReinitCipher extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("Cipher", "ARCFOUR") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Algorithm ARCFOUR is not supported by provider, skipping"); } Random random = new Random(); byte[] data1 = new byte[10 * 1024]; diff --git a/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java b/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java index ddca64ecb69..7aafa4fd70f 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java +++ b/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +29,16 @@ * @run main Test4512704 * @summary Verify that AES cipher can generate default IV in encrypt mode */ -import java.io.PrintStream; -import java.security.*; -import java.security.spec.*; -import java.util.Random; +import jtreg.SkippedException; -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import java.security.Provider; +import java.security.spec.AlgorithmParameterSpec; public class Test4512704 extends PKCS11Test { @@ -48,9 +50,8 @@ public class Test4512704 extends PKCS11Test { transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java index 06c1e84392c..f6b6157cefa 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 +31,21 @@ * @key randomness */ -import java.security.*; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.math.*; -import java.io.*; +import jtreg.SkippedException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.util.Arrays; +import java.util.Random; -import java.util.*; public class TestCICOWithGCM extends PKCS11Test { public static void main(String[] args) throws Exception { @@ -55,9 +63,8 @@ public class TestCICOWithGCM extends PKCS11Test { String transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java index be2b1d18c8f..13ab8541351 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test CipherInputStream/OutputStream with AES GCM mode with AAD. * @key randomness */ +import jtreg.SkippedException; + import java.io.*; import java.security.*; import java.util.*; @@ -44,7 +46,6 @@ public class TestCICOWithGCMAndAAD extends PKCS11Test { @Override public void main(Provider p) throws Exception { test("GCM", p); -// test("CCM", p); } public void test(String mode, Provider p) throws Exception { @@ -53,9 +54,8 @@ public class TestCICOWithGCMAndAAD extends PKCS11Test { String transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java index 26853ae3ee6..da351bc7493 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.crypto.NoSuchPaddingException; -import jdk.test.lib.Utils; +import jtreg.SkippedException; public class TestChaChaPoly extends PKCS11Test { @@ -70,8 +70,7 @@ public class TestChaChaPoly extends PKCS11Test { try { Cipher.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO); } this.p = p; testTransformations(); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java index 5649ed013ef..d2590b2c3cb 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,22 +26,25 @@ * @bug 8255410 * @library /test/lib .. * @modules jdk.crypto.cryptoki - * @build jdk.test.lib.Convert * @run main/othervm TestChaChaPolyKAT * @summary ChaCha20-Poly1305 Cipher Implementation (KAT) */ -import java.util.*; +import jtreg.SkippedException; + import java.security.GeneralSecurityException; import java.security.Provider; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; -import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.crypto.AEADBadTagException; import java.nio.ByteBuffer; -import jdk.test.lib.Convert; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; public class TestChaChaPolyKAT extends PKCS11Test { public static class TestData { @@ -126,8 +129,7 @@ public class TestChaChaPolyKAT extends PKCS11Test { try { Cipher.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO); } int testsPassed = 0; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java index 94272367caa..60d80b9e365 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +30,22 @@ * (key/nonce reuse check) */ -import java.util.*; +import jtreg.SkippedException; + import javax.crypto.Cipher; import java.security.spec.AlgorithmParameterSpec; import java.security.Provider; import java.security.NoSuchAlgorithmException; -import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.crypto.AEADBadTagException; import javax.crypto.SecretKey; import java.security.InvalidKeyException; import java.security.InvalidAlgorithmParameterException; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; public class TestChaChaPolyNoReuse extends PKCS11Test { @@ -238,8 +242,7 @@ public class TestChaChaPolyNoReuse extends PKCS11Test { try { Cipher.getInstance(CIPHER_ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + CIPHER_ALGO); - return; + throw new SkippedException("Skip; no support for " + CIPHER_ALGO); } int testsPassed = 0; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java index 57a7b9a4606..f68340658fa 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +30,14 @@ * @run main TestChaChaPolyOutputSize */ +import jtreg.SkippedException; + import java.nio.ByteBuffer; import java.security.GeneralSecurityException; -import java.security.Key; import java.security.SecureRandom; import java.security.Provider; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; -import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -60,8 +60,7 @@ public class TestChaChaPolyOutputSize extends PKCS11Test { try { Cipher.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO); } testGetOutSize(p); testMultiPartAEADDec(p); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java b/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java index 76f0c9dc412..cf3d948be17 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run main/othervm TestCipherMode */ +import jtreg.SkippedException; + import java.security.Provider; import java.security.Key; import java.security.KeyPair; @@ -38,20 +40,22 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; public class TestCipherMode extends PKCS11Test { - private static String[] TRANSFORMATIONS = { - "AES/ECB/PKCS5Padding", "AES/GCM/NoPadding", - "RSA/ECB/PKCS1Padding" + private static final String[] TRANSFORMATIONS = { + "AES/ECB/PKCS5Padding", "AES/GCM/NoPadding", + "RSA/ECB/PKCS1Padding" }; - private static byte[] BYTES16 = - Arrays.copyOf(TRANSFORMATIONS[0].getBytes(), 16); + private static final byte[] BYTES16 = + Arrays.copyOf("AES/ECB/PKCS5Padding".getBytes(), 16); private static SecretKey AES_KEY = new SecretKeySpec(BYTES16, "AES"); private static PublicKey RSA_PUBKEY = null; private static PrivateKey RSA_PRIVKEY = null; @@ -97,18 +101,29 @@ public class TestCipherMode extends PKCS11Test { // test all cipher impls, e.g. P11Cipher, P11AEADCipher, and // P11RSACipher - for (String t : TRANSFORMATIONS) { - checkModes(t, p); + List skipped = new ArrayList<>(); + for (final String t : TRANSFORMATIONS) { + try { + checkModes(t, p); + } catch (SkippedException skippedException) { + // printing to System.out, so it's easier to see which test it relates to + skippedException.printStackTrace(System.out); + skipped.add(t); + } + } + + if (!skipped.isEmpty()) { + throw new SkippedException("Some tests skipped: " + skipped); + } else { + System.out.println("All tests passed"); } - System.out.println("All tests passed"); } private static void checkModes(String t, Provider p) throws Exception { try { Cipher.getInstance(t, p); } catch (Exception e) { - System.out.println("Skip " + t + " due to " + e.getMessage()); - return; + throw new SkippedException("Skip " + t + " due to " + e.getMessage()); } for (CipherMode m : CipherMode.values()) { diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java b/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java index adabcc571aa..4e78d8d39d7 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 +31,21 @@ */ -import java.security.*; -import java.security.spec.AlgorithmParameterSpec; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.math.*; +import jtreg.SkippedException; -import java.util.*; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Provider; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import java.util.Arrays; public class TestGCMKeyAndIvCheck extends PKCS11Test { @@ -77,9 +85,8 @@ public class TestGCMKeyAndIvCheck extends PKCS11Test { String transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } System.out.println("Testing against " + p.getName()); SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java index 95e6e5b1a0a..9844e8ecfd2 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Known Answer Test for AES cipher with GCM mode support in * PKCS11 provider. */ +import jtreg.SkippedException; + import java.security.GeneralSecurityException; import java.security.Provider; import java.util.Arrays; @@ -311,9 +313,8 @@ public class TestKATForGCM extends PKCS11Test { try { c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + transformation); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + transformation); } try { if (execute(testValues, c)) { diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java index 73039ba2f65..204b852e4d6 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestRSACipher extends PKCS11Test { @@ -55,8 +56,7 @@ public class TestRSACipher extends PKCS11Test { try { Cipher.getInstance(RSA_ALGOS[0], p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Algorithm " + RSA_ALGOS[0] + " is not supported by provider, skipping"); } String kpgAlgorithm = "RSA"; int keySize = SecurityUtils.getTestKeySize(kpgAlgorithm); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java index 559c7680c06..01d30934049 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +43,7 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestRSACipherWrap extends PKCS11Test { @@ -54,8 +55,7 @@ public class TestRSACipherWrap extends PKCS11Test { try { Cipher.getInstance(RSA_ALGOS[0], p); } catch (GeneralSecurityException e) { - System.out.println(RSA_ALGOS[0] + " unsupported, skipping"); - return; + throw new SkippedException(RSA_ALGOS[0] + " unsupported, skipping"); } String kpgAlgorithm = "RSA"; KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java b/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java index 2c553f7e452..8989e951b09 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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 java.util.HexFormat; import java.util.Random; import javax.crypto.Cipher; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestRawRSACipher extends PKCS11Test { @@ -49,8 +50,7 @@ public class TestRawRSACipher extends PKCS11Test { try { Cipher.getInstance("RSA/ECB/NoPadding", p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Algorithm RSA/ECB/NoPadding is not supported by provider, skipping"); } String kpgAlgorithm = "RSA"; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java index b818adfe589..2e66370b807 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +32,15 @@ * @run main/othervm TestSymmCiphers */ +import jtreg.SkippedException; + import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; @@ -44,43 +48,33 @@ import javax.crypto.SecretKey; public class TestSymmCiphers extends PKCS11Test { - private static class CI { // class for holding Cipher Information + private record CI (String transformation, String keyAlgo, int dataSize){} // record for holding Cipher Information - String transformation; - String keyAlgo; - int dataSize; - - CI(String transformation, String keyAlgo, int dataSize) { - this.transformation = transformation; - this.keyAlgo = keyAlgo; - this.dataSize = dataSize; - } - } private static final CI[] TEST_LIST = { - new CI("ARCFOUR", "ARCFOUR", 400), - new CI("RC4", "RC4", 401), - new CI("DES/CBC/NoPadding", "DES", 400), - new CI("DESede/CBC/NoPadding", "DESede", 160), - new CI("AES/CBC/NoPadding", "AES", 4800), - new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), - new CI("DES/cbc/PKCS5Padding", "DES", 6401), - new CI("DESede/CBC/PKCS5Padding", "DESede", 402), - new CI("AES/CBC/PKCS5Padding", "AES", 30), - new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19), - new CI("DES/ECB/NoPadding", "DES", 400), - new CI("DESede/ECB/NoPadding", "DESede", 160), - new CI("AES/ECB/NoPadding", "AES", 4800), - new CI("DES/ECB/PKCS5Padding", "DES", 32), - new CI("DES/ECB/PKCS5Padding", "DES", 6400), - new CI("DESede/ECB/PKCS5Padding", "DESede", 400), - new CI("AES/ECB/PKCS5Padding", "AES", 64), + new CI("ARCFOUR", "ARCFOUR", 400), + new CI("RC4", "RC4", 401), + new CI("DES/CBC/NoPadding", "DES", 400), + new CI("DESede/CBC/NoPadding", "DESede", 160), + new CI("AES/CBC/NoPadding", "AES", 4800), + new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), + new CI("DES/cbc/PKCS5Padding", "DES", 6401), + new CI("DESede/CBC/PKCS5Padding", "DESede", 402), + new CI("AES/CBC/PKCS5Padding", "AES", 30), + new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19), + new CI("DES/ECB/NoPadding", "DES", 400), + new CI("DESede/ECB/NoPadding", "DESede", 160), + new CI("AES/ECB/NoPadding", "AES", 4800), + new CI("DES/ECB/PKCS5Padding", "DES", 32), + new CI("DES/ECB/PKCS5Padding", "DES", 6400), + new CI("DESede/ECB/PKCS5Padding", "DESede", 400), + new CI("AES/ECB/PKCS5Padding", "AES", 64), - new CI("DES", "DES", 6400), - new CI("DESede", "DESede", 408), - new CI("AES", "AES", 128), + new CI("DES", "DES", 6400), + new CI("DESede", "DESede", 408), + new CI("AES", "AES", 128), - new CI("AES/CTR/NoPadding", "AES", 3200), - new CI("AES/CTS/NoPadding", "AES", 3200), + new CI("AES/CTR/NoPadding", "AES", 3200), + new CI("AES/CTS/NoPadding", "AES", 3200), }; private static final StringBuffer debugBuf = new StringBuffer(); @@ -90,11 +84,10 @@ public class TestSymmCiphers extends PKCS11Test { // NSS reports CKR_DEVICE_ERROR when the data passed to // its EncryptUpdate/DecryptUpdate is not multiple of blocks int firstBlkSize = 16; - boolean status = true; + List skippedList = new ArrayList<>(); Random random = new Random(); try { - for (int i = 0; i < TEST_LIST.length; i++) { - CI currTest = TEST_LIST[i]; + for (CI currTest : TEST_LIST) { System.out.println("===" + currTest.transformation + "==="); try { KeyGenerator kg = @@ -123,7 +116,8 @@ public class TestSymmCiphers extends PKCS11Test { System.out.println("Decryption tests: DONE"); } catch (NoSuchAlgorithmException nsae) { System.out.println("Skipping unsupported algorithm: " + - nsae); + nsae); + skippedList.add(currTest); } } } catch (Exception ex) { @@ -131,11 +125,15 @@ public class TestSymmCiphers extends PKCS11Test { System.out.println(debugBuf); throw ex; } + + if (!skippedList.isEmpty()){ + throw new SkippedException("Some tests skipped: " + skippedList); + } } private static void test(Cipher cipher, int mode, SecretKey key, - AlgorithmParameters params, int firstBlkSize, - byte[] in, byte[] answer) throws Exception { + AlgorithmParameters params, int firstBlkSize, + byte[] in, byte[] answer) throws Exception { // test setup long startTime, endTime; cipher.init(mode, key, params); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java index 9290fe8d6eb..973da3b0c55 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @run main/othervm TestSymmCiphersNoPad */ +import jtreg.SkippedException; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; @@ -39,6 +41,8 @@ import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; @@ -47,48 +51,37 @@ import javax.crypto.SecretKey; public class TestSymmCiphersNoPad extends PKCS11Test { - private static class CI { // class for holding Cipher Information - String transformation; - String keyAlgo; - int dataSize; - - CI(String transformation, String keyAlgo, int dataSize) { - this.transformation = transformation; - this.keyAlgo = keyAlgo; - this.dataSize = dataSize; - } - } - - private static final CI TEST_LIST[] = { - new CI("ARCFOUR", "ARCFOUR", 400), - new CI("RC4", "RC4", 401), - new CI("DES/CBC/NoPadding", "DES", 400), - new CI("DESede/CBC/NoPadding", "DESede", 160), - 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/CTS/NoPadding", "AES", 1600), - new CI("AES/CTS/NoPadding", "AES", 65), - }; + private record CI (String transformation, String keyAlgo, int dataSize){} // record for holding Cipher Information private static final StringBuffer debugBuf = new StringBuffer(); + private static final CI[] TEST_LIST = { + new CI("ARCFOUR", "ARCFOUR", 400), + new CI("RC4", "RC4", 401), + new CI("DES/CBC/NoPadding", "DES", 400), + new CI("DESede/CBC/NoPadding", "DESede", 160), + 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/CTS/NoPadding", "AES", 1600), + new CI("AES/CTS/NoPadding", "AES", 65), + }; + @Override public void main(Provider p) throws Exception { - boolean status = true; + List skippedList = new ArrayList<>(); Random random = new Random(); try { - for (int i = 0; i < TEST_LIST.length; i++) { - CI currTest = TEST_LIST[i]; + for (CI currTest : TEST_LIST) { System.out.println("===" + currTest.transformation + "==="); try { KeyGenerator kg = - KeyGenerator.getInstance(currTest.keyAlgo, p); + KeyGenerator.getInstance(currTest.keyAlgo, p); SecretKey key = kg.generateKey(); Cipher c1 = Cipher.getInstance(currTest.transformation, p); Cipher c2 = Cipher.getInstance(currTest.transformation, - System.getProperty("test.provider.name", "SunJCE")); + System.getProperty("test.provider.name", "SunJCE")); byte[] plainTxt = new byte[currTest.dataSize]; random.nextBytes(plainTxt); @@ -98,16 +91,17 @@ public class TestSymmCiphersNoPad extends PKCS11Test { AlgorithmParameters params = c2.getParameters(); byte[] answer = c2.doFinal(plainTxt); test(c1, Cipher.ENCRYPT_MODE, key, params, - plainTxt, answer); + plainTxt, answer); System.out.println("Encryption tests: DONE"); c2.init(Cipher.DECRYPT_MODE, key, params); byte[] answer2 = c2.doFinal(answer); test(c1, Cipher.DECRYPT_MODE, key, params, - answer, answer2); + answer, answer2); System.out.println("Decryption tests: DONE"); } catch (NoSuchAlgorithmException nsae) { System.out.println("Skipping unsupported algorithm: " + nsae); + skippedList.add(currTest); } } } catch (Exception ex) { @@ -115,6 +109,10 @@ public class TestSymmCiphersNoPad extends PKCS11Test { System.out.println(debugBuf); throw ex; } + + if (!skippedList.isEmpty()){ + throw new SkippedException("Some tests skipped: " + skippedList); + } } private static void test(Cipher cipher, int mode, SecretKey key, From 452b052fe343a70bc81bf299d08a9f06a1e30fe9 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 28 Aug 2025 15:45:17 +0000 Subject: [PATCH 038/295] 8365726: Test crashed with assert in C1 thread: Possible safepoint reached by thread that does not allow it Reviewed-by: dlong, shade --- src/hotspot/share/oops/trainingData.hpp | 4 ++-- src/hotspot/share/runtime/mutexLocker.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index baf19773a7b..c47d0a0f66e 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -96,7 +96,7 @@ public: // TrainingDataLocker is used to guard read/write operations on non-MT-safe data structures. // It supports recursive locking and a read-only mode (in which case no locks are taken). - // It is also a part of the TD collection termination protocol (see the "spanshot" field). + // It is also a part of the TD collection termination protocol (see the "snapshot" field). class TrainingDataLocker { static volatile bool _snapshot; // If true we're not allocating new training data static int _lock_mode; @@ -105,7 +105,7 @@ public: #if INCLUDE_CDS assert(_lock_mode != 0, "Forgot to call TrainingDataLocker::initialize()"); if (_lock_mode > 0) { - TrainingData_lock->lock(); + TrainingData_lock->lock_without_safepoint_check(); } #endif } diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 8cfecd098f6..3f8915973e2 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -263,7 +263,7 @@ void mutex_init() { MUTEX_DEFN(CompiledIC_lock , PaddedMutex , nosafepoint); // locks VtableStubs_lock MUTEX_DEFN(MethodCompileQueue_lock , PaddedMonitor, safepoint); - MUTEX_DEFL(TrainingData_lock , PaddedMutex , MethodCompileQueue_lock); + MUTEX_DEFN(TrainingData_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(TrainingReplayQueue_lock , PaddedMonitor, safepoint); MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint); MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); From 8c6d12250b524c0f4ee25dbbc6fe959581b7617b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 28 Aug 2025 15:58:50 +0000 Subject: [PATCH 039/295] 8333783: java/nio/channels/FileChannel/directio/DirectIOTest.java is unstable with AV software Reviewed-by: bpb --- .../FileChannel/directio/DirectIOTest.java | 90 +++++++++++++------ .../FileChannel/directio/libDirectIO.c | 34 ++++--- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java b/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java index 34f2bacc7dd..b9dd309d0f7 100644 --- a/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java +++ b/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java @@ -27,11 +27,13 @@ * @summary Test for ExtendedOpenOption.DIRECT flag * @requires (os.family == "linux" | os.family == "aix") * @library /test/lib + * @modules java.base/sun.nio.ch:+open java.base/java.io:+open * @build jdk.test.lib.Platform * @run main/native DirectIOTest */ import java.io.*; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.*; @@ -47,10 +49,25 @@ import com.sun.nio.file.ExtendedOpenOption; public class DirectIOTest { private static final int BASE_SIZE = 4096; + private static final int TRIES = 3; + + public static int getFD(FileChannel channel) throws Exception { + Field fFdFd = channel.getClass().getDeclaredField("fd"); + fFdFd.setAccessible(true); + FileDescriptor fd = (FileDescriptor) fFdFd.get(channel); + + Field fFd = FileDescriptor.class.getDeclaredField("fd"); + fFd.setAccessible(true); + return fFd.getInt(fd); + } + + private static void testWrite(Path p, long blockSize) throws Exception { + try (FileChannel fc = FileChannel.open(p, + StandardOpenOption.READ, + StandardOpenOption.WRITE, + ExtendedOpenOption.DIRECT)) { + int fd = getFD(fc); - private static int testWrite(Path p, long blockSize) throws Exception { - try (FileChannel fc = FileChannel.open(p, StandardOpenOption.WRITE, - ExtendedOpenOption.DIRECT)) { int bs = (int)blockSize; int size = Math.max(BASE_SIZE, bs); int alignment = bs; @@ -60,22 +77,55 @@ public class DirectIOTest { for (int j = 0; j < size; j++) { src.put((byte)0); } - src.flip(); - fc.write(src); - return size; + + // If there is AV or other FS tracing software, it may cache the file + // contents on first access, even though we have asked for DIRECT here. + // Do several attempts to make test more resilient. + + for (int t = 0; t < TRIES; t++) { + flushFileCache(size, fd); + src.flip(); + fc.position(0); + fc.write(src); + if (!isFileInCache(size, fd)) { + return; + } + } + + throw new RuntimeException("DirectIO is not working properly with " + + "write. File still exists in cache!"); } } - private static int testRead(Path p, long blockSize) throws Exception { - try (FileChannel fc = FileChannel.open(p, ExtendedOpenOption.DIRECT)) { + private static void testRead(Path p, long blockSize) throws Exception { + try (FileChannel fc = FileChannel.open(p, + StandardOpenOption.READ, + ExtendedOpenOption.DIRECT)) { + int fd = getFD(fc); + int bs = (int)blockSize; int size = Math.max(BASE_SIZE, bs); int alignment = bs; ByteBuffer dest = ByteBuffer.allocateDirect(size + alignment - 1) .alignedSlice(alignment); assert dest.capacity() != 0; - fc.read(dest); - return size; + + // If there is AV or other FS tracing software, it may cache the file + // contents on first access, even though we have asked for DIRECT here. + // Do several attempts to make test more resilient. + + for (int t = 0; t < TRIES; t++) { + flushFileCache(size, fd); + dest.clear(); + fc.position(0); + fc.read(dest); + if (!isFileInCache(size, fd)) { + return; + } + } + + throw new RuntimeException("DirectIO is not working properly with " + + "read. File still exists in cache!"); } } @@ -84,12 +134,8 @@ public class DirectIOTest { Paths.get(System.getProperty("test.dir", ".")), "test", null); } - private static boolean isFileInCache(int size, Path p) { - String path = p.toString(); - return isFileInCache0(size, path); - } - - private static native boolean isFileInCache0(int size, String path); + private static native boolean flushFileCache(int size, int fd); + private static native boolean isFileInCache(int size, int fd); public static void main(String[] args) throws Exception { Path p = createTempFile(); @@ -98,16 +144,8 @@ public class DirectIOTest { System.loadLibrary("DirectIO"); try { - int size = testWrite(p, blockSize); - if (isFileInCache(size, p)) { - throw new RuntimeException("DirectIO is not working properly with " - + "write. File still exists in cache!"); - } - size = testRead(p, blockSize); - if (isFileInCache(size, p)) { - throw new RuntimeException("DirectIO is not working properly with " - + "read. File still exists in cache!"); - } + testWrite(p, blockSize); + testRead(p, blockSize); } finally { Files.delete(p); } diff --git a/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c b/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c index 4897500bf2d..5eea51da4c7 100644 --- a/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c +++ b/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c @@ -45,13 +45,27 @@ static void ThrowException(JNIEnv *env, const char *name, const char *msg) { /* * Class: DirectIO - * Method: isFileInCache0 - * Signature: (ILjava/lang/String;)Z + * Method: flushFileCache + * Signature: (II;)V */ -JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env, +JNIEXPORT void Java_DirectIOTest_flushFileCache(JNIEnv *env, jclass cls, jint file_size, - jstring file_path) { + jint fd) { +#ifdef __linux__ + posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED); +#endif +} + +/* + * Class: DirectIO + * Method: isFileInCache + * Signature: (II;)Z + */ +JNIEXPORT jboolean Java_DirectIOTest_isFileInCache(JNIEnv *env, + jclass cls, + jint file_size, + jint fd) { void *f_mmap; #ifdef __linux__ unsigned char *f_seg; @@ -69,17 +83,10 @@ JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env, size_t index = (file_size + page_size - 1) /page_size; jboolean result = JNI_FALSE; - const char* path = (*env)->GetStringUTFChars(env, file_path, JNI_FALSE); - - int fd = open(path, O_RDWR); - - (*env)->ReleaseStringUTFChars(env, file_path, path); - f_mmap = mmap(0, file_size, PROT_NONE, MAP_SHARED, fd, 0); if (f_mmap == MAP_FAILED) { - close(fd); ThrowException(env, "java/io/IOException", - "test of whether file exists in cache failed"); + "test of whether file exists in cache failed: mmap failed"); } f_seg = malloc(index); if (f_seg != NULL) { @@ -95,9 +102,8 @@ JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env, free(f_seg); } else { ThrowException(env, "java/io/IOException", - "test of whether file exists in cache failed"); + "test of whether file exists in cache failed: malloc failed"); } - close(fd); munmap(f_mmap, file_size); return result; } From 33d00a77f38ea16e4751b216a3bf98a620eb8055 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 28 Aug 2025 16:36:14 +0000 Subject: [PATCH 040/295] 8294035: Remove null ids checking from keytool -gencrl Reviewed-by: weijun --- .../share/classes/sun/security/tools/keytool/Main.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 8c6cd139a0d..9fb830da338 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1562,9 +1562,6 @@ public final class Main { private void doGenCRL(PrintStream out) throws Exception { - if (ids == null) { - throw new Exception("Must provide -id when -gencrl"); - } Certificate signerCert = keyStore.getCertificate(alias); byte[] encoded = signerCert.getEncoded(); X509CertImpl signerCertImpl = new X509CertImpl(encoded); From aaac8c0636e12c40c46170bf4989bd34bb577430 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 28 Aug 2025 17:38:09 +0000 Subject: [PATCH 041/295] 8366254: (fs) UnixException.translateToIOException should translate ELOOP to FileSystemLoopException Reviewed-by: vyazici, alanb --- .../unix/classes/sun/nio/fs/UnixException.java | 10 ++++++---- test/jdk/java/nio/file/Files/IsSameFile.java | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixException.java b/src/java.base/unix/classes/sun/nio/fs/UnixException.java index 9c90911f9cf..0f0de768109 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixException.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +92,11 @@ class UnixException extends Exception { return new NoSuchFileException(file, other, null); if (errno() == UnixConstants.EEXIST) return new FileAlreadyExistsException(file, other, null); - if (errno() == UnixConstants.ELOOP) - return new FileSystemException(file, other, errorString() - + " or unable to access attributes of symbolic link"); + if (errno() == UnixConstants.ELOOP) { + String msg = file + ": " + errorString() + + " or unable to access attributes of symbolic link"; + return new FileSystemLoopException(msg); + } // fallback to the more general exception return new FileSystemException(file, other, errorString()); diff --git a/test/jdk/java/nio/file/Files/IsSameFile.java b/test/jdk/java/nio/file/Files/IsSameFile.java index 00bac0fb5a7..44e03a15a02 100644 --- a/test/jdk/java/nio/file/Files/IsSameFile.java +++ b/test/jdk/java/nio/file/Files/IsSameFile.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 8154364 + * @bug 8154364 8366254 * @summary Test of Files.isSameFile * @requires (os.family != "windows") * @library .. /test/lib @@ -33,6 +33,7 @@ import java.io.IOException; import java.io.FileOutputStream; import java.nio.file.Files; import java.nio.file.FileSystem; +import java.nio.file.FileSystemLoopException; import java.nio.file.FileSystemException; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -451,6 +452,6 @@ public class IsSameFile { @ParameterizedTest @MethodSource("linkLoopSource") public void linkLoop(boolean expect, Path x, Path y) throws IOException { - assertThrows(FileSystemException.class, () -> Files.isSameFile(x, y)); + assertThrows(FileSystemLoopException.class, () -> Files.isSameFile(x, y)); } } From 9f70965bb9ead2268c02c688c79ec0d80574c725 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 28 Aug 2025 18:08:55 +0000 Subject: [PATCH 042/295] 8366193: Add comments about ResolvedFieldEntry::copy_from() Reviewed-by: adinn, coleenp --- src/hotspot/share/oops/resolvedFieldEntry.hpp | 30 ++++++++++++++++++- src/hotspot/share/oops/resolvedIndyEntry.hpp | 5 +++- .../share/oops/resolvedMethodEntry.hpp | 4 ++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/oops/resolvedFieldEntry.hpp b/src/hotspot/share/oops/resolvedFieldEntry.hpp index c98d5f54d1e..1e89d10ab0c 100644 --- a/src/hotspot/share/oops/resolvedFieldEntry.hpp +++ b/src/hotspot/share/oops/resolvedFieldEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +80,38 @@ public: ResolvedFieldEntry() : ResolvedFieldEntry(0) {} + // Notes on copy constructor, copy assignment operator, and copy_from(). + // These are necessary for generating deterministic CDS archives. + // + // We have some unused padding on 64-bit platforms (4 bytes at the tail end). + // + // When ResolvedFieldEntries in a ConstantPoolCache are allocated from the metaspace, + // their entire content (including the padding) is filled with zeros. They are + // then initialized with initialize_resolved_entries_array() in cpCache.cpp from a + // GrowableArray. + // + // The GrowableArray is initialized in rewriter.cpp, using ResolvedFieldEntries that + // are originally allocated from the C++ stack. Functions like GrowableArray::expand_to() + // will also allocate ResolvedFieldEntries from the stack. These may have random bits + // in the padding as the C++ compiler is allowed to leave the padding in uninitialized + // states. + // + // If we use the default copy constructor and/or default copy assignment operator, + // the random padding will be copied into the GrowableArray, from there + // to the ConstantPoolCache, and eventually to the CDS archive. As a result, the + // CDS archive will contain random bits, causing failures in + // test/hotspot/jtreg/runtime/cds/DeterministicDump.java (usually on Windows). + // + // By using copy_from(), we can prevent the random padding from being copied, + // ensuring that the ResolvedFieldEntries in a ConstantPoolCache (and thus the + // CDS archive) will have all zeros in the padding. + + // Copy constructor ResolvedFieldEntry(const ResolvedFieldEntry& other) { copy_from(other); } + // Copy assignment operator ResolvedFieldEntry& operator=(const ResolvedFieldEntry& other) { copy_from(other); return *this; diff --git a/src/hotspot/share/oops/resolvedIndyEntry.hpp b/src/hotspot/share/oops/resolvedIndyEntry.hpp index a7782c88f1e..af0efbadc9f 100644 --- a/src/hotspot/share/oops/resolvedIndyEntry.hpp +++ b/src/hotspot/share/oops/resolvedIndyEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +52,9 @@ class ResolvedIndyEntry { u1 _flags; // Flags: [0000|00|has_appendix|resolution_failed] public: + // The copy_from() pattern in resolvedFieldEntry.hpp is not necessary + // as we have no unused padding (on 32- or 64-bit platforms). + ResolvedIndyEntry() : _method(nullptr), _resolved_references_index(0), diff --git a/src/hotspot/share/oops/resolvedMethodEntry.hpp b/src/hotspot/share/oops/resolvedMethodEntry.hpp index 8f49608127f..097f7de8a56 100644 --- a/src/hotspot/share/oops/resolvedMethodEntry.hpp +++ b/src/hotspot/share/oops/resolvedMethodEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,8 @@ class ResolvedMethodEntry { bool _has_table_index; #endif + // See comments in resolvedFieldEntry.hpp about copy_from and padding. + // We have unused padding on debug builds. void copy_from(const ResolvedMethodEntry& other) { _method = other._method; _entry_specific = other._entry_specific; From 05da2137f1cb6eef1cfc7693905daf789d315b5c Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Thu, 28 Aug 2025 21:23:15 +0000 Subject: [PATCH 043/295] 8362335: [macos] Change value of CFBundleDevelopmentRegion from "English" to "en-US" Reviewed-by: asemenyuk --- .../internal/resources/ApplicationRuntime-Info.plist.template | 2 +- .../jdk/jpackage/internal/resources/Info-lite.plist.template | 2 +- .../jdk/jpackage/internal/resources/Runtime-Info.plist.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template index e24cc94fa8e..af8e19177c2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - English + en-US CFBundleExecutable libjli.dylib CFBundleIdentifier diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template index b981dc41d65..7b69368c8dd 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template @@ -5,7 +5,7 @@ LSMinimumSystemVersion 10.11 CFBundleDevelopmentRegion - English + en-US CFBundleAllowMixedLocalizations CFBundleExecutable diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template index 5a1492e2eab..82fbdbbfbfb 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - English + en-US CFBundleExecutable libjli.dylib CFBundleIdentifier From b8cdf31a2e52df857df2badb4f365454443dd89d Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Fri, 29 Aug 2025 00:46:53 +0000 Subject: [PATCH 044/295] 8365898: Specification of java.lang.module.ModuleDescriptor.packages() method can be improved Reviewed-by: alanb, liach --- .../share/classes/java/lang/module/ModuleDescriptor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index 7aac752cc89..c55ccd735df 100644 --- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -1516,11 +1516,7 @@ public final class ModuleDescriptor } /** - * Returns the set of packages in the module. - * - *

      The set of packages includes all exported and open packages, as well - * as the packages of any service providers, and the package for the main - * class.

      + * Returns the set of all packages in the module. * * @return A possibly-empty unmodifiable set of the packages in the module */ From a2da75a6b69f56be41741bffba2c6874a93dfa40 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 29 Aug 2025 06:13:34 +0000 Subject: [PATCH 045/295] 8362884: [GCC static analyzer] unix NetworkInterface.c addif leak on early returns Reviewed-by: dfuchs, mbaesken --- .../unix/native/libnet/NetworkInterface.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index 61267ec13d5..ceb5dd5f751 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -58,10 +58,14 @@ #endif #define CHECKED_MALLOC3(_pointer, _type, _size) \ + CHECKED_MALLOC4(_pointer, _type, _size, {}) + +#define CHECKED_MALLOC4(_pointer, _type, _size, _onFailure) \ do { \ _pointer = (_type)malloc(_size); \ if (_pointer == NULL) { \ JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \ + do _onFailure while (0); \ return ifs; /* return untouched list */ \ } \ } while(0) @@ -995,7 +999,7 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, // If "new" then create a netif structure and insert it into the list. if (currif == NULL) { - CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE); + CHECKED_MALLOC4(currif, netif *, sizeof(netif) + IFNAMESIZE, { free(addrP); }); currif->name = (char *)currif + sizeof(netif); strncpy(currif->name, name, IFNAMESIZE); currif->name[IFNAMESIZE - 1] = '\0'; @@ -1027,7 +1031,10 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, } if (currif == NULL) { - CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE); + CHECKED_MALLOC4(currif, netif *, sizeof(netif) + IFNAMESIZE, { + free(addrP); + free(parent); + }); currif->name = (char *)currif + sizeof(netif); strncpy(currif->name, vname, IFNAMESIZE); currif->name[IFNAMESIZE - 1] = '\0'; @@ -1039,7 +1046,11 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, parent->childs = currif; } - CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size); + CHECKED_MALLOC4(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size, { + free(addrP); + free(parent); + free(currif); + }); memcpy(tmpaddr, addrP, sizeof(netaddr)); if (addrP->addr != NULL) { tmpaddr->addr = (struct sockaddr *) From 86d6a2e05eb52ea2c603a06bce838a56d5ae507b Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 29 Aug 2025 07:35:03 +0000 Subject: [PATCH 046/295] 8366147: ZGC: ZPageAllocator::cleanup_failed_commit_single_partition may leak memory Reviewed-by: stefank, sjohanss, jsikstro --- src/hotspot/share/gc/z/zPageAllocator.cpp | 23 +++++++++++-------- .../hotspot/jtreg/gc/z/TestCommitFailure.java | 8 +++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index d8f653cc7d0..9f484394521 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1092,7 +1092,8 @@ void ZPartition::free_memory_alloc_failed(ZMemoryAllocation* allocation) { freed += vmem.size(); _cache.insert(vmem); } - assert(allocation->harvested() + allocation->committed_capacity() == freed, "must have freed all"); + assert(allocation->harvested() + allocation->committed_capacity() == freed, "must have freed all" + " %zu + %zu == %zu", allocation->harvested(), allocation->committed_capacity(), freed); // Adjust capacity to reflect the failed capacity increase const size_t remaining = allocation->size() - freed; @@ -1909,23 +1910,27 @@ void ZPageAllocator::cleanup_failed_commit_single_partition(ZSinglePartitionAllo ZMemoryAllocation* const allocation = single_partition_allocation->allocation(); assert(allocation->commit_failed(), "Must have failed to commit"); + assert(allocation->partial_vmems()->is_empty(), "Invariant for single partition commit failure"); - const size_t committed = allocation->committed_capacity(); - const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested()); - const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed); - const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed); + // For a single partition we have unmapped the harvested memory before we + // started committing, and moved its physical memory association to the start + // of the vmem. As such, the partial_vmems is empty. All the harvested and + // partially successfully committed memory is mapped in the first part of vmem. + const size_t harvested_and_committed_capacity = allocation->harvested() + allocation->committed_capacity(); + const ZVirtualMemory succeeded_vmem = vmem.first_part(harvested_and_committed_capacity); + const ZVirtualMemory failed_vmem = vmem.last_part(harvested_and_committed_capacity); - if (committed_vmem.size() > 0) { + if (succeeded_vmem.size() > 0) { // Register the committed and mapped memory. We insert the committed // memory into partial_vmems so that it will be inserted into the cache // in a subsequent step. - allocation->partial_vmems()->append(committed_vmem); + allocation->partial_vmems()->append(succeeded_vmem); } // Free the virtual and physical memory we fetched to use but failed to commit ZPartition& partition = allocation->partition(); - partition.free_physical(non_committed_vmem); - partition.free_virtual(non_committed_vmem); + partition.free_physical(failed_vmem); + partition.free_virtual(failed_vmem); } void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { diff --git a/test/hotspot/jtreg/gc/z/TestCommitFailure.java b/test/hotspot/jtreg/gc/z/TestCommitFailure.java index c1babe7eb83..3cee84d4f95 100644 --- a/test/hotspot/jtreg/gc/z/TestCommitFailure.java +++ b/test/hotspot/jtreg/gc/z/TestCommitFailure.java @@ -23,6 +23,14 @@ package gc.z; +/* + * @test id=Normal + * @requires vm.gc.Z & vm.debug + * @summary Test ZGC graceful failure when a commit fails + * @library / /test/lib + * @run driver gc.z.TestCommitFailure + */ + /* * @test id=ZFakeNUMA * @requires vm.gc.Z & vm.debug From 937d61bfbaba61117076c78358570ec4c35c8c42 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 29 Aug 2025 14:35:26 +0000 Subject: [PATCH 047/295] 8364751: ConstantBootstraps.explicitCast contradictory specification for null-to-primitive Reviewed-by: jvernee, rriggs --- .../java/lang/invoke/ConstantBootstraps.java | 50 +++++++----- test/jdk/java/lang/constant/ConvertTest.java | 79 ------------------- .../invoke/condy/ConstantBootstrapsTest.java | 46 ++++++++++- 3 files changed, 76 insertions(+), 99 deletions(-) delete mode 100644 test/jdk/java/lang/constant/ConvertTest.java diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java index b7983d18b2e..89d818721a1 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -369,17 +369,32 @@ public final class ConstantBootstraps { *

      * Otherwise one of the following conversions is applied to {@code value}: *

        - *
      1. If {@code dstType} is a reference type, a reference cast - * is applied to {@code value} as if by calling {@code dstType.cast(value)}. - *
      2. If {@code dstType} is a primitive type, then, if the runtime type - * of {@code value} is a primitive wrapper type (such as {@link Integer}), - * a Java unboxing conversion is applied {@jls 5.1.8} followed by a - * Java casting conversion {@jls 5.5} converting either directly to - * {@code dstType}, or, if {@code dstType} is {@code boolean}, - * to {@code int}, which is then converted to either {@code true} - * or {@code false} depending on whether the least-significant-bit - * is 1 or 0 respectively. If the runtime type of {@code value} is - * not a primitive wrapper type a {@link ClassCastException} is thrown. + *
      3. If {@code dstType} is a reference type, a reference cast is applied + * to {@code value} as if by calling {@link Class#cast(Object) + * dstType.cast(value)}. + *
      4. Otherwise, {@code dstType} is a primitive type: + *
          + *
        1. If {@code value} is null, the default value (JVMS {@jvms 2.3}) + * of {@code dstType} is returned. + *
        2. If the runtime type of {@code value} is a primitive wrapper type + * (such as {@link Integer}), a Java unboxing conversion is applied + * (JLS {@jls 5.1.8}). + *
            + *
          • If the runtime type is {@link Boolean}, the unboxing result + * is then converted to {@code int}, where {@code true} becomes + * {@code 1} and {@code false} becomes {@code 0}. + *
          + * Followed by a Java casting conversion (JLS {@jls 5.5}): + *
            + *
          • If {@code dstType} is not {@code boolean}, the cast converts + * directly to {@code dstType}. + *
          • If {@code dstType} is {@code boolean}, the cast converts to + * {@code int}, and the resulting {@code boolean} is produced + * by testing whether the least significant bit of the cast + * {@code int} is 1. + *
          + *
        3. Otherwise, a {@link ClassCastException} is thrown. + *
        *
      *

      * The result is the same as when using the following code: @@ -393,13 +408,12 @@ public final class ConstantBootstraps { * @param lookup unused * @param name unused * @param dstType the destination type of the conversion - * @param value the value to be converted + * @param value the value to be converted, may be null * @return the converted value - * @throws ClassCastException when {@code dstType} is {@code void}, - * when a cast per (1) fails, or when {@code dstType} is a primitive type - * and the runtime type of {@code value} is not a primitive wrapper type - * (such as {@link Integer}) - * + * @throws ClassCastException when {@code dstType} is {@code void}; when + * {@code dstType} is a reference type, and the reference cast fails; or + * when {@code dstType} is primitive, and {@code value} is an + * instance of a reference type that is not a wrapper class * @since 15 */ public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class dstType, Object value) diff --git a/test/jdk/java/lang/constant/ConvertTest.java b/test/jdk/java/lang/constant/ConvertTest.java deleted file mode 100644 index d7018df6352..00000000000 --- a/test/jdk/java/lang/constant/ConvertTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * 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 - * @run testng ConvertTest - */ - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import java.lang.invoke.ConstantBootstraps; -import java.math.BigInteger; - -import static org.testng.Assert.assertEquals; - -public class ConvertTest { - - @DataProvider - public static Object[][] cceInputs() { - return new Object[][]{ - { void.class, null }, - { Integer.class, "a" }, - { int.class, BigInteger.ZERO }, - }; - } - - @Test(dataProvider = "cceInputs", expectedExceptions = ClassCastException.class) - public void testBadConversion(Class dstType, Object value) { - ConstantBootstraps.explicitCast(null, null, dstType, value); - } - - @DataProvider - public static Object[][] goodInputs() { - Object o = new Object(); - return new Object[][]{ - { Object.class, null, null }, - { Object.class, o, o }, - { String.class, "abc", "abc" }, - { short.class, 10, (short) 10 }, - { int.class, (short) 10, 10 }, - { boolean.class, 1, true }, - { boolean.class, 2, false }, - { int.class, true, 1 }, - { int.class, false, 0 }, - { int.class, 10, 10 }, - { Integer.class, 10, 10 }, - { Object.class, 10, 10 }, - { Number.class, 10, 10 }, - }; - } - - @Test(dataProvider = "goodInputs") - public void testSuccess(Class dstType, Object value, Object expected) { - Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); - assertEquals(actual, expected); - } - -} diff --git a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java index 640affeec5c..829f26704f9 100644 --- a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java +++ b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8186046 8195694 + * @bug 8186046 8195694 8241100 8364751 * @summary Test dynamic constant bootstraps * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper @@ -31,6 +31,7 @@ * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest */ +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; @@ -241,4 +242,45 @@ public class ConstantBootstrapsTest { assertEquals(vhandle.varType(), String.class); assertEquals(vhandle.coordinateTypes(), List.of(String[].class, int.class)); } + + @DataProvider + public static Object[][] cceCasts() { + return new Object[][]{ + { void.class, null }, + { Integer.class, "a" }, + { int.class, BigInteger.ZERO }, + }; + } + + @Test(dataProvider = "cceCasts", expectedExceptions = ClassCastException.class) + public void testBadCasts(Class dstType, Object value) { + ConstantBootstraps.explicitCast(null, null, dstType, value); + } + + @DataProvider + public static Object[][] validCasts() { + Object o = new Object(); + return new Object[][]{ + { Object.class, null, null }, + { Object.class, o, o }, + { String.class, "abc", "abc" }, + { short.class, 10, (short) 10 }, + { int.class, (short) 10, 10 }, + { boolean.class, 1, true }, + { boolean.class, 2, false }, + { int.class, true, 1 }, + { int.class, false, 0 }, + { int.class, 10, 10 }, + { Integer.class, 10, 10 }, + { Object.class, 10, 10 }, + { Number.class, 10, 10 }, + { char.class, null, (char) 0 } + }; + } + + @Test(dataProvider = "validCasts") + public void testSuccessfulCasts(Class dstType, Object value, Object expected) { + Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); + assertEquals(actual, expected); + } } From ae9607725c8c6a1b2f2728dbb5f7993722497da7 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 29 Aug 2025 14:35:45 +0000 Subject: [PATCH 048/295] 8361614: Missing sub-int value validation in the Class-File API Reviewed-by: asotona --- .../java/lang/classfile/AccessFlags.java | 4 +- .../java/lang/classfile/ClassBuilder.java | 17 ++ .../java/lang/classfile/ClassFileVersion.java | 15 +- .../java/lang/classfile/ClassModel.java | 8 +- .../java/lang/classfile/ClassReader.java | 5 +- .../java/lang/classfile/CodeBuilder.java | 55 +++-- .../java/lang/classfile/FieldBuilder.java | 4 + .../java/lang/classfile/MethodBuilder.java | 6 +- .../java/lang/classfile/TypeAnnotation.java | 39 +++- .../attribute/CharacterRangeInfo.java | 3 + .../classfile/attribute/InnerClassInfo.java | 9 +- .../classfile/attribute/LineNumberInfo.java | 2 + .../attribute/MethodParameterInfo.java | 8 +- .../classfile/attribute/ModuleAttribute.java | 8 +- .../classfile/attribute/ModuleExportInfo.java | 10 +- .../classfile/attribute/ModuleOpenInfo.java | 10 +- .../attribute/ModuleRequireInfo.java | 6 +- .../attribute/ModuleResolutionAttribute.java | 6 +- .../constantpool/ConstantPoolBuilder.java | 4 +- .../classfile/instruction/CharacterRange.java | 4 +- .../instruction/DiscontinuedInstruction.java | 15 +- .../instruction/IncrementInstruction.java | 6 +- .../classfile/instruction/LineNumber.java | 4 +- .../instruction/LoadInstruction.java | 17 +- .../classfile/instruction/LocalVariable.java | 16 +- .../instruction/LocalVariableType.java | 16 +- .../instruction/StoreInstruction.java | 17 +- .../java/lang/classfile/package-info.java | 46 +++- .../impl/AbstractPseudoInstruction.java | 4 +- .../classfile/impl/AccessFlagsImpl.java | 6 +- .../classfile/impl/ClassFileVersionImpl.java | 9 +- .../classfile/impl/DirectClassBuilder.java | 2 +- .../classfile/impl/DirectFieldBuilder.java | 6 +- .../classfile/impl/DirectMethodBuilder.java | 6 +- .../classfile/impl/LineNumberImpl.java | 4 +- .../impl/ModuleAttributeBuilderImpl.java | 4 +- .../classfile/impl/SplitConstantPool.java | 1 + .../classfile/impl/TargetInfoImpl.java | 45 ++-- .../classfile/impl/UnboundAttribute.java | 27 ++- .../jdk/internal/classfile/impl/Util.java | 29 ++- .../classfile/InstructionValidationTest.java | 66 +++++- .../classfile/PreviewMinorVersionTest.java | 57 ----- .../jdk/classfile/SubIntValidationTest.java | 201 ++++++++++++++++++ 43 files changed, 636 insertions(+), 191 deletions(-) delete mode 100644 test/jdk/jdk/classfile/PreviewMinorVersionTest.java create mode 100644 test/jdk/jdk/classfile/SubIntValidationTest.java diff --git a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java index 33db731efc8..c53609615b8 100644 --- a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java +++ b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java @@ -64,8 +64,8 @@ public sealed interface AccessFlags permits AccessFlagsImpl { /** - * {@return the access flags, as a bit mask} It is in the range of unsigned - * short, {@code [0, 0xFFFF]}. + * {@return the access flags, as a bit mask} It is a {@link + * java.lang.classfile##u2 u2} value. */ int flagsMask(); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 6efd240d8af..86cdb298d9e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -66,6 +66,9 @@ public sealed interface ClassBuilder * @param major the major version number * @param minor the minor version number * @return this builder + * @throws IllegalArgumentException if {@code major} or {@code minor} is not + * {@link java.lang.classfile##u2 u2}; {@code minor} may be {@code + * -1} to indicate {@value ClassFile#PREVIEW_MINOR_VERSION} * @see ClassFileVersion */ default ClassBuilder withVersion(int major, int minor) { @@ -77,6 +80,8 @@ public sealed interface ClassBuilder * * @param flags the access flags, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see AccessFlags * @see AccessFlag.Location#CLASS */ @@ -188,6 +193,8 @@ public sealed interface ClassBuilder * @param descriptor the field descriptor string * @param flags the access flags for this field, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see FieldModel * @see FieldBuilder#withFlags(int) */ @@ -221,6 +228,8 @@ public sealed interface ClassBuilder * @param descriptor the symbolic field descriptor * @param flags the access flags for this field, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see FieldModel * @see FieldBuilder#withFlags(int) */ @@ -260,6 +269,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ ClassBuilder withMethod(Utf8Entry name, @@ -284,6 +295,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method body * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ default ClassBuilder withMethodBody(Utf8Entry name, @@ -304,6 +317,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ default ClassBuilder withMethod(String name, @@ -333,6 +348,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method body * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ default ClassBuilder withMethodBody(String name, diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java b/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java index 5a795b94865..a6dfcae8884 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java @@ -60,8 +60,8 @@ public sealed interface ClassFileVersion extends ClassElement permits ClassFileVersionImpl { /** - * {@return the major version} It is in the range of unsigned short, {@code - * [0, 65535]}. + * {@return the major version} It is a {@link java.lang.classfile##u2 u2} + * value. * * @apiNote * Constants in {@link ClassFile} named {@code Java_#_VERSION}, where # is @@ -71,15 +71,20 @@ public sealed interface ClassFileVersion int majorVersion(); /** - * {@return the minor version} It is in the range of unsigned short, {@code - * [0, 65535]}. + * {@return the minor version} It is a {@link java.lang.classfile##u2 u2} + * value. */ int minorVersion(); /** - * {@return a {@link ClassFileVersion} element} + * {@return a {@link ClassFileVersion} element} The minor version number + * may be {@code -1} to represent {@value ClassFile#PREVIEW_MINOR_VERSION}. + * * @param majorVersion the major version * @param minorVersion the minor version + * @throws IllegalArgumentException if the major version or the minor + * version is not {@link java.lang.classfile##u2 u2}; the minor + * version may be {@code -1} */ static ClassFileVersion of(int majorVersion, int minorVersion) { return new ClassFileVersionImpl(majorVersion, minorVersion); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassModel.java b/src/java.base/share/classes/java/lang/classfile/ClassModel.java index 2c547e6336d..735ce34d232 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassModel.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassModel.java @@ -84,16 +84,16 @@ public sealed interface ClassModel ClassEntry thisClass(); /** - * {@return the major version of this class} It is in the range of unsigned - * short, {@code [0, 65535]}. + * {@return the major version of this class} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see ClassFileVersion */ int majorVersion(); /** - * {@return the minor version of this class} It is in the range of unsigned - * short, {@code [0, 65535]}. + * {@return the minor version of this class} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see ClassFileVersion */ 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 3de188af8b3..c3d60d7fc31 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java @@ -153,8 +153,9 @@ public sealed interface ClassReader extends ConstantPool int readU1(int offset); /** - * {@return the unsigned short at the specified offset within the {@code - * class} file} Reads a 2-byte value and zero-extends it to an {@code int}. + * {@return the {@link java.lang.classfile##u2 u2} at the specified offset + * within the {@code class} file} Reads a 2-byte value and zero-extends it + * to an {@code int}. * * @param offset the offset within the {@code class} file */ 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 c1070bbcc77..656e84adf58 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -465,7 +465,7 @@ public sealed interface CodeBuilder * @param slot the local variable slot * @return this builder * @throws IllegalArgumentException if {@code tk} is {@link TypeKind#VOID - * void} or {@code slot} is out of range + * void} or {@code slot} is not {@link java.lang.classfile##u2 u2} * @see LoadInstruction */ default CodeBuilder loadLocal(TypeKind tk, int slot) { @@ -479,7 +479,8 @@ public sealed interface CodeBuilder * @param slot the local variable slot * @return this builder * @throws IllegalArgumentException if {@code tk} is {@link TypeKind#VOID - * void} or {@code slot} is out of range + * void} or {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see StoreInstruction */ default CodeBuilder storeLocal(TypeKind tk, int slot) { @@ -811,6 +812,8 @@ public sealed interface CodeBuilder * * @param line the line number * @return this builder + * @throws IllegalArgumentException if {@code line} is not {@link + * java.lang.classfile##u2 u2} * @see LineNumber */ default CodeBuilder lineNumber(int line) { @@ -907,6 +910,8 @@ public sealed interface CodeBuilder * @param characterRangeEnd the encoded end of the character range region (exclusive) * @param flags the flags word, indicating the kind of range * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see CharacterRange */ default CodeBuilder characterRange(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { @@ -926,7 +931,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariable */ default CodeBuilder localVariable(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { @@ -946,7 +952,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariable */ default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { @@ -974,7 +981,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariableType */ default CodeBuilder localVariableType(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { @@ -999,7 +1007,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariableType */ default CodeBuilder localVariableType(int slot, String name, Signature signature, Label startScope, Label endScope) { @@ -1058,7 +1067,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ALOAD * @see #loadLocal * @see LoadInstruction @@ -1128,7 +1138,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ASTORE * @see #storeLocal * @see StoreInstruction @@ -1384,7 +1395,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#DLOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -1449,7 +1461,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#DSTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction @@ -1696,7 +1709,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#FLOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -1761,7 +1775,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#FSTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction @@ -2393,7 +2408,9 @@ public sealed interface CodeBuilder * @param slot the local variable slot * @param val the increment value * @return this builder - * @throws IllegalArgumentException if {@code slot} or {@code val} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} or {@code val} is out of range of + * {@link TypeKind#SHORT short} * @see Opcode#IINC * @see IncrementInstruction */ @@ -2410,7 +2427,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ILOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -2763,7 +2781,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ISTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction @@ -3001,7 +3020,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#LLOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -3103,7 +3123,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#LSTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction diff --git a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java index 477aa6984a2..a71cdb2611f 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java @@ -56,6 +56,8 @@ public sealed interface FieldBuilder * * @param flags the access flags, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see AccessFlags * @see AccessFlag.Location#FIELD * @see ClassBuilder#withField(String, ClassDesc, int) @@ -69,6 +71,8 @@ public sealed interface FieldBuilder * * @param flags the access flags, as a bit mask * @return this builder + * @throws IllegalArgumentException if any flag cannot be applied to the + * {@link AccessFlag.Location#FIELD} location * @see AccessFlags * @see AccessFlag.Location#FIELD * @see ClassBuilder#withField(String, ClassDesc, int) diff --git a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java index ff777246fde..847f5315c5f 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java @@ -58,7 +58,8 @@ public sealed interface MethodBuilder * * @param flags the access flags, as a bit mask * @return this builder - * @throws IllegalArgumentException if the {@link ClassFile#ACC_STATIC + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2}, or the {@link ClassFile#ACC_STATIC * ACC_STATIC} flag is modified * @see AccessFlags * @see AccessFlag.Location#METHOD @@ -74,7 +75,8 @@ public sealed interface MethodBuilder * @param flags the access flags, as a bit mask * @return this builder * @throws IllegalArgumentException if the {@link ClassFile#ACC_STATIC - * ACC_STATIC} flag is modified + * ACC_STATIC} flag is modified, or if any flag cannot be applied to + * the {@link AccessFlag.Location#METHOD} location * @see AccessFlags * @see AccessFlag.Location#METHOD */ diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 68514a2436c..09dc3b59098 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -31,6 +31,7 @@ import java.util.List; import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; +import jdk.internal.classfile.impl.Util; import static java.lang.classfile.TypeAnnotation.TargetInfo.*; @@ -352,6 +353,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on a class or method type parameter declaration} * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER} or {@link TargetType#METHOD_TYPE_PARAMETER} * @param typeParameterIndex specifies which type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeParameterTarget ofTypeParameter(TargetType targetType, int typeParameterIndex) { return new TargetInfoImpl.TypeParameterTargetImpl(targetType, typeParameterIndex); @@ -360,6 +363,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on a class type parameter declaration} * @param typeParameterIndex specifies which type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeParameterTarget ofClassTypeParameter(int typeParameterIndex) { return ofTypeParameter(TargetType.CLASS_TYPE_PARAMETER, typeParameterIndex); @@ -368,6 +373,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on a method type parameter declaration} * @param typeParameterIndex specifies which type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeParameterTarget ofMethodTypeParameter(int typeParameterIndex) { return ofTypeParameter(TargetType.METHOD_TYPE_PARAMETER, typeParameterIndex); @@ -376,6 +383,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on the type of an "extends" or "implements" clause} * @param supertypeIndex the index into the interfaces array or 65535 to indicate it is the superclass + * @throws IllegalArgumentException if {@code supertypeIndex} is not + * {@link java.lang.classfile##u2 u2} */ static SupertypeTarget ofClassExtends(int supertypeIndex) { return new TargetInfoImpl.SupertypeTargetImpl(supertypeIndex); @@ -387,6 +396,8 @@ public sealed interface TypeAnnotation * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER_BOUND} or {@link TargetType#METHOD_TYPE_PARAMETER_BOUND} * @param typeParameterIndex specifies which type parameter declaration is annotated * @param boundIndex specifies which bound of the type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} or + * {@code boundIndex} is not {@link java.lang.classfile##u1 u1} */ static TypeParameterBoundTarget ofTypeParameterBound(TargetType targetType, int typeParameterIndex, int boundIndex) { return new TargetInfoImpl.TypeParameterBoundTargetImpl(targetType, typeParameterIndex, boundIndex); @@ -397,6 +408,8 @@ public sealed interface TypeAnnotation * a generic class, or interface} * @param typeParameterIndex specifies which type parameter declaration is annotated * @param boundIndex specifies which bound of the type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} or + * {@code boundIndex} is not {@link java.lang.classfile##u1 u1} */ static TypeParameterBoundTarget ofClassTypeParameterBound(int typeParameterIndex, int boundIndex) { return ofTypeParameterBound(TargetType.CLASS_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex); @@ -407,6 +420,8 @@ public sealed interface TypeAnnotation * a generic method, or constructor} * @param typeParameterIndex specifies which type parameter declaration is annotated * @param boundIndex specifies which bound of the type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} or + * {@code boundIndex} is not {@link java.lang.classfile##u1 u1} */ static TypeParameterBoundTarget ofMethodTypeParameterBound(int typeParameterIndex, int boundIndex) { return ofTypeParameterBound(TargetType.METHOD_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex); @@ -448,6 +463,8 @@ public sealed interface TypeAnnotation * synthetic or implicit parameters are omitted. * * @param formalParameterIndex specifies which formal parameter declaration has an annotated type + * @throws IllegalArgumentException if {@code formalParameterIndex} is + * not {@link java.lang.classfile##u1 u1} */ static FormalParameterTarget ofMethodFormalParameter(int formalParameterIndex) { return new TargetInfoImpl.FormalParameterTargetImpl(formalParameterIndex); @@ -457,6 +474,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on the i'th type in the throws clause of a method or * constructor declaration} * @param throwsTargetIndex the index into the exception table of the Exceptions attribute of the method + * @throws IllegalArgumentException if {@code throwsTargetIndex} is + * not {@link java.lang.classfile##u2 u2} */ static ThrowsTarget ofThrows(int throwsTargetIndex) { return new TargetInfoImpl.ThrowsTargetImpl(throwsTargetIndex); @@ -492,6 +511,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on the i'th type in an exception parameter declaration} * @param exceptionTableIndex the index into the exception table of the Code attribute + * @throws IllegalArgumentException if {@code exceptionTableIndex} is + * not {@link java.lang.classfile##u2 u2} */ static CatchTarget ofExceptionParameter(int exceptionTableIndex) { return new TargetInfoImpl.CatchTargetImpl(exceptionTableIndex); @@ -552,6 +573,8 @@ public sealed interface TypeAnnotation * or {@link TargetType#METHOD_REFERENCE_TYPE_ARGUMENT} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the cast operator or argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofTypeArgument(TargetType targetType, Label target, int typeArgumentIndex) { return new TargetInfoImpl.TypeArgumentTargetImpl(targetType, target, typeArgumentIndex); @@ -561,6 +584,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on the i'th type in a cast expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the cast operator is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofCastExpr(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CAST, target, typeArgumentIndex); @@ -571,6 +596,8 @@ public sealed interface TypeAnnotation * an explicit constructor invocation statement} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofConstructorInvocationTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -581,6 +608,8 @@ public sealed interface TypeAnnotation * a method invocation expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofMethodInvocationTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.METHOD_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -591,6 +620,8 @@ public sealed interface TypeAnnotation * a new expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofConstructorReferenceTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -601,6 +632,8 @@ public sealed interface TypeAnnotation * a method reference expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofMethodReferenceTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.METHOD_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -792,6 +825,8 @@ public sealed interface TypeAnnotation * @param startLabel the code label indicating start of an interval where variable has value * @param endLabel the code label indicating start of an interval where variable has value * @param index index into the local variables + * @throws IllegalArgumentException if {@code index} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVarTargetInfo of(Label startLabel, Label endLabel, int index) { return new TargetInfoImpl.LocalVarTargetInfoImpl(startLabel, endLabel, index); @@ -959,9 +994,11 @@ public sealed interface TypeAnnotation * {@return type path component of an annotation} * @param typePathKind the kind of path element * @param typeArgumentIndex the type argument index + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypePathComponent of(Kind typePathKind, int typeArgumentIndex) { - + Util.checkU1(typeArgumentIndex, "type argument index"); return switch (typePathKind) { case ARRAY -> ARRAY; case INNER_TYPE -> INNER_TYPE; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java index 7bb0a0d124d..f6f5f9928bc 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.instruction.CharacterRange; import jdk.internal.classfile.impl.UnboundAttribute; +import jdk.internal.classfile.impl.Util; /** * Models a single character range entry in the {@link @@ -166,6 +167,8 @@ public sealed interface CharacterRangeInfo * @param characterRangeEnd the encoded end of character positions in the * source file, exclusive * @param flags the flags of this entry + * @throws IllegalArgumentException if {@code startPc}, {@code endPc}, or + * {@code flags} is not {@link java.lang.classfile##u2 u2} */ static CharacterRangeInfo of(int startPc, int endPc, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java index 960d3755c4c..df6b63ae692 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java @@ -68,8 +68,7 @@ public sealed interface InnerClassInfo /** * {@return a bit mask of flags denoting access permissions and properties - * of the inner class} It is in the range of unsigned short, {@code [0, - * 0xFFFF]}. + * of the inner class} It is a {@link java.lang.classfile##u2 u2} value. * * @see Class#getModifiers() * @see AccessFlag.Location#INNER_CLASS @@ -104,6 +103,8 @@ public sealed interface InnerClassInfo * @param outerClass the class that has the nested class as a member, if it exists * @param innerName the simple name of the nested class, if it is not anonymous * @param flags the inner class access flags + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static InnerClassInfo of(ClassEntry innerClass, Optional outerClass, Optional innerName, int flags) { @@ -116,7 +117,9 @@ public sealed interface InnerClassInfo * @param outerClass the class that has the nested class as a member, if it exists * @param innerName the simple name of the nested class, if it is not anonymous * @param flags the inner class access flags - * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass} represents a primitive type + * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass} + * represents a primitive type, or if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static InnerClassInfo of(ClassDesc innerClass, Optional outerClass, Optional innerName, int flags) { return new UnboundAttribute.UnboundInnerClassInfo(TemporaryConstantPool.INSTANCE.classEntry(innerClass), diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java index 2f4f6d00deb..3a0b5499657 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java @@ -60,6 +60,8 @@ public sealed interface LineNumberInfo * * @param startPc the starting index of the code array for this line * @param lineNumber the line number within the original source file + * @throws IllegalArgumentException if {@code startPc} or {@code lineNumber} + * is not {@link java.lang.classfile##u2 u2} */ public static LineNumberInfo of(int startPc, int lineNumber) { return new UnboundAttribute.UnboundLineNumberInfo(startPc, lineNumber); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java index 636c671f25a..a5bc14601e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java @@ -53,8 +53,8 @@ public sealed interface MethodParameterInfo Optional name(); /** - * {@return the access flags, as a bit mask} It is in the range of unsigned - * short, {@code [0, 0xFFFF]}. + * {@return the access flags, as a bit mask} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see Parameter#getModifiers() * @see AccessFlag.Location#METHOD_PARAMETER @@ -85,6 +85,8 @@ public sealed interface MethodParameterInfo * {@return a method parameter description} * @param name the method parameter name, may be empty * @param flags the method parameter access flags + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static MethodParameterInfo of(Optional name, int flags) { return new UnboundAttribute.UnboundMethodParameterInfo(name, flags); @@ -105,6 +107,8 @@ public sealed interface MethodParameterInfo * {@return a method parameter description} * @param name the method parameter name, may be empty * @param flags the method parameter access flags + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static MethodParameterInfo ofParameter(Optional name, int flags) { return of(name.map(TemporaryConstantPool.INSTANCE::utf8Entry), flags); 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 ad564913d84..678c0f29714 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 @@ -81,8 +81,8 @@ public sealed interface ModuleAttribute ModuleEntry moduleName(); /** - * {@return the module flags of the module, as a bit mask} It is in the - * range of unsigned short, {@code [0, 0xFFFF]}. + * {@return the module flags of the module, as a bit mask} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor#modifiers() * @see AccessFlag.Location#MODULE @@ -170,6 +170,8 @@ public sealed interface ModuleAttribute * @param opens the opened packages * @param uses the consumed services * @param provides the provided services + * @throws IllegalArgumentException if {@code moduleFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleAttribute of(ModuleEntry moduleName, int moduleFlags, Utf8Entry moduleVersion, @@ -230,6 +232,8 @@ public sealed interface ModuleAttribute * * @param flagsMask the module flags * @return this builder + * @throws IllegalArgumentException if {@code flagsMask} is not {@link + * java.lang.classfile##u2 u2} */ ModuleAttributeBuilder moduleFlags(int flagsMask); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java index e498b8bc036..af04c83d260 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java @@ -58,7 +58,7 @@ public sealed interface ModuleExportInfo /** * {@return the flags associated with this export declaration, as a bit mask} - * It is in the range of unsigned short, {@code [0, 0xFFFF]}. + * It is a {@link java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor.Exports#modifiers() * @see AccessFlag.Location#MODULE_EXPORTS @@ -103,6 +103,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, List exportsTo) { @@ -131,6 +133,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, @@ -161,6 +165,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, List exportsTo) { @@ -191,6 +197,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java index d183a0b4985..40a9b929776 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java @@ -64,7 +64,7 @@ public sealed interface ModuleOpenInfo /** * {@return the flags associated with this open declaration, as a bit mask} - * It is in the range of unsigned short, {@code [0, 0xFFFF]}. + * It is a {@link java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor.Opens#modifiers() * @see AccessFlag.Location#MODULE_OPENS @@ -109,6 +109,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, List opensTo) { @@ -137,6 +139,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, @@ -166,6 +170,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the modules to which this package is opened, if it is a * qualified open, or empty + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, List opensTo) { @@ -194,6 +200,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the packages to which this package is opened, or empty if * this is an unqualified open + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java index 49544554090..6e3e7df5ed0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java @@ -55,7 +55,7 @@ public sealed interface ModuleRequireInfo /** * {@return the flags associated with this require declaration, as a bit mask} - * It is in the range of unsigned short, {@code [0, 0xFFFF]}. + * It is a {@link java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor.Requires#modifiers() * @see AccessFlag.Location#MODULE_REQUIRES @@ -97,6 +97,8 @@ public sealed interface ModuleRequireInfo * @param requires the required module * @param requiresFlags the require-specific flags * @param requiresVersion the required version, may be {@code null} + * @throws IllegalArgumentException if {@code requiresFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleRequireInfo of(ModuleEntry requires, int requiresFlags, Utf8Entry requiresVersion) { return new UnboundAttribute.UnboundModuleRequiresInfo(requires, requiresFlags, Optional.ofNullable(requiresVersion)); @@ -121,6 +123,8 @@ public sealed interface ModuleRequireInfo * @param requires the required module * @param requiresFlags the require-specific flags * @param requiresVersion the required version, may be {@code null} + * @throws IllegalArgumentException if {@code requiresFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleRequireInfo of(ModuleDesc requires, int requiresFlags, String requiresVersion) { return new UnboundAttribute.UnboundModuleRequiresInfo(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(requires.name())), requiresFlags, Optional.ofNullable(requiresVersion).map(s -> TemporaryConstantPool.INSTANCE.utf8Entry(s))); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java index 039700f024a..1d607da2333 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java @@ -78,8 +78,8 @@ public sealed interface ModuleResolutionAttribute permits BoundAttribute.BoundModuleResolutionAttribute, UnboundAttribute.UnboundModuleResolutionAttribute { /** - * {@return the module resolution flags} It is in the range of unsigned - * short, {@code [0, 0xFFFF]}. + * {@return the module resolution flags} It is a {@link + * java.lang.classfile##u2 u2} value. *

      * The value of the resolution_flags item is a mask of flags used to denote * properties of module resolution. The flags are as follows: @@ -99,6 +99,8 @@ public sealed interface ModuleResolutionAttribute * {@return a {@code ModuleResolution} attribute} * * @param resolutionFlags the resolution flags + * @throws IllegalArgumentException if {@code resolutionFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleResolutionAttribute of(int resolutionFlags) { return new UnboundAttribute.UnboundModuleResolutionAttribute(resolutionFlags); 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 4b443929158..7d3f3c546a7 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 @@ -397,12 +397,14 @@ public sealed interface ConstantPoolBuilder /** * {@return a {@link MethodHandleEntry} encoding a reference kind and - * referring to a {@link MemberRefEntry}} The reference kind must be + * referring to a {@link MemberRefEntry}} The reference kind is * in {@code [1, 9]}, and the {@code MemberRefEntry} is subject to * various restrictions based on the reference kind (JVMS {@jvms 4.4.8}). * * @param refKind the reference kind of the method handle * @param reference the {@code MemberRefEntry} + * @throws IllegalArgumentException if {@code refKind} is not {@link + * java.lang.classfile##u1 u1} * @see MethodHandleInfo##refkinds Reference kinds * @see MethodHandleEntry#kind() MethodHandleEntry::kind * @see MethodHandleEntry#reference() MethodHandleEntry::reference diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java index 07d4c116b3a..ec491880fd9 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +149,8 @@ public sealed interface CharacterRange extends PseudoInstruction * @param characterRangeStart the encoded start of the character range region (inclusive) * @param characterRangeEnd the encoded end of the character range region (exclusive) * @param flags a flags word, indicating the kind of range + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static CharacterRange of(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { return new AbstractPseudoInstruction.UnboundCharacterRange(startScope, endScope, characterRangeStart, characterRangeEnd, flags); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java index 906aaea421d..40c4f06f98c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java @@ -131,7 +131,7 @@ public sealed interface DiscontinuedInstruction extends Instruction { * // @link substring="RetInstruction" target="#of(int)" : * RetInstruction(int slot) // @link substring="slot" target="#slot()" * } - * where {@code slot} must be within {@code [0, 65535]}. + * where {@code slot} must be {@link java.lang.classfile##u2 u2}. *

      * {@link StoreInstruction astore} series of instructions store a {@link * TypeKind##returnAddress returnAddress} value to a local variable slot, @@ -153,16 +153,16 @@ public sealed interface DiscontinuedInstruction extends Instruction { /** * {@return the local variable slot with return address} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); /** * {@return a return from subroutine instruction} *

      - * {@code slot} must be in the closed range of {@code [0, 255]} for - * {@link Opcode#RET ret}, or within {@code [0, 65535]} for {@link - * Opcode#RET_W wide ret}. + * {@code slot} must be {@link java.lang.classfile##u1 u1} for + * {@link Opcode#RET ret}, or {@link java.lang.classfile##u2 u2} for + * {@link Opcode#RET_W wide ret}. * * @apiNote * The explicit {@code op} argument allows creating {@code wide ret} @@ -183,10 +183,11 @@ public sealed interface DiscontinuedInstruction extends Instruction { /** * {@return a return from subroutine instruction} *

      - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot to load return address from - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static RetInstruction of(int slot) { return of(slot < 256 ? Opcode.RET : Opcode.RET_W, slot); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java index a874ef0a954..352f83f529c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +48,7 @@ import jdk.internal.classfile.impl.AbstractInstruction; * } * where *

        - *
      • {@code slot} must be within {@code [0, 65535]}. + *
      • {@code slot} must be {@link java.lang.classfile##u2 u2}. *
      • {@code constant} must be within {@code [-32768, 32767]}. *
      * @@ -73,7 +73,7 @@ public sealed interface IncrementInstruction extends Instruction /** * {@return an increment instruction} *
        - *
      • {@code slot} must be within {@code [0, 65535]}. + *
      • {@code slot} must be {@link java.lang.classfile##u2 u2}. *
      • {@code constant} must be within {@code [-32768, 32767]}. *
      * diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java index 3f10a3ada0d..12760df5fcb 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ public sealed interface LineNumber extends PseudoInstruction * {@return a line number pseudo-instruction} * * @param line the line number + * @throws IllegalArgumentException if {@code line} is not {@link + * java.lang.classfile##u2 u2} */ static LineNumber of(int line) { return LineNumberImpl.of(line); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java index 81961320be3..16de554b228 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.internal.classfile.impl.Util; * ) * } * where {@code TypeKind} is {@linkplain TypeKind##computational-type - * computational}, and {@code slot} is within {@code [0, 65535]}. + * computational}, and {@code slot} is {@link java.lang.classfile##u2 u2}. * * @see Opcode.Kind#LOAD * @see CodeBuilder#loadLocal CodeBuilder::loadLocal @@ -62,7 +62,7 @@ public sealed interface LoadInstruction extends Instruction /** * {@return the local variable slot to load from} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -76,12 +76,13 @@ public sealed interface LoadInstruction extends Instruction * {@return a local variable load instruction} * {@code kind} is {@linkplain TypeKind#asLoadable() converted} to its * computational type. - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be a {@link java.lang.classfile##u2 u2} value. * * @param kind the type of the value to be loaded * @param slot the local variable slot to load from * @throws IllegalArgumentException if {@code kind} is - * {@link TypeKind#VOID void} or {@code slot} is out of range + * {@link TypeKind#VOID void} or {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LoadInstruction of(TypeKind kind, int slot) { var opcode = BytecodeHelpers.loadOpcode(kind, slot); // validates slot, trusted @@ -96,8 +97,10 @@ public sealed interface LoadInstruction extends Instruction *
        *
      • If {@code op} has size 1, {@code slot} must be exactly the slot value * implied by the opcode. - *
      • If {@code op} has size 2, {@code slot} must be within {@code [0, 255]}. - *
      • If {@code op} has size 4, {@code slot} must be within {@code [0, 65535]}. + *
      • If {@code op} has size 2, {@code slot} must be {@link + * java.lang.classfile##u1 u1}. + *
      • If {@code op} has size 4, {@code slot} must be {@link + * java.lang.classfile##u2 u2}. *
      * * @apiNote diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java index f44a4e094f1..3c743aadbeb 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.internal.classfile.impl.Util; * Label endScope // @link substring="endScope" target="#endScope" * ) * } - * Where {@code slot} is within {@code [0, 65535]}. + * Where {@code slot} is {@link java.lang.classfile##u2 u2}. *

      * Another model, {@link LocalVariableInfo}, also models a local variable * entry; it has no dependency on a {@code CodeModel} and represents of bci @@ -79,7 +79,7 @@ public sealed interface LocalVariable extends PseudoInstruction permits AbstractPseudoInstruction.UnboundLocalVariable, BoundLocalVariable { /** * {@return the local variable slot} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -116,14 +116,15 @@ public sealed interface LocalVariable extends PseudoInstruction /** * {@return a local variable pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param nameEntry the local variable name * @param descriptorEntry the local variable descriptor * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariable of(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { return new AbstractPseudoInstruction.UnboundLocalVariable(slot, nameEntry, descriptorEntry, @@ -132,14 +133,15 @@ public sealed interface LocalVariable extends PseudoInstruction /** * {@return a local variable pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param name the local variable name * @param descriptor the local variable descriptor * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariable of(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { return of(slot, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java index 1e28804a837..09d8c11d52f 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.internal.classfile.impl.TemporaryConstantPool; * Label endScope // @link substring="endScope" target="#endScope" * ) * } - * Where {@code slot} is within {@code [0, 65535]}. + * Where {@code slot} is {@link java.lang.classfile##u2 u2}. *

      * Another model, {@link LocalVariableTypeInfo}, also models a local variable * type entry; it has no dependency on a {@code CodeModel} and represents of bci @@ -72,7 +72,7 @@ public sealed interface LocalVariableType extends PseudoInstruction permits AbstractPseudoInstruction.UnboundLocalVariableType, BoundLocalVariableType { /** * {@return the local variable slot} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -109,14 +109,15 @@ public sealed interface LocalVariableType extends PseudoInstruction /** * {@return a local variable type pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param nameEntry the local variable name * @param signatureEntry the local variable signature * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariableType of(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { return new AbstractPseudoInstruction.UnboundLocalVariableType(slot, nameEntry, signatureEntry, @@ -125,14 +126,15 @@ public sealed interface LocalVariableType extends PseudoInstruction /** * {@return a local variable type pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param name the local variable name * @param signature the local variable signature * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariableType of(int slot, String name, Signature signature, Label startScope, Label endScope) { return of(slot, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java index 93d33e0b7c2..35190796c19 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.internal.classfile.impl.Util; * ) * } * where {@code TypeKind} is {@linkplain TypeKind##computational-type - * computational}, and {@code slot} is within {@code [0, 65535]}. + * computational}, and {@code slot} is {@link java.lang.classfile##u2 u2}. *

      * {@code astore} series of instructions, or {@code reference} type store * instructions, can also operate on the {@link TypeKind##returnAddress @@ -66,7 +66,7 @@ public sealed interface StoreInstruction extends Instruction /** * {@return the local variable slot to store to} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -82,12 +82,13 @@ public sealed interface StoreInstruction extends Instruction * {@return a local variable store instruction} * {@code kind} is {@linkplain TypeKind#asLoadable() converted} to its * computational type. - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param kind the type of the value to be stored * @param slot the local variable slot to store to * @throws IllegalArgumentException if {@code kind} is {@link - * TypeKind#VOID void} or {@code slot} is out of range + * TypeKind#VOID void} or {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static StoreInstruction of(TypeKind kind, int slot) { var opcode = BytecodeHelpers.storeOpcode(kind, slot); // validates slot @@ -102,8 +103,10 @@ public sealed interface StoreInstruction extends Instruction *

        *
      • If {@code op} has size 1, {@code slot} must be exactly the slot value * implied by the opcode. - *
      • If {@code op} has size 2, {@code slot} must be within {@code [0, 255]}. - *
      • If {@code op} has size 4, {@code slot} must be within {@code [0, 65535]}. + *
      • If {@code op} has size 2, {@code slot} must be {@link + * java.lang.classfile##u1 u1}. + *
      • If {@code op} has size 4, {@code slot} must be {@link + * java.lang.classfile##u2 u2}. *
      * * @apiNote diff --git a/src/java.base/share/classes/java/lang/classfile/package-info.java b/src/java.base/share/classes/java/lang/classfile/package-info.java index 832dac2fff1..5d905aace65 100644 --- a/src/java.base/share/classes/java/lang/classfile/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/package-info.java @@ -273,13 +273,22 @@ * accepting constant pool entries. * *

      Consistency checks, syntax checks and verification

      + * The Class-File API performs checks to ensure arguments are representable in + * the {@code class} file format. A value that is lost when it is built to a + * {@code class} file and re-parsed to a model is rejected with an {@link + * IllegalArgumentException}. For example, a negative value or a value over + * {@code 65535} is lost when built to a {@link ##u2 u2} item, with + * the range {@code [0, 65535]}. In particular, any variable-sized table + * exceeding its maximum representable size is rejected. + *

      * No consistency checks are performed while building or transforming classfiles - * (except for null arguments checks). All builders and classfile elements factory - * methods accepts the provided information without implicit validation. - * However, fatal inconsistencies (like for example invalid code sequence or + * (except for null and representable arguments checks). All builders and + * classfile elements factory methods accepts the provided information without + * implicit validation, as long as they are representable in the {@code class} + * file format. However, fatal inconsistencies (like invalid code sequence or * unresolved labels) affects internal tools and may cause exceptions later in * the classfile building process. These fatal exceptions are thrown as - * {@link IllegalArgumentException}. + * {@code IllegalArgumentException}. *

      * Using nominal descriptors assures the right serial form is applied by the * ClassFile API library based on the actual context. Also these nominal @@ -294,9 +303,9 @@ *

      * On the other hand it is possible to use builders methods and factories accepting * constant pool entries directly. Constant pool entries can be constructed also - * directly from raw values, with no additional conversions or validations. - * Following example uses intentionally wrong class name form and it is applied - * without any validation or conversion. + * directly from raw values, with no additional conversions or validations, as + * long as they are representable. Following example uses intentionally wrong + * class name form, which is applied without any validation or conversion. * {@snippet lang=java : * var invalidClassEntry = constantPoolBuilder.classEntry( * constantPoolBuilder.utf8Entry("mypackage.MyClass")); @@ -451,6 +460,29 @@ * accept nominal descriptors from {@link java.lang.constant} (e.g., {@link * ClassDesc}.) * + *

      Conventional data types

      + * Chapter {@jvms 4} of the Java Virtual Machine Specification + * defines a few conventional data types in the {@code class} file format. + * They are consistently represented as {@code int} in the API model. + * Out-of-bound values provided for these data types to the API result in {@link + * IllegalArgumentException}. + *
      + *
      {@code u1}
      + *
      One-byte {@linkplain Byte#toUnsignedInt(byte) unsigned} integer, in the + * range {@code [0, 255]}. + *
      See {@link java.io.DataInput#readUnsignedByte()}.
      + *
      {@code u2}
      + *
      Two-byte {@linkplain Short#toUnsignedInt(short) unsigned} integer, in the + * range {@code [0, 65535]}. + *
      Equivalent to a Java {@link Character char}. Frequently used for flag + * fields and indices and sizes of list structures. + *
      See {@link java.io.DataInput#readUnsignedShort()}.
      + *
      {@code u4}
      + *
      Four-byte {@linkplain Integer#toUnsignedLong(int) unsigned} integer, in + * the range {@code [0, 4294967295]}. + *
      See {@link java.io.DataInput#readInt()}.
      + *
      + * *

      Data model

      * We define each kind of element by its name, an optional arity indicator (zero * or more, zero or one, exactly one), and a list of components. The elements diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index ea3af78a600..43d8b2b1b3f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,7 +116,7 @@ public abstract sealed class AbstractPseudoInstruction this.endScope = requireNonNull(endScope); this.characterRangeStart = characterRangeStart; this.characterRangeEnd = characterRangeEnd; - this.flags = flags; + this.flags = Util.checkU2(flags, "character range flags"); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java index 43e15c04b6d..c290dd438c5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ public final class AccessFlagsImpl extends AbstractElement private final int flagsMask; private Set flags; - public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) { + public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) { this.location = location; this.flagsMask = Util.flagsToBits(location, flags); this.flags = Set.of(flags); @@ -43,7 +43,7 @@ public final class AccessFlagsImpl extends AbstractElement public AccessFlagsImpl(AccessFlag.Location location, int mask) { this.location = location; - this.flagsMask = mask; + this.flagsMask = Util.checkFlags(mask); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java index ba2605296cb..93fc4f47c85 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +26,17 @@ package jdk.internal.classfile.impl; import java.lang.classfile.ClassFileVersion; +import static java.lang.classfile.ClassFile.PREVIEW_MINOR_VERSION; + public final class ClassFileVersionImpl extends AbstractElement implements ClassFileVersion { private final int majorVersion, minorVersion; public ClassFileVersionImpl(int majorVersion, int minorVersion) { - this.majorVersion = majorVersion; - this.minorVersion = minorVersion; + this.majorVersion = Util.checkU2(majorVersion, "major version"); + this.minorVersion = minorVersion == -1 ? PREVIEW_MINOR_VERSION + : Util.checkU2(minorVersion, "minor version"); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 1e12969f204..0e82c545359 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -81,7 +81,7 @@ public final class DirectClassBuilder @Override public ClassBuilder withFlags(int flags) { - setFlags(flags); + setFlags(Util.checkFlags(flags)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java index 1af3724766e..8dae9665f83 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ public final class DirectFieldBuilder setOriginal(original); this.name = requireNonNull(name); this.desc = requireNonNull(type); - this.flags = flags; + this.flags = Util.checkFlags(flags); } @Override @@ -71,7 +71,7 @@ public final class DirectFieldBuilder @Override public FieldBuilder withFlags(int flags) { - setFlags(flags); + setFlags(Util.checkFlags(flags)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java index 938d6c088b7..db8c185a07d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,12 +51,12 @@ public final class DirectMethodBuilder setOriginal(original); this.name = requireNonNull(nameInfo); this.desc = requireNonNull(typeInfo); - this.flags = flags; + this.flags = Util.checkFlags(flags); } @Override public MethodBuilder withFlags(int flags) { - setFlags(flags); + setFlags(Util.checkFlags(flags)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java index 4fc4a342143..36fd4915f71 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ public final class LineNumberImpl } public static LineNumber of(int line) { - return (line < INTERN_LIMIT) + return (Util.checkU2(line, "line number") < INTERN_LIMIT) ? internCache[line] : new LineNumberImpl(line); } 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 505bbfd6fea..1b77af3746e 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ public final class ModuleAttributeBuilderImpl @Override public ModuleAttributeBuilder moduleFlags(int flags) { - this.moduleFlags = flags; + this.moduleFlags = Util.checkFlags(flags); return this; } 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 5a5f2908ae6..d9ca3ff61bc 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 @@ -594,6 +594,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder { @Override public MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference) { + Util.checkU1(refKind, "reference kind"); reference = AbstractPoolEntry.maybeClone(this, reference); int hash = AbstractPoolEntry.hash2(TAG_METHOD_HANDLE, refKind, reference.index()); EntryMap map1 = map(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index 07aa3c8d8c8..a0afb5efae1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,13 +44,18 @@ public final class TargetInfoImpl { public record TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) implements TypeParameterTarget { - public TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) { - this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER, TARGET_METHOD_TYPE_PARAMETER); - this.typeParameterIndex = typeParameterIndex; + public TypeParameterTargetImpl { + checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER, TARGET_METHOD_TYPE_PARAMETER); + Util.checkU1(typeParameterIndex, "type parameter index"); } } public record SupertypeTargetImpl(int supertypeIndex) implements SupertypeTarget { + + public SupertypeTargetImpl { + Util.checkU2(supertypeIndex, "supertype index"); + } + @Override public TargetType targetType() { return TargetType.CLASS_EXTENDS; @@ -60,10 +65,10 @@ public final class TargetInfoImpl { public record TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) implements TypeParameterBoundTarget { - public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) { - this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER_BOUND, TARGET_METHOD_TYPE_PARAMETER_BOUND); - this.typeParameterIndex = typeParameterIndex; - this.boundIndex = boundIndex; + public TypeParameterBoundTargetImpl { + checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER_BOUND, TARGET_METHOD_TYPE_PARAMETER_BOUND); + Util.checkU1(typeParameterIndex, "type parameter index"); + Util.checkU1(boundIndex, "bound index"); } } @@ -75,6 +80,11 @@ public final class TargetInfoImpl { } public record FormalParameterTargetImpl(int formalParameterIndex) implements FormalParameterTarget { + + public FormalParameterTargetImpl { + Util.checkU1(formalParameterIndex, "formal parameter index"); + } + @Override public TargetType targetType() { return TargetType.METHOD_FORMAL_PARAMETER; @@ -82,6 +92,11 @@ public final class TargetInfoImpl { } public record ThrowsTargetImpl(int throwsTargetIndex) implements ThrowsTarget { + + public ThrowsTargetImpl { + Util.checkU2(throwsTargetIndex, "throws type index"); + } + @Override public TargetType targetType() { return TargetType.THROWS; @@ -107,10 +122,16 @@ public final class TargetInfoImpl { public LocalVarTargetInfoImpl { requireNonNull(startLabel); requireNonNull(endLabel); + BytecodeHelpers.validateSlot(index); } } public record CatchTargetImpl(int exceptionTableIndex) implements CatchTarget { + + public CatchTargetImpl { + Util.checkU2(exceptionTableIndex, "exception table index"); + } + @Override public TargetType targetType() { return TargetType.EXCEPTION_PARAMETER; @@ -128,10 +149,10 @@ public final class TargetInfoImpl { public record TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) implements TypeArgumentTarget { - public TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) { - this.targetType = checkValid(targetType, TARGET_CAST, TARGET_METHOD_REFERENCE_TYPE_ARGUMENT); - this.target = requireNonNull(target); - this.typeArgumentIndex = typeArgumentIndex; + public TypeArgumentTargetImpl { + checkValid(targetType, TARGET_CAST, TARGET_METHOD_REFERENCE_TYPE_ARGUMENT); + requireNonNull(target); + Util.checkU1(typeArgumentIndex, "type argument index"); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 0b0f1836f66..347b0c12657 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -474,7 +474,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleResolutionAttribute(int flags) { super(Attributes.moduleResolution()); - resolutionFlags = flags; + resolutionFlags = Util.checkU2(flags, "resolution flags"); } @Override @@ -888,7 +888,14 @@ public abstract sealed class UnboundAttribute> int characterRangeStart, int characterRangeEnd, int flags) - implements CharacterRangeInfo { } + implements CharacterRangeInfo { + + public UnboundCharacterRangeInfo { + Util.checkU2(startPc, "start pc"); + Util.checkU2(endPc, "end pc"); + Util.checkU2(flags, "flags"); + } + } public record UnboundInnerClassInfo(ClassEntry innerClass, Optional outerClass, @@ -899,11 +906,17 @@ public abstract sealed class UnboundAttribute> requireNonNull(innerClass); requireNonNull(outerClass); requireNonNull(innerName); + Util.checkFlags(flagsMask); } } public record UnboundLineNumberInfo(int startPc, int lineNumber) - implements LineNumberInfo { } + implements LineNumberInfo { + public UnboundLineNumberInfo { + Util.checkU2(startPc, "start pc"); + Util.checkU2(lineNumber, "line number"); + } + } public record UnboundLocalVariableInfo(int startPc, int length, Utf8Entry name, @@ -931,6 +944,7 @@ public abstract sealed class UnboundAttribute> implements MethodParameterInfo { public UnboundMethodParameterInfo { requireNonNull(name); + Util.checkFlags(flagsMask); } } @@ -940,6 +954,7 @@ public abstract sealed class UnboundAttribute> implements ModuleExportInfo { public UnboundModuleExportInfo { requireNonNull(exportedPackage); + Util.checkFlags(exportsFlagsMask); exportsTo = List.copyOf(exportsTo); } } @@ -957,6 +972,7 @@ public abstract sealed class UnboundAttribute> implements ModuleOpenInfo { public UnboundModuleOpenInfo { requireNonNull(openedPackage); + Util.checkFlags(opensFlagsMask); opensTo = List.copyOf(opensTo); } } @@ -975,6 +991,7 @@ public abstract sealed class UnboundAttribute> implements ModuleRequireInfo { public UnboundModuleRequiresInfo { requireNonNull(requires); + Util.checkFlags(requiresFlagsMask); requireNonNull(requiresVersion); } } @@ -1028,7 +1045,7 @@ public abstract sealed class UnboundAttribute> { super(Attributes.module()); this.moduleName = requireNonNull(moduleName); - this.moduleFlags = moduleFlags; + this.moduleFlags = Util.checkFlags(moduleFlags); this.moduleVersion = moduleVersion; this.requires = List.copyOf(requires); this.exports = List.copyOf(exports); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index b0234fb88cc..0eea2bffd22 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +56,7 @@ import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void; * represented as JVM type descriptor strings and symbols are represented as * name strings */ -public class Util { +public final class Util { private Util() { } @@ -186,6 +186,31 @@ public class Util { String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k)); } + /// Ensures the given value won't be truncated when written as a u1 + public static int checkU1(int incoming, String valueName) { + if ((incoming & ~0xFF) != 0) { + throw outOfRangeException(incoming, valueName, "u1"); + } + return incoming; + } + + /// Ensures the given value won't be truncated when written as a u2 + public static char checkU2(int incoming, String valueName) { + if ((incoming & ~0xFFFF) != 0) + throw outOfRangeException(incoming, valueName, "u2"); + return (char) incoming; + } + + public static IllegalArgumentException outOfRangeException(int value, String fieldName, String typeName) { + return new IllegalArgumentException( + String.format("%s out of range of %d: %d", fieldName, typeName, value)); + } + + /// Ensures the given mask won't be truncated when written as an access flag + public static char checkFlags(int mask) { + return checkU2(mask, "access flags"); + } + public static int flagsToBits(AccessFlag.Location location, Collection flags) { int i = 0; for (AccessFlag f : flags) { diff --git a/test/jdk/jdk/classfile/InstructionValidationTest.java b/test/jdk/jdk/classfile/InstructionValidationTest.java index 9d5b4198adf..f02c7a9c78c 100644 --- a/test/jdk/jdk/classfile/InstructionValidationTest.java +++ b/test/jdk/jdk/classfile/InstructionValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,14 @@ /* * @test - * @bug 8341277 8361102 - * @summary Testing ClassFile instruction argument validation. + * @bug 8341277 8361102 8361182 8361614 + * @summary Testing ClassFile (pseudo-)instruction argument validation. * @run junit InstructionValidationTest */ import java.lang.classfile.*; +import java.lang.classfile.attribute.CharacterRangeInfo; +import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.instruction.*; @@ -278,4 +280,62 @@ class InstructionValidationTest { cob.return_(); }); } + + @Test + void testCharacterRange() { + assertDoesNotThrow(() -> CharacterRangeInfo.of(0, 0, -234, 59494648, 0)); + assertDoesNotThrow(() -> CharacterRangeInfo.of(0, 0, -234, 59494648, 65535)); + assertThrows(IllegalArgumentException.class, () -> CharacterRangeInfo.of(0, 0, -234, 59494648, -1)); + assertThrows(IllegalArgumentException.class, () -> CharacterRangeInfo.of(0, 0, -234, 59494648, 65536)); + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + var dummyLabel = cob.startLabel(); + assertDoesNotThrow(() -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, 0)); + assertDoesNotThrow(() -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, 65535)); + assertThrows(IllegalArgumentException.class, () -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, -1)); + assertThrows(IllegalArgumentException.class, () -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, 65536)); + assertThrows(IllegalArgumentException.class, () -> cob.characterRange(dummyLabel, dummyLabel, -234, 59494648, -1)); + assertThrows(IllegalArgumentException.class, () -> cob.characterRange(dummyLabel, dummyLabel, -234, 59494648, 65536)); + cob.return_(); + })); + } + + @Test + void testLineNumber() { + assertDoesNotThrow(() -> LineNumberInfo.of(0, 25)); + assertThrows(IllegalArgumentException.class, () -> LineNumberInfo.of(0, -1)); + assertThrows(IllegalArgumentException.class, () -> LineNumberInfo.of(0, 65536)); + assertDoesNotThrow(() -> LineNumber.of(25)); + assertThrows(IllegalArgumentException.class, () -> LineNumber.of(-1)); + assertThrows(IllegalArgumentException.class, () -> LineNumber.of(65536)); + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + assertThrows(IllegalArgumentException.class, () -> cob.lineNumber(-1)); + assertThrows(IllegalArgumentException.class, () -> cob.lineNumber(65536)); + cob.return_(); + })); + } + + @Test + void testTypeAnnotationLocalVarTargetInfo() { + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + var label = cob.startLabel(); + assertDoesNotThrow(() -> TypeAnnotation.LocalVarTargetInfo.of(label, label, 256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.LocalVarTargetInfo.of(label, label, -1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.LocalVarTargetInfo.of(label, label, 65536)); + cob.return_(); + })); + } + + @Test + void testTypeAnnotationTypeArgumentTarget() { + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + var label = cob.startLabel(); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofTypeArgument(TypeAnnotation.TargetType.CAST, label, 0)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofCastExpr(label, -1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodInvocationTypeArgument(label, Integer.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodReferenceTypeArgument(label, 256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofConstructorInvocationTypeArgument(label, 300)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofConstructorReferenceTypeArgument(label, -2)); + cob.return_(); + })); + } } diff --git a/test/jdk/jdk/classfile/PreviewMinorVersionTest.java b/test/jdk/jdk/classfile/PreviewMinorVersionTest.java deleted file mode 100644 index 6cbff76f6d9..00000000000 --- a/test/jdk/jdk/classfile/PreviewMinorVersionTest.java +++ /dev/null @@ -1,57 +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. - */ -import java.lang.classfile.ClassFile; -import org.junit.jupiter.api.Test; - -import java.lang.constant.ClassDesc; - -import static java.lang.constant.ConstantDescs.*; -import static java.lang.classfile.ClassFile.*; -import static org.junit.jupiter.api.Assertions.*; - -/* - * @test - * @bug 8311172 - * @run junit PreviewMinorVersionTest - * @summary Ensures ClassFile.PREVIEW_MINOR_VERSION equals that of classes with - * preview minor version from ClassModel::minorVersion - */ -public class PreviewMinorVersionTest { - - @Test - public void testMinorVersionMatches() { - // compile a class with --enable-preview - // uses Record feature to trigger forcePreview - var cf = ClassFile.of(); - var cd = ClassDesc.of("Test"); - var bytes = cf.build(cd, cb -> cb - .withSuperclass(CD_Object) - // old preview minor version, - // with all bits set to 1 - .withVersion(JAVA_17_VERSION, -1) - ); - - var cm = ClassFile.of().parse(bytes); - assertEquals(ClassFile.PREVIEW_MINOR_VERSION, cm.minorVersion()); - } -} diff --git a/test/jdk/jdk/classfile/SubIntValidationTest.java b/test/jdk/jdk/classfile/SubIntValidationTest.java new file mode 100644 index 00000000000..b455948c4c8 --- /dev/null +++ b/test/jdk/jdk/classfile/SubIntValidationTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.classfile.ClassFile; +import java.lang.classfile.ClassFileVersion; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.MethodParameterInfo; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleExportInfo; +import java.lang.classfile.attribute.ModuleOpenInfo; +import java.lang.classfile.attribute.ModuleRequireInfo; +import java.lang.classfile.attribute.ModuleResolutionAttribute; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.constant.ClassDesc; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.JAVA_17_VERSION; +import static java.lang.constant.ConstantDescs.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* + * @test + * @bug 8311172 8361614 + * @summary Testing ClassFile validation of non-instruction subint (u1, u2) arguments. + * @run junit SubIntValidationTest + */ +class SubIntValidationTest { + + @Test + public void testBuilderFlags() { + ClassFile.of().build(CD_Void, clb -> { + assertThrows(IllegalArgumentException.class, () -> clb.withFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> clb.withFlags(70000)); + assertThrows(IllegalArgumentException.class, () -> clb.withField("test", CD_String, -1)); + assertThrows(IllegalArgumentException.class, () -> clb.withField("test", CD_String, 70000)); + assertThrows(IllegalArgumentException.class, () -> clb.withMethod("test", MTD_void, -1, _ -> {})); + assertThrows(IllegalArgumentException.class, () -> clb.withMethod("test", MTD_void, 70000, _ -> {})); + clb.withField("test", CD_String, fb -> { + assertThrows(IllegalArgumentException.class, () -> fb.withFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> fb.withFlags(70000 | ACC_STATIC)); + }); + clb.withMethod("test", MTD_void, ACC_STATIC, mb -> { + assertThrows(IllegalArgumentException.class, () -> mb.withFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> mb.withFlags(70000 | ACC_STATIC)); + }); + }); + } + + @Test + public void testClassFileVersion() { + // Prohibited but representable major/minor + assertDoesNotThrow(() -> ClassFileVersion.of(0, 0)); + // Non-representable major/minor + assertDoesNotThrow(() -> ClassFileVersion.of(JAVA_17_VERSION, 42)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(-1, 0)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(65536, 0)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(0, -2)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(0, 65536)); + ClassFile.of().build(CD_Void, clb -> assertThrows(IllegalArgumentException.class, () -> clb.withVersion(-1, 0))); + // Special rule without serializing to class file format + assertEquals(ClassFile.PREVIEW_MINOR_VERSION, ClassFileVersion.of(0, -1).minorVersion()); + } + + @Test + public void testReadMinorVersion() { + var cf = ClassFile.of(); + var cd = ClassDesc.of("Test"); + var bytes = cf.build(cd, cb -> cb + .withSuperclass(CD_Object) + // old preview minor version, + // with all bits set to 1 + .withVersion(JAVA_17_VERSION, -1) + ); + + var cm = ClassFile.of().parse(bytes); + assertEquals(ClassFile.PREVIEW_MINOR_VERSION, cm.minorVersion()); + } + + // LocalVarTargetInfo/TypeArgumentTarget in InstructionValidationTest for Label + @Test + public void testTypeAnnotations() { + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofTypeParameter(TypeAnnotation.TargetType.CLASS_TYPE_PARAMETER, 0)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassTypeParameter(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodTypeParameter(300)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofClassExtends(65535)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassExtends(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassExtends(65536)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofClassTypeParameterBound(255, 255)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassTypeParameterBound(-1, 255)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodTypeParameterBound(0, 256)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(0)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(256)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofThrows(256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofThrows(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofThrows(65536)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofExceptionParameter(256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofExceptionParameter(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofExceptionParameter(65536)); + assertDoesNotThrow(() -> TypeAnnotation.TypePathComponent.of(TypeAnnotation.TypePathComponent.Kind.ARRAY, 2)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TypePathComponent.of(TypeAnnotation.TypePathComponent.Kind.INNER_TYPE, -1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TypePathComponent.of(TypeAnnotation.TypePathComponent.Kind.TYPE_ARGUMENT, 256)); + } + + @Test + public void testInnerClasses() { + assertDoesNotThrow(() -> InnerClassInfo.of(CD_Object, Optional.empty(), Optional.empty(), 65535)); + assertThrows(IllegalArgumentException.class, () -> InnerClassInfo.of(CD_Object, Optional.empty(), Optional.empty(), -1)); + assertThrows(IllegalArgumentException.class, () -> InnerClassInfo.of(ConstantPoolBuilder.of().classEntry(CD_String), + Optional.empty(), Optional.empty(), 65536)); + } + + @Test + public void testMethodParameter() { + assertDoesNotThrow(() -> MethodParameterInfo.of(Optional.empty(), 65535)); + assertThrows(IllegalArgumentException.class, () -> MethodParameterInfo.of(Optional.empty(), -1)); + assertThrows(IllegalArgumentException.class, () -> MethodParameterInfo.ofParameter(Optional.empty(), 65536)); + } + + @Test + public void testModule() { + assertDoesNotThrow(() -> ModuleAttribute.of(ConstantPoolBuilder.of().moduleEntry(ModuleDesc.of("java.base")), + 65535, null, List.of(), List.of(), List.of(), List.of(), List.of())); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(ConstantPoolBuilder.of().moduleEntry(ModuleDesc.of("java.base")), + -1, null, List.of(), List.of(), List.of(), List.of(), List.of())); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(ConstantPoolBuilder.of().moduleEntry(ModuleDesc.of("java.base")), + 65536, null, List.of(), List.of(), List.of(), List.of(), List.of())); + ModuleAttribute.of(ModuleDesc.of("java.base"), b -> { + assertThrows(IllegalArgumentException.class, () -> b.moduleFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> b.moduleFlags(65536)); + b.moduleFlags(0); + }); + } + + @Test + public void testModuleExport() { + assertDoesNotThrow(() -> ModuleExportInfo.of(PackageDesc.of("java.lang"), 0)); + assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(PackageDesc.of("java.lang"), -1)); + assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(PackageDesc.of("java.lang"), 65536)); + } + + @Test + public void testModuleOpen() { + assertDoesNotThrow(() -> ModuleOpenInfo.of(PackageDesc.of("java.lang"), 0)); + assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(PackageDesc.of("java.lang"), -1)); + assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(PackageDesc.of("java.lang"), 65536)); + } + + @Test + public void testModuleRequire() { + assertDoesNotThrow(() -> ModuleRequireInfo.of(ModuleDesc.of("java.base"), 0, null)); + assertThrows(IllegalArgumentException.class, () -> ModuleRequireInfo.of(ModuleDesc.of("java.base"), -1, null)); + assertThrows(IllegalArgumentException.class, () -> ModuleRequireInfo.of(ModuleDesc.of("java.base"), 65536, null)); + } + + @Test + public void testModuleResolution() { + assertDoesNotThrow(() -> ModuleResolutionAttribute.of(256)); + assertThrows(IllegalArgumentException.class, () -> ModuleResolutionAttribute.of(-1)); + assertThrows(IllegalArgumentException.class, () -> ModuleResolutionAttribute.of(65536)); + } + + @Test + public void testMethodHandleEntry() { + ConstantPoolBuilder cp = ConstantPoolBuilder.of(); + var ref = cp.fieldRefEntry(CD_String, "a", CD_int); + // Intentionally choose an invalid but representable refKind + assertDoesNotThrow(() -> cp.methodHandleEntry(25, ref)); + assertThrows(IllegalArgumentException.class, () -> cp.methodHandleEntry(256, ref)); + assertThrows(IllegalArgumentException.class, () -> cp.methodHandleEntry(-1, ref)); + } +} From d594ef3a3e013b84a392b6d64a54015adc8173cd Mon Sep 17 00:00:00 2001 From: David Holmes Date: Fri, 29 Aug 2025 16:31:13 +0000 Subject: [PATCH 049/295] 8366121: Hotspot Style Guide should document conventions for lock-free code Reviewed-by: stefank, ayang, jsjolen, jwaters, kvn, kbarrett --- doc/hotspot-style.html | 10 ++++++++++ doc/hotspot-style.md | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index dafd29d6f54..88ec07475fd 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -209,6 +209,16 @@ lines of code. Name what you must repeat.

      attribute, the change should be done with a "setter" accessor matched to the simple "getter".

      +

      Conventions for Lock-free +Code

      +

      Sometimes variables are accessed concurrently without appropriate +synchronization context, such as a held mutex or at a safepoint. In such +cases the variable should be declared volatile and it +should NOT be accessed as a normal C++ lvalue. Rather, access should be +performed via functions from Atomic, such as +Atomic::load, Atomic::store, etc.

      +

      This special formulation makes it more clear to maintainers that the +variable is accessed concurrently in a lock-free manner.

      Source Files

      • All source files must have a globally unique basename. The build diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 0a0089ee454..322bdc8458e 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -135,6 +135,17 @@ lines of code. Name what you must repeat. change should be done with a "setter" accessor matched to the simple "getter". +#### Conventions for Lock-free Code + +Sometimes variables are accessed concurrently without appropriate synchronization +context, such as a held mutex or at a safepoint. In such cases the variable should +be declared `volatile` and it should NOT be accessed as a normal C++ lvalue. Rather, +access should be performed via functions from `Atomic`, such as `Atomic::load`, +`Atomic::store`, etc. + +This special formulation makes it more clear to maintainers that the variable is +accessed concurrently in a lock-free manner. + ### Source Files * All source files must have a globally unique basename. The build From 849570a94a3178da7899e5cd36400ef03ad9ae29 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Fri, 29 Aug 2025 17:04:37 +0000 Subject: [PATCH 050/295] 8365288: PEMDecoder should throw ClassCastException Reviewed-by: weijun --- .../classes/java/security/PEMDecoder.java | 8 ++--- .../jdk/java/security/PEM/PEMDecoderTest.java | 30 +++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/security/PEMDecoder.java b/src/java.base/share/classes/java/security/PEMDecoder.java index 7279e75cc98..0b959bf2440 100644 --- a/src/java.base/share/classes/java/security/PEMDecoder.java +++ b/src/java.base/share/classes/java/security/PEMDecoder.java @@ -437,12 +437,12 @@ public final class PEMDecoder { so = getKeyFactory(key.getAlgorithm()) .getKeySpec(key, X509EncodedKeySpec.class); } else { - throw new IllegalArgumentException("Invalid KeySpec."); + throw new ClassCastException("Invalid KeySpec"); } } catch (InvalidKeySpecException e) { - throw new IllegalArgumentException("Invalid KeySpec " + - "specified (" + tClass.getName() +") for key (" + - key.getClass().getName() +")", e); + throw new ClassCastException("Invalid KeySpec " + + "specified: " + tClass.getName() + " for key " + + key.getClass().getName()); } } diff --git a/test/jdk/java/security/PEM/PEMDecoderTest.java b/test/jdk/java/security/PEM/PEMDecoderTest.java index 90d67af2f8d..8e3ae76994d 100644 --- a/test/jdk/java/security/PEM/PEMDecoderTest.java +++ b/test/jdk/java/security/PEM/PEMDecoderTest.java @@ -25,7 +25,7 @@ /* * @test - * @bug 8298420 + * @bug 8298420 8365288 * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util @@ -78,7 +78,9 @@ public class PEMDecoderTest { System.out.println("Decoder test rsapub PEM asking X509EKS.class returned:"); testClass(PEMData.rsapub, X509EncodedKeySpec.class, true); System.out.println("Decoder test rsapriv PEM asking X509EKS.class returned:"); - testClass(PEMData.rsapriv, X509EncodedKeySpec.class, false); + testClass(PEMData.rsapriv, X509EncodedKeySpec.class, false, ClassCastException.class); + System.out.println("Decoder test rsapriv PEM asking other EKS returned:"); + testClass(PEMData.rsapriv, XEKS.class, false, ClassCastException.class); System.out.println("Decoder test RSAcert PEM asking X509EKS.class returned:"); testClass(PEMData.rsaCert, X509EncodedKeySpec.class, false); System.out.println("Decoder test OAS RFC PEM asking PrivateKey.class returned:"); @@ -484,6 +486,19 @@ public class PEMDecoderTest { } } + static void testClass(PEMData.Entry entry, Class clazz, boolean pass, + Class ec) throws RuntimeException { + try { + testClass(entry, clazz); + } catch (Exception e) { + if (ec.isInstance(e)) { + System.out.println("PASS"); + return; + } + throw new RuntimeException(e); + } + } + // Run test with a given Entry static void testDERCheck(PEMData.Entry entry) { if (entry.name().equals("rsaOpenSSL") || // PKCS1 data @@ -573,4 +588,15 @@ public class PEMDecoderTest { throw new AssertionError(e); } } + + class XEKS extends EncodedKeySpec { + public XEKS(byte[] encodedKey) { + super(encodedKey); + } + + @Override + public String getFormat() { + return ""; + } + } } \ No newline at end of file From d4ce630cea267e746f7feb5124fe2ecd39d7e13a Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 29 Aug 2025 20:44:09 +0000 Subject: [PATCH 051/295] 8366399: Allow custom base reference for update_copyright_year.sh Reviewed-by: erikj --- make/scripts/update_copyright_year.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/make/scripts/update_copyright_year.sh b/make/scripts/update_copyright_year.sh index 578ab4cbc99..fa7989d234b 100644 --- a/make/scripts/update_copyright_year.sh +++ b/make/scripts/update_copyright_year.sh @@ -62,17 +62,22 @@ Help() echo "options:" echo "-c Specifies the company. Set to Oracle by default." echo "-y Specifies the copyright year. Set to current year by default." + echo "-b Specifies the base reference for change set lookup." echo "-f Updates the copyright for all change sets in a given year," - echo " as specified by -y." + echo " as specified by -y. Overrides -b flag." echo "-h Print this help." echo } full_year=false +base_reference=master # Process options -while getopts "c:fhy:" option; do +while getopts "b:c:fhy:" option; do case $option in + b) # supplied base reference + base_reference=${OPTARG} + ;; c) # supplied company year company=${OPTARG} ;; @@ -111,7 +116,7 @@ else if [ "$full_year" = "true" ]; then vcs_list_changesets=(git log --no-merges --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") else - vcs_list_changesets=(git log --no-merges 'master..HEAD' --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") + vcs_list_changesets=(git log --no-merges "${base_reference}..HEAD" --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") fi vcs_changeset_message=(git log -1 --pretty=tformat:"%B") # followed by ${changeset} vcs_changeset_files=(git diff-tree --no-commit-id --name-only -r) # followed by ${changeset} From f23c150709fbd6d9b84261a7c99b67d7d08334b9 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sat, 30 Aug 2025 02:20:44 +0000 Subject: [PATCH 052/295] 8366359: Test should throw SkippedException when there is no lpstat Reviewed-by: aivanov, prr --- .../CountPrintServices.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java b/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java index 5be9f0297d2..4da1ed59a27 100644 --- a/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java +++ b/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,21 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import javax.print.PrintService; import javax.print.PrintServiceLookup; -import javax.print.attribute.AttributeSet; -import javax.print.attribute.HashAttributeSet; -import javax.print.attribute.standard.PrinterName; +import java.io.IOException; + +import jtreg.SkippedException; /* * @test * @bug 8032693 * @key printer + * @library /test/lib/ + * @requires (os.family == "linux") * @summary Test that lpstat and JDK agree whether there are printers. */ public class CountPrintServices { public static void main(String[] args) throws Exception { - String os = System.getProperty("os.name").toLowerCase(); - System.out.println("OS is " + os); - if (!os.equals("linux")) { - System.out.println("Linux specific test. No need to continue"); - return; - } PrintService services[] = PrintServiceLookup.lookupPrintServices(null, null); if (services.length > 0) { @@ -51,7 +47,16 @@ public class CountPrintServices { return; } String[] lpcmd = { "lpstat", "-a" }; - Process proc = Runtime.getRuntime().exec(lpcmd); + Process proc; + try { + proc = Runtime.getRuntime().exec(lpcmd); + } catch (IOException e) { + if (e.getMessage().contains("No such file or directory")) { + throw new SkippedException("Cannot find lpstat"); + } else { + throw e; + } + } proc.waitFor(); InputStreamReader ir = new InputStreamReader(proc.getInputStream()); BufferedReader br = new BufferedReader(ir); @@ -66,4 +71,3 @@ public class CountPrintServices { } } } - From 0e7399318b6c33c03a72ed1fdfb671f8cd9342a3 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Sat, 30 Aug 2025 14:03:56 +0000 Subject: [PATCH 053/295] 8366264: tools/javac/launcher/SourceLauncherStackTraceTest.java does not cover the scenario for 8362237 Reviewed-by: cstein, jlahoda --- .../SourceLauncherStackTraceTest.java | 84 ------------------- .../javac/launcher/SourceLauncherTest.java | 24 ++++++ 2 files changed, 24 insertions(+), 84 deletions(-) delete mode 100644 test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java diff --git a/test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java b/test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java deleted file mode 100644 index 7bcb86bde46..00000000000 --- a/test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * 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 8362237 - * @summary Test source launcher with specific VM behaviors - * @library /tools/lib - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.launcher - * jdk.compiler/com.sun.tools.javac.main - * java.base/jdk.internal.module - * @build toolbox.JavaTask toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox - * @run main/othervm -XX:-StackTraceInThrowable SourceLauncherStackTraceTest - */ - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -import toolbox.TestRunner; - -/// SourceLauncherTest runs the source launcher in the same VM, so we must -/// use another test to run specific tests with specific VM flags -public class SourceLauncherStackTraceTest extends TestRunner { - - // Inheritance will shadow all parent tests - SourceLauncherTest parent = new SourceLauncherTest(); - - SourceLauncherStackTraceTest() { - super(System.err); - } - - public static void main(String... args) throws Exception { - SourceLauncherStackTraceTest t = new SourceLauncherStackTraceTest(); - t.runTests(m -> new Object[] { Paths.get(m.getName()) }); - } - - /* - * Tests in which main throws an exception without a stacktrace. - */ - @Test - public void testTargetException2(Path base) throws IOException { - parent.tb.writeJavaFiles(base, """ - public class TestLauncher { - public static TestLauncher test() { - throw new RuntimeException("No trace"); - } - - public static void main(String[] args) { - // This will throw a RuntimeException without - // a stack trace due to VM options - test(); - } - } - """); - Path file = base.resolve("TestLauncher.java"); - SourceLauncherTest.Result r = parent.run(file, List.of(), List.of("3")); - parent.checkEmpty("stdout", r.stdOut()); - parent.checkEmpty("stderr", r.stdErr()); - parent.checkTrace("exception", r.exception(), "java.lang.RuntimeException: No trace"); - } -} diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index bb5ba7e133f..6b147d32d00 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8192920 8204588 8246774 8248843 8268869 8235876 8328339 8335896 8344706 + * 8362237 * @summary Test source launcher * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -714,6 +715,29 @@ public class SourceLauncherTest extends TestRunner { "at Thrower.main(Thrower.java:4)"); } + /* + * Tests in which main throws a traceless exception. + */ + @Test + public void testTracelessTargetException(Path base) throws IOException { + tb.writeJavaFiles(base, """ + class TestLauncherException extends RuntimeException { + TestLauncherException() { + super("No trace", null, true, false); // No writable trace + } + + public static void main(String... args) { + throw new TestLauncherException(); + } + } + """); + Path file = base.resolve("TestLauncherException.java"); + SourceLauncherTest.Result r = run(file, List.of(), List.of("3")); + checkEmpty("stdout", r.stdOut()); + checkEmpty("stderr", r.stdErr()); + checkTrace("exception", r.exception(), "TestLauncherException: No trace"); + } + @Test public void testNoDuplicateIncubatorWarning(Path base) throws Exception { Path module = base.resolve("lib"); From 12e6a0b6d0086caf156cf5513a604320c619b856 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 30 Aug 2025 19:26:45 +0000 Subject: [PATCH 054/295] 8366208: Unexpected exception in sun.java2d.cmm.lcms.LCMSImageLayout Reviewed-by: aivanov, prr --- .../sun/java2d/cmm/lcms/LCMSImageLayout.java | 22 ++- .../FilterSemiCustomImages.java | 162 ++++++++++++++++++ 2 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index cfe488fee72..663e11ff172 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ final class LCMSImageLayout { static LCMSImageLayout createImageLayout(BufferedImage image) { LCMSImageLayout l = new LCMSImageLayout(); - switch (image.getType()) { + Raster raster = image.getRaster(); + int type = image.getType(); + switch (type) { case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB: l.pixelType = PT_ARGB_8 ^ SWAP_ENDIAN; break; @@ -164,7 +166,7 @@ final class LCMSImageLayout { return null; } } - return createImageLayout(image.getRaster(), cm); + return createImageLayout(raster, cm); } return null; } @@ -172,11 +174,13 @@ final class LCMSImageLayout { l.width = image.getWidth(); l.height = image.getHeight(); - switch (image.getType()) { + switch (type) { case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE, BufferedImage.TYPE_INT_BGR -> { - var intRaster = (IntegerComponentRaster) image.getRaster(); + if (!(raster instanceof IntegerComponentRaster intRaster)) { + return null; + } l.nextRowOffset = safeMult(4, intRaster.getScanlineStride()); l.nextPixelOffset = safeMult(4, intRaster.getPixelStride()); l.offset = safeMult(4, intRaster.getDataOffset(0)); @@ -188,7 +192,9 @@ final class LCMSImageLayout { BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE -> { - var byteRaster = (ByteComponentRaster) image.getRaster(); + if (!(raster instanceof ByteComponentRaster byteRaster)) { + return null; + } l.nextRowOffset = byteRaster.getScanlineStride(); l.nextPixelOffset = byteRaster.getPixelStride(); int firstBand = byteRaster.getSampleModel().getNumBands() - 1; @@ -198,7 +204,9 @@ final class LCMSImageLayout { l.dataType = DT_BYTE; } case BufferedImage.TYPE_USHORT_GRAY -> { - var shortRaster = (ShortComponentRaster) image.getRaster(); + if (!(raster instanceof ShortComponentRaster shortRaster)) { + return null; + } l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride()); l.nextPixelOffset = safeMult(2, shortRaster.getPixelStride()); l.offset = safeMult(2, shortRaster.getDataOffset(0)); diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java new file mode 100644 index 00000000000..ff3fcde7482 --- /dev/null +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java @@ -0,0 +1,162 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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.awt.Color; +import java.awt.Point; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; +import java.awt.image.ColorModel; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.io.File; + +import javax.imageio.ImageIO; + +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; +import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY; + +/** + * @test + * @bug 8366208 + * @summary Verifies ColorConvertOp works correctly with BufferedImage and + * semi-custom raster + */ +public final class FilterSemiCustomImages { + + private static final int W = 144; + private static final int H = 123; + + private static final int[] TYPES = { + TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE, + TYPE_USHORT_GRAY + }; + + private static final int[] CSS = { + ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB, + ColorSpace.CS_PYCC, ColorSpace.CS_sRGB + }; + + private static final class CustomRaster extends WritableRaster { + CustomRaster(SampleModel sampleModel, Point origin) { + super(sampleModel, origin); + } + } + + public static void main(String[] args) throws Exception { + for (int fromIndex : CSS) { + for (int toIndex : CSS) { + if (fromIndex != toIndex) { + for (int type : TYPES) { + test(fromIndex, toIndex, type); + } + } + } + } + } + + private static void test(int fromIndex, int toIndex, int type) + throws Exception + { + ColorSpace fromCS = ColorSpace.getInstance(fromIndex); + ColorSpace toCS = ColorSpace.getInstance(toIndex); + ColorConvertOp op = new ColorConvertOp(fromCS, toCS, null); + + // standard source -> standard dst + BufferedImage srcGold = new BufferedImage(W, H, type); + fill(srcGold); + BufferedImage dstGold = new BufferedImage(W, H, type); + op.filter(srcGold, dstGold); + + // custom source -> standard dst + BufferedImage srcCustom = makeCustomBI(srcGold); + fill(srcCustom); + BufferedImage dst = new BufferedImage(W, H, type); + op.filter(srcCustom, dst); + verify(dstGold, dst); + + // standard source -> custom dst + BufferedImage src = new BufferedImage(W, H, type); + fill(src); + BufferedImage dstCustom = makeCustomBI(dstGold); + op.filter(src, dstCustom); + verify(dstGold, dstCustom); + + // custom source -> custom dst + srcCustom = makeCustomBI(srcGold); + fill(srcCustom); + dstCustom = makeCustomBI(dstGold); + op.filter(srcCustom, dstCustom); + verify(dstGold, dstCustom); + } + + private static BufferedImage makeCustomBI(BufferedImage bi) { + ColorModel cm = bi.getColorModel(); + SampleModel sm = bi.getSampleModel(); + CustomRaster cr = new CustomRaster(sm, new Point()); + return new BufferedImage(cm, cr, bi.isAlphaPremultiplied(), null) { + @Override + public int getType() { + return bi.getType(); + } + }; + } + + private static void fill(BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + // alpha channel may be calculated slightly differently on + // different code paths, so only check fully transparent and + // fully opaque pixels + Color c = new Color(y * 255 / (height - 1), + x * 255 / (width - 1), + x % 255, + (x % 2 == 0) ? 0 : 255); + image.setRGB(x, y, c.getRGB()); + } + } + } + + private static void verify(BufferedImage dstGold, BufferedImage dst) + throws Exception + { + for (int x = 0; x < W; ++x) { + for (int y = 0; y < H; ++y) { + if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) { + ImageIO.write(dst, "png", new File("custom.png")); + ImageIO.write(dstGold, "png", new File("gold.png")); + throw new RuntimeException("Test failed."); + } + } + } + } +} From 9339a6a23236e783e93f967cf6aba16c2f749fdd Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 31 Aug 2025 00:35:09 +0000 Subject: [PATCH 055/295] 8361593: Commented dead code in JDK-8342868 can be removed Reviewed-by: jlu, naoto, jwaters, jpai --- .../libjava/HostLocaleProviderAdapter_md.c | 16 +++++----------- .../windows/native/libjava/TimeZone_md.c | 3 --- .../windows/native/libnet/NTLMAuthSequence.c | 2 -- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c index 10513b28cb6..bf399a68894 100644 --- a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c @@ -965,34 +965,28 @@ void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) { DWORD pattern = 0; int style = numberStyle; - // int got = 0; if (positive) { if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } } else { if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_INEGCURR | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } else { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } diff --git a/src/java.base/windows/native/libjava/TimeZone_md.c b/src/java.base/windows/native/libjava/TimeZone_md.c index 0a73bc26028..5adecff50e7 100644 --- a/src/java.base/windows/native/libjava/TimeZone_md.c +++ b/src/java.base/windows/native/libjava/TimeZone_md.c @@ -232,7 +232,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) WCHAR stdNameInReg[MAX_ZONE_CHAR]; TziValue tempTzi; WCHAR *stdNamePtr = tzi.StandardName; - // int onlyMapID; timeType = GetTimeZoneInformation(&tzi); if (timeType == TIME_ZONE_ID_INVALID) { @@ -304,7 +303,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) * Compare to the "Std" value of each subkey and find the entry that * matches the current control panel setting. */ - // onlyMapID = 0; for (i = 0; i < nSubKeys; ++i) { DWORD size = sizeof(subKeyName); ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL); @@ -325,7 +323,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) * entry in the Time Zones registry. */ RegCloseKey(hSubKey); - // onlyMapID = 1; ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey); if (ret != ERROR_SUCCESS) { goto err; diff --git a/src/java.base/windows/native/libnet/NTLMAuthSequence.c b/src/java.base/windows/native/libnet/NTLMAuthSequence.c index 62627504ecd..507409e0ae6 100644 --- a/src/java.base/windows/native/libnet/NTLMAuthSequence.c +++ b/src/java.base/windows/native/libnet/NTLMAuthSequence.c @@ -47,8 +47,6 @@ static jfieldID ntlm_ctxHandleID; static jfieldID ntlm_crdHandleID; static jfieldID status_seqCompleteID; -// static HINSTANCE lib = NULL; - JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_initFirst (JNIEnv *env, jclass authseq_clazz, jclass status_clazz) { From bdc39818ce7b3c3bad10f4682a2a52fbb696f247 Mon Sep 17 00:00:00 2001 From: Anass Baya Date: Sun, 31 Aug 2025 04:34:04 +0000 Subject: [PATCH 056/295] 8361521: BogusFocusableWindowState.java fails with StackOverflowError on Linux Reviewed-by: aivanov, serb --- src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java | 6 ++++-- test/jdk/ProblemList.txt | 1 - .../BogusFocusableWindowState.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index f2b7efc978f..4911dea5d97 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -1098,9 +1098,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, suppressWmTakeFocus(true); } } - updateFocusability(); - promoteDefaultPosition(); boolean refreshChildsTransientFor = isVisible() != vis; + if (refreshChildsTransientFor) { + updateFocusability(); + } + promoteDefaultPosition(); super.setVisible(vis); if (refreshChildsTransientFor) { for (Window child : ((Window) target).getOwnedWindows()) { diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1193ea45ba7..58fb2c51397 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -119,7 +119,6 @@ java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java 8081489 generi java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java 6849364 generic-all java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 generic-all java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all -java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java 8361521 linux-all java/awt/Frame/MaximizedToMaximized/MaximizedToMaximized.java 8340374 macosx-all java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all diff --git a/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java b/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java index 64621796b4f..efcb9c098f0 100644 --- a/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java +++ b/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java @@ -25,7 +25,7 @@ import java.awt.Window; /** * @test - * @bug 8346952 + * @bug 8346952 8361521 * @summary Verifies no exception occurs when triggering updateCG() * for an ownerless window. * @key headful From 80ab094a75a6474c33214e3347e08ea7b9177ec8 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 31 Aug 2025 21:34:16 +0000 Subject: [PATCH 057/295] 8347707: Standardise the use of os::snprintf and os::snprintf_checked Reviewed-by: kbarrett, fbredberg --- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 4 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 24 ++++++------ .../cpu/aarch64/vm_version_aarch64.cpp | 6 +-- src/hotspot/cpu/arm/macroAssembler_arm.cpp | 2 +- src/hotspot/cpu/arm/vm_version_arm_32.cpp | 4 +- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 4 +- src/hotspot/cpu/s390/vm_version_s390.cpp | 4 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 4 +- src/hotspot/cpu/zero/frame_zero.cpp | 30 +++++++-------- src/hotspot/cpu/zero/vm_version_zero.cpp | 4 +- src/hotspot/os/aix/attachListener_aix.cpp | 15 ++++---- src/hotspot/os/aix/os_aix.cpp | 8 ++-- src/hotspot/os/aix/porting_aix.cpp | 5 +-- src/hotspot/os/bsd/memMapPrinter_macosx.cpp | 2 +- src/hotspot/os/bsd/os_bsd.cpp | 38 +++++++++---------- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 4 +- src/hotspot/os/linux/os_linux.cpp | 38 +++++++++---------- src/hotspot/os/linux/os_perf_linux.cpp | 2 +- src/hotspot/os/posix/attachListener_posix.cpp | 15 ++++---- src/hotspot/os/posix/os_posix.cpp | 2 +- src/hotspot/os/posix/perfMemory_posix.cpp | 4 +- src/hotspot/os/windows/os_windows.cpp | 18 ++++----- src/hotspot/os/windows/perfMemory_windows.cpp | 6 +-- .../linux_riscv/vm_version_linux_riscv.cpp | 2 +- src/hotspot/share/ci/ciEnv.cpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 19 ++++++---- src/hotspot/share/code/codeHeapState.cpp | 2 +- .../compiler/compilationMemoryStatistic.cpp | 4 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 24 ++++++------ src/hotspot/share/gc/shared/oopStorage.cpp | 2 +- src/hotspot/share/gc/shared/satbMarkQueue.cpp | 4 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 2 +- src/hotspot/share/oops/compressedKlass.cpp | 8 ++-- src/hotspot/share/oops/generateOopMap.cpp | 4 +- src/hotspot/share/opto/idealGraphPrinter.cpp | 8 ++-- src/hotspot/share/runtime/os.cpp | 11 +++--- src/hotspot/share/runtime/os.hpp | 18 ++++++--- src/hotspot/share/services/heapDumper.cpp | 2 +- .../share/utilities/forbiddenFunctions.hpp | 1 + .../share/utilities/virtualizationSupport.cpp | 4 +- .../gtest/classfile/test_symbolTable.cpp | 6 +-- test/hotspot/gtest/gtestMain.cpp | 2 +- test/hotspot/gtest/logging/test_asynclog.cpp | 2 +- .../hotspot/gtest/runtime/test_os_windows.cpp | 2 +- 46 files changed, 195 insertions(+), 183 deletions(-) diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index db72218d6d7..aff50b9cf2f 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -702,10 +702,10 @@ static void printbc(Method *m, intptr_t bcx) { if (m->validate_bci_from_bcp((address)bcx) < 0 || !m->contains((address)bcx)) { name = "???"; - snprintf(buf, sizeof buf, "(bad)"); + os::snprintf_checked(buf, sizeof buf, "(bad)"); } else { int bci = m->bci_from((address)bcx); - snprintf(buf, sizeof buf, "%d", bci); + os::snprintf_checked(buf, sizeof buf, "%d", bci); name = Bytecodes::name(m->code_at(bci)); } ResourceMark rm; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index fb307c8831a..3999beeec2b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2259,7 +2259,7 @@ void MacroAssembler::movptr(Register r, uintptr_t imm64) { #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64); block_comment(buffer); } #endif @@ -2317,7 +2317,7 @@ void MacroAssembler::mov_immediate64(Register dst, uint64_t imm64) #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX64, imm64); block_comment(buffer); } #endif @@ -2430,7 +2430,7 @@ void MacroAssembler::mov_immediate32(Register dst, uint32_t imm32) #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIX32, imm32); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX32, imm32); block_comment(buffer); } #endif @@ -2902,11 +2902,11 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack, FpPushPopMode m { char buffer[48]; if (mode == PushPopSVE) { - snprintf(buffer, sizeof(buffer), "push_fp: %d SVE registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d SVE registers", count); } else if (mode == PushPopNeon) { - snprintf(buffer, sizeof(buffer), "push_fp: %d Neon registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d Neon registers", count); } else { - snprintf(buffer, sizeof(buffer), "push_fp: %d fp registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d fp registers", count); } block_comment(buffer); } @@ -3014,11 +3014,11 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack, FpPushPopMode mo { char buffer[48]; if (mode == PushPopSVE) { - snprintf(buffer, sizeof(buffer), "pop_fp: %d SVE registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d SVE registers", count); } else if (mode == PushPopNeon) { - snprintf(buffer, sizeof(buffer), "pop_fp: %d Neon registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d Neon registers", count); } else { - snprintf(buffer, sizeof(buffer), "pop_fp: %d fp registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d fp registers", count); } block_comment(buffer); } @@ -5920,7 +5920,7 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, { const char kind = (elem_size == 2) ? 'U' : 'L'; char comment[64]; - snprintf(comment, sizeof comment, "array_equals%c{", kind); + os::snprintf_checked(comment, sizeof comment, "array_equals%c{", kind); BLOCK_COMMENT(comment); } #endif @@ -6118,7 +6118,7 @@ void MacroAssembler::string_equals(Register a1, Register a2, #ifndef PRODUCT { char comment[64]; - snprintf(comment, sizeof comment, "{string_equalsL"); + os::snprintf_checked(comment, sizeof comment, "{string_equalsL"); BLOCK_COMMENT(comment); } #endif @@ -6266,7 +6266,7 @@ address MacroAssembler::zero_words(Register base, uint64_t cnt) #ifndef PRODUCT { char buf[64]; - snprintf(buf, sizeof buf, "zero_words (count = %" PRIu64 ") {", cnt); + os::snprintf_checked(buf, sizeof buf, "zero_words (count = %" PRIu64 ") {", cnt); BLOCK_COMMENT(buf); } #endif diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 24c77174711..308deeaf5e2 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -721,12 +721,12 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64"); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64"); - int desc_len = snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); + int desc_len = os::snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); desc_len = (int)strlen(_cpu_desc); - snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string); + os::snprintf_checked(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index e101e5631d9..12462e1843c 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -839,7 +839,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, char buffer[64]; #ifdef COMPILER1 if (CommentedAssembly) { - snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset()); + os::snprintf_checked(buffer, sizeof(buffer), "verify_oop at %d", offset()); block_comment(buffer); } #endif diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index d0941936035..209dc41035c 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -362,7 +362,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index ec2766ac75b..1d2b8d3ca04 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -625,7 +625,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string()); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b4d286cabbf..1436bc02113 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2679,7 +2679,7 @@ void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset, Register #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIx64, uimm64); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIx64, uimm64); block_comment(buffer); } #endif diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 46324815001..4b437896dcd 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -493,8 +493,8 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string()); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index ed925aa23b4..7f5b4870aab 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -1549,7 +1549,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string()); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 058ea06ab4e..6eb641daaf9 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4331,10 +4331,10 @@ void StubGenerator::generate_compiler_stubs() { if (libsimdsort != nullptr) { log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "simdsort" JNI_LIB_SUFFIX, p2i(libsimdsort)); - snprintf(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_sort" : "avx2_sort"); + os::snprintf_checked(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_sort" : "avx2_sort"); StubRoutines::_array_sort = (address)os::dll_lookup(libsimdsort, ebuf_); - snprintf(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_partition" : "avx2_partition"); + os::snprintf_checked(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_partition" : "avx2_partition"); StubRoutines::_array_partition = (address)os::dll_lookup(libsimdsort, ebuf_); } } diff --git a/src/hotspot/cpu/zero/frame_zero.cpp b/src/hotspot/cpu/zero/frame_zero.cpp index 4b4bd1e2b87..52ccad2fa68 100644 --- a/src/hotspot/cpu/zero/frame_zero.cpp +++ b/src/hotspot/cpu/zero/frame_zero.cpp @@ -242,8 +242,8 @@ void frame::zero_print_on_error(int frame_index, int offset = fp() - addr; // Fill in default values, then try and improve them - snprintf(fieldbuf, buflen, "word[%d]", offset); - snprintf(valuebuf, buflen, PTR_FORMAT, *addr); + os::snprintf_checked(fieldbuf, buflen, "word[%d]", offset); + os::snprintf_checked(valuebuf, buflen, PTR_FORMAT, *addr); zeroframe()->identify_word(frame_index, offset, fieldbuf, valuebuf, buflen); fieldbuf[buflen - 1] = '\0'; valuebuf[buflen - 1] = '\0'; @@ -300,7 +300,7 @@ void EntryFrame::identify_word(int frame_index, break; default: - snprintf(fieldbuf, buflen, "local[%d]", offset - 3); + os::snprintf_checked(fieldbuf, buflen, "local[%d]", offset - 3); } } @@ -321,12 +321,12 @@ void InterpreterFrame::identify_word(int frame_index, istate->method()->name_and_sig_as_C_string(valuebuf, buflen); } else if (is_valid && !strcmp(field, "_bcp") && istate->bcp()) { - snprintf(valuebuf, buflen, PTR_FORMAT " (bci %d)", - (intptr_t) istate->bcp(), - istate->method()->bci_from(istate->bcp())); + os::snprintf_checked(valuebuf, buflen, PTR_FORMAT " (bci %d)", + (intptr_t) istate->bcp(), + istate->method()->bci_from(istate->bcp())); } - snprintf(fieldbuf, buflen, "%sistate->%s", - field[strlen(field) - 1] == ')' ? "(": "", field); + os::snprintf_checked(fieldbuf, buflen, "%sistate->%s", + field[strlen(field) - 1] == ')' ? "(": "", field); } else if (addr == (intptr_t *) istate) { strncpy(fieldbuf, "(vtable for istate)", buflen); @@ -358,13 +358,13 @@ void InterpreterFrame::identify_word(int frame_index, else desc = " (this)"; } - snprintf(fieldbuf, buflen, "parameter[%d]%s", param, desc); + os::snprintf_checked(fieldbuf, buflen, "parameter[%d]%s", param, desc); return; } for (int i = 0; i < handler->argument_count(); i++) { if (params[i] == (intptr_t) addr) { - snprintf(fieldbuf, buflen, "unboxed parameter[%d]", i); + os::snprintf_checked(fieldbuf, buflen, "unboxed parameter[%d]", i); return; } } @@ -396,18 +396,18 @@ void ZeroFrame::identify_vp_word(int frame_index, intptr_t offset = (intptr_t) addr - monitor; if (offset == in_bytes(BasicObjectLock::obj_offset())) - snprintf(fieldbuf, buflen, "monitor[%d]->_obj", index); + os::snprintf_checked(fieldbuf, buflen, "monitor[%d]->_obj", index); else if (offset == in_bytes(BasicObjectLock::lock_offset())) - snprintf(fieldbuf, buflen, "monitor[%d]->_lock", index); + os::snprintf_checked(fieldbuf, buflen, "monitor[%d]->_lock", index); return; } // Expression stack if (addr < stack_base) { - snprintf(fieldbuf, buflen, "%s[%d]", - frame_index == 0 ? "stack_word" : "local", - (int) (stack_base - addr - 1)); + os::snprintf_checked(fieldbuf, buflen, "%s[%d]", + frame_index == 0 ? "stack_word" : "local", + (int) (stack_base - addr - 1)); return; } } diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index 3ce9227c193..35cbd296a26 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -150,7 +150,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/os/aix/attachListener_aix.cpp b/src/hotspot/os/aix/attachListener_aix.cpp index e5101814f97..58de062a2fd 100644 --- a/src/hotspot/os/aix/attachListener_aix.cpp +++ b/src/hotspot/os/aix/attachListener_aix.cpp @@ -209,10 +209,10 @@ int AixAttachListener::init() { ::atexit(listener_cleanup); } - int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); + int n = os::snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); if (n < (int)UNIX_PATH_MAX) { - n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); + n = os::snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); } if (n >= (int)UNIX_PATH_MAX) { return -1; @@ -349,9 +349,8 @@ void AttachListener::vm_start() { struct stat st; int ret; - int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); + os::snprintf_checked(fn, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { @@ -419,8 +418,8 @@ bool AttachListener::is_init_trigger() { RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); - snprintf(fn, sizeof(fn), "%s/.attach_pid%d", - os::get_temp_directory(), os::current_process_id()); + os::snprintf_checked(fn, sizeof(fn), "%s/.attach_pid%d", + os::get_temp_directory(), os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 25a930dc1d9..c58e240719b 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1051,8 +1051,8 @@ static void* dll_load_library(const char *filename, int *eno, char *ebuf, int eb error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s, LIBPATH=%s, LD_LIBRARY_PATH=%s : %s", - filename, ::getenv("LIBPATH"), ::getenv("LD_LIBRARY_PATH"), error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s, LIBPATH=%s, LD_LIBRARY_PATH=%s : %s", + filename, ::getenv("LIBPATH"), ::getenv("LD_LIBRARY_PATH"), error_report); } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); @@ -1077,7 +1077,7 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { STATIC_ASSERT(sizeof(old_extension) >= sizeof(new_extension)); char* tmp_path = os::strdup(filename); size_t prefix_size = pointer_delta(pointer_to_dot, filename, 1); - os::snprintf(tmp_path + prefix_size, sizeof(old_extension), "%s", new_extension); + os::snprintf_checked(tmp_path + prefix_size, sizeof(old_extension), "%s", new_extension); result = dll_load_library(tmp_path, &eno, ebuf, ebuflen); os::free(tmp_path); } @@ -1094,7 +1094,7 @@ void os::get_summary_os_info(char* buf, size_t buflen) { // There might be something more readable than uname results for AIX. struct utsname name; uname(&name); - snprintf(buf, buflen, "%s %s", name.release, name.version); + os::snprintf_checked(buf, buflen, "%s %s", name.release, name.version); } int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index 2235d3da686..402abd7d579 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -936,7 +936,7 @@ static const char* rtv_linkedin_libpath() { // retrieve the path to the currently running executable binary // to open it - snprintf(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); + os::snprintf_checked(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); FILE* f = nullptr; struct xcoffhdr the_xcoff; struct scnhdr the_scn; @@ -1154,7 +1154,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s", error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report); } assert(false, "os::pd_dll_unload() ::dlclose() failed"); } @@ -1189,4 +1189,3 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { return res; } // end: os::pd_dll_unload() - diff --git a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp index ee76214ddfa..a7ddab04d85 100644 --- a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp +++ b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp @@ -177,7 +177,7 @@ public: X1(GENEALOGY, genealogy); default: static char buffer[30]; - snprintf(buffer, sizeof(buffer), "user_tag=0x%x(%d)", user_tag, user_tag); + os::snprintf_checked(buffer, sizeof(buffer), "user_tag=0x%x(%d)", user_tag, user_tag); return buffer; } } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b7b88e8e606..6ef43ba991e 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -522,7 +522,7 @@ void os::init_system_properties_values() { // by the nulls included by the sizeof operator (so actually one byte more // than necessary is allocated). os::snprintf_checked(buf, bufsize, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, - user_home_dir, Arguments::get_java_home()); + user_home_dir, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); FREE_C_HEAP_ARRAY(char, buf); @@ -1242,27 +1242,27 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } if (lib_arch.endianess != arch_array[running_arch_index].endianess) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); return nullptr; } #ifndef S390 if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: architecture word width mismatch)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1," (Possible cause: architecture word width mismatch)"); return nullptr; } #endif // !S390 if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { if (lib_arch.name!=nullptr) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load %s-bit .so on a %s-bit platform)", - lib_arch.name, arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load %s-bit .so on a %s-bit platform)", + lib_arch.name, arch_array[running_arch_index].name); } else { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load this .so (machine code=0x%x) on a %s-bit platform)", - lib_arch.code, - arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load this .so (machine code=0x%x) on a %s-bit platform)", + lib_arch.code, + arch_array[running_arch_index].name); } } @@ -1364,13 +1364,13 @@ void os::get_summary_os_info(char* buf, size_t buflen) { size = sizeof(build); int mib_build[] = { CTL_KERN, KERN_OSVERSION }; if (sysctl(mib_build, 2, build, &size, nullptr, 0) < 0) { - snprintf(buf, buflen, "%s %s, macOS %s", os, release, osproductversion); + os::snprintf_checked(buf, buflen, "%s %s, macOS %s", os, release, osproductversion); } else { - snprintf(buf, buflen, "%s %s, macOS %s (%s)", os, release, osproductversion, build); + os::snprintf_checked(buf, buflen, "%s %s, macOS %s (%s)", os, release, osproductversion, build); } } else #endif - snprintf(buf, buflen, "%s %s", os, release); + os::snprintf_checked(buf, buflen, "%s %s", os, release); } void os::print_os_info_brief(outputStream* st) { @@ -1447,14 +1447,14 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { #if defined(__APPLE__) && !defined(ZERO) if (VM_Version::is_cpu_emulated()) { - snprintf(buf, buflen, "\"%s\" %s (EMULATED) %d MHz", model, machine, mhz); + os::snprintf_checked(buf, buflen, "\"%s\" %s (EMULATED) %d MHz", model, machine, mhz); } else { - NOT_AARCH64(snprintf(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz)); + NOT_AARCH64(os::snprintf_checked(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz)); // aarch64 CPU doesn't report its speed - AARCH64_ONLY(snprintf(buf, buflen, "\"%s\" %s", model, machine)); + AARCH64_ONLY(os::snprintf_checked(buf, buflen, "\"%s\" %s", model, machine)); } #else - snprintf(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz); + os::snprintf_checked(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz); #endif } @@ -2156,7 +2156,7 @@ void os::set_native_thread_name(const char *name) { if (name != nullptr) { // Add a "Java: " prefix to the name char buf[MAXTHREADNAMESIZE]; - snprintf(buf, sizeof(buf), "Java: %s", name); + (void) os::snprintf(buf, sizeof(buf), "Java: %s", name); pthread_setname_np(buf); } #endif @@ -2490,7 +2490,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s", error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report); } } diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index c33e49b57f9..84dfcbd6614 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -204,7 +204,7 @@ int ZPhysicalMemoryBacking::create_mem_fd(const char* name) const { // Create file name char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s%s", name, ZLargePages::is_explicit() ? ".hugetlb" : ""); + os::snprintf_checked(filename, sizeof(filename), "%s%s", name, ZLargePages::is_explicit() ? ".hugetlb" : ""); // Create file const int extra_flags = ZLargePages::is_explicit() ? (MFD_HUGETLB | MFD_HUGE_2MB) : 0; @@ -262,7 +262,7 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const { // Create file name char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id()); + os::snprintf_checked(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id()); // Create file const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 4d6225cf21e..cee8a11b1d2 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1848,32 +1848,32 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { if (lib_arch.name != nullptr) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load %s .so on a %s platform)", - lib_arch.name, arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load %s .so on a %s platform)", + lib_arch.name, arch_array[running_arch_index].name); } else { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", - lib_arch.code, arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", + lib_arch.code, arch_array[running_arch_index].name); } return nullptr; } if (lib_arch.endianness != arch_array[running_arch_index].endianness) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: endianness mismatch)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: endianness mismatch)"); return nullptr; } // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); return nullptr; } if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", - (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", + (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); return nullptr; } @@ -2613,10 +2613,10 @@ static void print_sys_devices_cpu_info(outputStream* st) { char hbuf_type[60]; char hbuf_size[60]; char hbuf_coherency_line_size[80]; - snprintf(hbuf_level, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/level", i); - snprintf(hbuf_type, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/type", i); - snprintf(hbuf_size, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/size", i); - snprintf(hbuf_coherency_line_size, 80, "/sys/devices/system/cpu/cpu0/cache/index%u/coherency_line_size", i); + os::snprintf_checked(hbuf_level, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/level", i); + os::snprintf_checked(hbuf_type, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/type", i); + os::snprintf_checked(hbuf_size, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/size", i); + os::snprintf_checked(hbuf_coherency_line_size, 80, "/sys/devices/system/cpu/cpu0/cache/index%u/coherency_line_size", i); if (os::file_exists(hbuf_level)) { _print_ascii_file_h("cache level", hbuf_level, st); _print_ascii_file_h("cache type", hbuf_type, st); @@ -4217,7 +4217,7 @@ int os::Linux::get_namespace_pid(int vmid) { char fname[24]; int retpid = -1; - snprintf(fname, sizeof(fname), "/proc/%d/status", vmid); + os::snprintf_checked(fname, sizeof(fname), "/proc/%d/status", vmid); FILE *fp = os::fopen(fname, "r"); if (fp) { @@ -4797,7 +4797,7 @@ uint os::processor_id() { void os::set_native_thread_name(const char *name) { if (Linux::_pthread_setname_np) { char buf [16]; // according to glibc manpage, 16 chars incl. '/0' - snprintf(buf, sizeof(buf), "%s", name); + (void) os::snprintf(buf, sizeof(buf), "%s", name); buf[sizeof(buf) - 1] = '\0'; const int rc = Linux::_pthread_setname_np(pthread_self(), buf); // ERANGE should not happen; all other errors should just be ignored. @@ -5008,7 +5008,7 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { long ldummy; FILE *fp; - snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid); + os::snprintf_checked(proc_name, 64, "/proc/self/task/%d/stat", tid); fp = os::fopen(proc_name, "r"); if (fp == nullptr) return -1; statlen = fread(stat, 1, 2047, fp); @@ -5394,7 +5394,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s", error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report); } } diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index ea7535edb87..9151049dd1c 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -988,7 +988,7 @@ NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const { char buf[128]; - snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter); + os::snprintf_checked(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter); int fd = os::open(buf, O_RDONLY, 0); if (fd == -1) { diff --git a/src/hotspot/os/posix/attachListener_posix.cpp b/src/hotspot/os/posix/attachListener_posix.cpp index a4bc49c6bf3..d3e24807124 100644 --- a/src/hotspot/os/posix/attachListener_posix.cpp +++ b/src/hotspot/os/posix/attachListener_posix.cpp @@ -195,10 +195,10 @@ int PosixAttachListener::init() { ::atexit(listener_cleanup); } - int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); + int n = os::snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); if (n < (int)UNIX_PATH_MAX) { - n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); + n = os::snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); } if (n >= (int)UNIX_PATH_MAX) { return -1; @@ -346,9 +346,8 @@ void AttachListener::vm_start() { struct stat st; int ret; - int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); + os::snprintf_checked(fn, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { @@ -418,8 +417,8 @@ bool AttachListener::is_init_trigger() { RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); - snprintf(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), - os::current_process_id()); + os::snprintf_checked(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), + os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1ece8260948..6a39c95db52 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -323,7 +323,7 @@ int os::create_file_for_heap(const char* dir) { vm_exit_during_initialization(err_msg("Malloc failed during creation of backing file for heap (%s)", os::strerror(errno))); return -1; } - int n = snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); + int n = os::snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); assert((size_t)n == fullname_len, "Unexpected number of characters in string"); os::native_path(fullname); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index cbbecea3a6a..c58f216b2c3 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -150,7 +150,7 @@ static char* get_user_tmp_dir(const char* user, int vmid, int nspid) { char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); // construct the path name to user specific tmp directory - snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user); + os::snprintf_checked(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user); return dirname; } @@ -661,7 +661,7 @@ static char* get_sharedmem_filename(const char* dirname, int vmid, int nspid) { size_t nbytes = strlen(dirname) + UINT_CHARS + 2; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - snprintf(name, nbytes, "%s/%d", dirname, pid); + os::snprintf_checked(name, nbytes, "%s/%d", dirname, pid); return name; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index ffa22bd0365..27bf196075a 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1411,7 +1411,7 @@ void os::die() { void os::dll_unload(void *lib) { char name[MAX_PATH]; if (::GetModuleFileName((HMODULE)lib, name, sizeof(name)) == 0) { - snprintf(name, MAX_PATH, ""); + os::snprintf_checked(name, MAX_PATH, ""); } JFR_ONLY(NativeLibraryUnloadEvent unload_event(name);) @@ -1427,7 +1427,7 @@ void os::dll_unload(void *lib) { Events::log_dll_message(nullptr, "Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode); log_info(os)("Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode); if (tl == 0) { - os::snprintf(buf, sizeof(buf), "Attempt to unload dll failed (error code %d)", (int) errcode); + os::snprintf_checked(buf, sizeof(buf), "Attempt to unload dll failed (error code %d)", (int) errcode); } JFR_ONLY(unload_event.set_error_msg(buf);) } @@ -1824,14 +1824,14 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { } if (lib_arch_str != nullptr) { - os::snprintf(ebuf, ebuflen - 1, - "Can't load %s-bit .dll on a %s-bit platform", - lib_arch_str, running_arch_str); + os::snprintf_checked(ebuf, ebuflen - 1, + "Can't load %s-bit .dll on a %s-bit platform", + lib_arch_str, running_arch_str); } else { // don't know what architecture this dll was build for - os::snprintf(ebuf, ebuflen - 1, - "Can't load this .dll (machine code=0x%x) on a %s-bit platform", - lib_arch, running_arch_str); + os::snprintf_checked(ebuf, ebuflen - 1, + "Can't load this .dll (machine code=0x%x) on a %s-bit platform", + lib_arch, running_arch_str); } JFR_ONLY(load_event.set_error_msg(ebuf);) return nullptr; @@ -3198,7 +3198,7 @@ int os::create_file_for_heap(const char* dir) { vm_exit_during_initialization(err_msg("Malloc failed during creation of backing file for heap (%s)", os::strerror(errno))); return -1; } - int n = snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); + int n = os::snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); assert((size_t)n == fullname_len, "Unexpected number of characters in string"); os::native_path(fullname); diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index 273814f6572..a9b2eebb7be 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -164,7 +164,7 @@ static char* get_user_tmp_dir(const char* user) { char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); // construct the path name to user specific tmp directory - os::snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user); + os::snprintf_checked(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user); return dirname; } @@ -454,7 +454,7 @@ static char *get_sharedmem_objectname(const char* user, int vmid) { // nbytes += UINT_CHARS; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - os::snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid); + os::snprintf_checked(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid); return name; } @@ -470,7 +470,7 @@ static char* get_sharedmem_filename(const char* dirname, int vmid) { size_t nbytes = strlen(dirname) + UINT_CHARS + 2; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - os::snprintf(name, nbytes, "%s\\%d", dirname, vmid); + os::snprintf_checked(name, nbytes, "%s\\%d", dirname, vmid); return name; } diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 506c78cacca..cf9429b6bea 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -126,7 +126,7 @@ void VM_Version::setup_cpu_available_features() { char buf[1024] = {}; if (uarch != nullptr && strcmp(uarch, "") != 0) { // Use at max half the buffer. - snprintf(buf, sizeof(buf)/2, "%s ", uarch); + os::snprintf_checked(buf, sizeof(buf)/2, "%s ", uarch); } os::free((void*) uarch); diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 2de77f2828d..79ab881e7f6 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -217,7 +217,7 @@ public: void push_va(ciEnv* ci, const char* fmt, va_list args) { char *e = ci->_dyno_name + strlen(ci->_dyno_name); char *m = ci->_dyno_name + ARRAY_SIZE(ci->_dyno_name) - 1; - os::vsnprintf(e, m - e, fmt, args); + (void) os::vsnprintf(e, m - e, fmt, args); assert(strlen(ci->_dyno_name) < (ARRAY_SIZE(ci->_dyno_name) - 1), "overflow"); } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 20534b93290..bf678f94e0e 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -2619,14 +2619,16 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m char* buf = NEW_RESOURCE_ARRAY(char, buf_size); // Print stack trace line in buffer - size_t buf_off = os::snprintf_checked(buf, buf_size, "\tat %s.%s(", klass_name, method_name); - + int buf_off = os::snprintf(buf, buf_size, "\tat %s.%s(", klass_name, method_name); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); // Print module information if (module_name != nullptr) { if (module_version != nullptr) { - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s@%s/", module_name, module_version); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s@%s/", module_name, module_version); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } else { - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s/", module_name); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s/", module_name); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } } @@ -2641,13 +2643,16 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m } else { if (source_file_name != nullptr && (line_number != -1)) { // Sourcename and linenumber - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s:%d)", source_file_name, line_number); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s:%d)", source_file_name, line_number); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } else if (source_file_name != nullptr) { // Just sourcename - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s)", source_file_name); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s)", source_file_name); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } else { // Neither sourcename nor linenumber - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "Unknown Source)"); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "Unknown Source)"); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } nmethod* nm = method->code(); if (WizardMode && nm != nullptr) { diff --git a/src/hotspot/share/code/codeHeapState.cpp b/src/hotspot/share/code/codeHeapState.cpp index 065aab5c250..ea4a1519f79 100644 --- a/src/hotspot/share/code/codeHeapState.cpp +++ b/src/hotspot/share/code/codeHeapState.cpp @@ -739,7 +739,7 @@ void CodeHeapState::aggregate(outputStream* out, CodeHeap* heap, size_t granular if (jvmci_name != nullptr) { size_t size = ::strlen(blob_name) + ::strlen(" jvmci_name=") + ::strlen(jvmci_name) + 1; char* new_blob_name = (char*)os::malloc(size, mtInternal); - os::snprintf(new_blob_name, size, "%s jvmci_name=%s", blob_name, jvmci_name); + os::snprintf_checked(new_blob_name, size, "%s jvmci_name=%s", blob_name, jvmci_name); os::free((void*)blob_name); blob_name = new_blob_name; } diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index d842bcb2b6f..d22eab8ac55 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -158,10 +158,10 @@ void FootprintTimeline::print_on(outputStream* st) const { st->print("%24s", e.info.text); col += 25; st->fill_to(col); char tmp[64]; - os::snprintf(tmp, sizeof(tmp), "%9zu (%+zd)", e._bytes.cur, e._bytes.end_delta()); + os::snprintf_checked(tmp, sizeof(tmp), "%9zu (%+zd)", e._bytes.cur, e._bytes.end_delta()); st->print("%s ", tmp); // end col += 21; st->fill_to(col); - os::snprintf(tmp, sizeof(tmp), "%6u (%+d)", e._live_nodes.cur, e._live_nodes.end_delta()); + os::snprintf_checked(tmp, sizeof(tmp), "%6u (%+d)", e._live_nodes.cur, e._live_nodes.end_delta()); st->print("%s ", tmp); // end if (e._bytes.temporary_peak_size() > significant_peak_threshold) { col += 20; st->fill_to(col); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 04197495033..f73c4099ce6 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -81,19 +81,19 @@ class G1YoungGCTraceTime { evacuation_failed_string[0] = '\0'; if (_collector->evacuation_failed()) { - snprintf(evacuation_failed_string, - ARRAY_SIZE(evacuation_failed_string), - " (Evacuation Failure: %s%s%s)", - _collector->evacuation_alloc_failed() ? "Allocation" : "", - _collector->evacuation_alloc_failed() && _collector->evacuation_pinned() ? " / " : "", - _collector->evacuation_pinned() ? "Pinned" : ""); + os::snprintf_checked(evacuation_failed_string, + ARRAY_SIZE(evacuation_failed_string), + " (Evacuation Failure: %s%s%s)", + _collector->evacuation_alloc_failed() ? "Allocation" : "", + _collector->evacuation_alloc_failed() && _collector->evacuation_pinned() ? " / " : "", + _collector->evacuation_pinned() ? "Pinned" : ""); } - snprintf(_young_gc_name_data, - MaxYoungGCNameLength, - "Pause Young (%s) (%s)%s", - G1GCPauseTypeHelper::to_string(_pause_type), - GCCause::to_string(_pause_cause), - evacuation_failed_string); + os::snprintf_checked(_young_gc_name_data, + MaxYoungGCNameLength, + "Pause Young (%s) (%s)%s", + G1GCPauseTypeHelper::to_string(_pause_type), + GCCause::to_string(_pause_cause), + evacuation_failed_string); return _young_gc_name_data; } diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index ae3e9c46197..d36e9850bda 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -820,7 +820,7 @@ static Mutex* make_oopstorage_mutex(const char* storage_name, const char* kind, Mutex::Rank rank) { char name[256]; - os::snprintf(name, sizeof(name), "%s %s lock", storage_name, kind); + os::snprintf_checked(name, sizeof(name), "%s %s lock", storage_name, kind); return new PaddedMutex(rank, name); } diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp index 915eaa116fb..3cba3baf5f1 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp @@ -306,7 +306,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { int i = 0; while (nd != nullptr) { void** buf = BufferNode::make_buffer_from_node(nd); - os::snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i); + os::snprintf_checked(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i); print_satb_buffer(buffer, buf, nd->index(), nd->capacity()); nd = nd->next(); i += 1; @@ -321,7 +321,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { _qset(qset), _buffer(buffer) {} virtual void do_thread(Thread* t) { - os::snprintf(_buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name()); + (void) os::snprintf(_buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name()); _qset->satb_queue_for_thread(t).print(_buffer); } } closure(this, buffer); diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 23473940178..d8287dad198 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -934,7 +934,7 @@ void JVMCIEnv::fthrow_error(const char* file, int line, const char* format, ...) va_list ap; va_start(ap, format); char msg[max_msg_size]; - os::vsnprintf(msg, max_msg_size, format, ap); + (void) os::vsnprintf(msg, max_msg_size, format, ap); va_end(ap); JavaThread* THREAD = JavaThread::current(); if (is_hotspot()) { diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index 25e80b0a975..d7c97d3c8d5 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -78,10 +78,10 @@ void CompressedKlassPointers::pre_initialize() { void CompressedKlassPointers::sanity_check_after_initialization() { // In expectation of an assert, prepare condensed info to be printed with the assert. char tmp[256]; - os::snprintf(tmp, sizeof(tmp), "klass range: " RANGE2FMT "," - " base " PTR_FORMAT ", shift %d, lowest/highest valid narrowKlass %u/%u", - RANGE2FMTARGS(_klass_range_start, _klass_range_end), - p2i(_base), _shift, _lowest_valid_narrow_klass_id, _highest_valid_narrow_klass_id); + os::snprintf_checked(tmp, sizeof(tmp), "klass range: " RANGE2FMT "," + " base " PTR_FORMAT ", shift %d, lowest/highest valid narrowKlass %u/%u", + RANGE2FMTARGS(_klass_range_start, _klass_range_end), + p2i(_base), _shift, _lowest_valid_narrow_klass_id, _highest_valid_narrow_klass_id); #define ASSERT_HERE(cond) assert(cond, " (%s)", tmp); #define ASSERT_HERE_2(cond, msg) assert(cond, msg " (%s)", tmp); diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index a17d1ca4e37..97d8bf3d526 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -2150,10 +2150,10 @@ bool GenerateOopMap::compute_map(Thread* current) { void GenerateOopMap::error_work(const char *format, va_list ap) { _got_error = true; char msg_buffer[512]; - os::vsnprintf(msg_buffer, sizeof(msg_buffer), format, ap); + (void) os::vsnprintf(msg_buffer, sizeof(msg_buffer), format, ap); // Append method name char msg_buffer2[512]; - os::snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg_buffer, method()->name()->as_C_string()); + (void) os::snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg_buffer, method()->name()->as_C_string()); Thread* current = Thread::current(); if (current->can_call_java()) { _exception = Exceptions::new_exception(JavaThread::cast(current), diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 1ecb46eaf5a..cbf972166c2 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -640,8 +640,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { jint value = typeInt->get_con(); // Only use up to 4 chars and fall back to a generic "I" to keep it short. - int written_chars = os::snprintf_checked(buffer, sizeof(buffer), "%d", value); - if (written_chars <= 4) { + int written_chars = os::snprintf(buffer, sizeof(buffer), "%d", value); + if (written_chars > 0 && written_chars <= 4) { print_prop(short_name, buffer); } else { print_prop(short_name, "I"); @@ -654,8 +654,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { jlong value = typeLong->get_con(); // Only use up to 4 chars and fall back to a generic "L" to keep it short. - int written_chars = os::snprintf_checked(buffer, sizeof(buffer), JLONG_FORMAT, value); - if (written_chars <= 4) { + int written_chars = os::snprintf(buffer, sizeof(buffer), JLONG_FORMAT, value); + if (written_chars > 0 && written_chars <= 4) { print_prop(short_name, buffer); } else { print_prop(short_name, "L"); diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 04a363a7aab..e02d13edb8e 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -108,23 +108,24 @@ int os::snprintf(char* buf, size_t len, const char* fmt, ...) { return result; } -int os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { +void os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { va_list args; va_start(args, fmt); int result = os::vsnprintf(buf, len, fmt, args); va_end(args); - assert(result >= 0, "os::snprintf error"); assert(static_cast(result) < len, "os::snprintf truncated"); - return result; } int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { + assert(buf != nullptr || len == 0, "Valid buffer and length must be given"); + assert(fmt != nullptr, "Missing format string"); int result = permit_forbidden_function::vsnprintf(buf, len, fmt, args); - // If an encoding error occurred (result < 0) then it's not clear + // If an error occurred (result < 0) then it's not clear // whether the buffer is NUL terminated, so ensure it is. - if ((result < 0) && (len > 0)) { + if ((result < 0) && (len > 0) && (buf != nullptr)) { buf[len - 1] = '\0'; } + assert(result >= 0, "os::vsnprintf error: %s", strerror(errno)); return result; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index c34bf77e3d6..6d40a646358 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -804,12 +804,20 @@ class os: AllStatic { // Provide wrapper versions of these functions to guarantee NUL-termination // in all cases. - static int vsnprintf(char* buf, size_t len, const char* fmt, va_list args) ATTRIBUTE_PRINTF(3, 0); - static int snprintf(char* buf, size_t len, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4); - // Performs snprintf and asserts the result is non-negative (so there was not - // an encoding error) and that the output was not truncated. - static int snprintf_checked(char* buf, size_t len, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4); + // Performs vsnprintf and asserts the result is non-negative (so there was not + // an encoding error or any other kind of usage error). + [[nodiscard]] + ATTRIBUTE_PRINTF(3, 0) + static int vsnprintf(char* buf, size_t len, const char* fmt, va_list args); + // Delegates to vsnprintf. + [[nodiscard]] + ATTRIBUTE_PRINTF(3, 4) + static int snprintf(char* buf, size_t len, const char* fmt, ...); + + // Delegates to snprintf and asserts that the output was not truncated. + ATTRIBUTE_PRINTF(3, 4) + static void snprintf_checked(char* buf, size_t len, const char* fmt, ...); // Get host name in buffer provided static bool get_host_name(char* buf, size_t buflen); diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 051096ae24a..cd679986a6c 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2113,7 +2113,7 @@ char* DumpMerger::get_writer_path(const char* base_path, int seq) { char* path = NEW_RESOURCE_ARRAY(char, buf_size); memset(path, 0, buf_size); - os::snprintf(path, buf_size, "%s.p%d", base_path, seq); + os::snprintf_checked(path, buf_size, "%s.p%d", base_path, seq); return path; } diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp index 0bc34adf213..a8dcba95a6d 100644 --- a/src/hotspot/share/utilities/forbiddenFunctions.hpp +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -59,6 +59,7 @@ FORBID_IMPORTED_C_FUNCTION(char* strerror(int), "use os::strerror"); FORBID_IMPORTED_C_FUNCTION(char* strtok(char*, const char*), "use strtok_r"); FORBID_C_FUNCTION(int sprintf(char*, const char*, ...), "use os::snprintf"); +FORBID_C_FUNCTION(int snprintf(char*, size_t, const char*, ...), "use os::snprintf"); PRAGMA_DIAG_PUSH FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING diff --git a/src/hotspot/share/utilities/virtualizationSupport.cpp b/src/hotspot/share/utilities/virtualizationSupport.cpp index 5feff1039ef..c2e8a61012e 100644 --- a/src/hotspot/share/utilities/virtualizationSupport.cpp +++ b/src/hotspot/share/utilities/virtualizationSupport.cpp @@ -67,13 +67,13 @@ void VirtualizationSupport::initialize() { VMGuestLibError sg_error = GuestLib_StatGet("text", "resources", &result_info, &result_size); if (sg_error == VMGUESTLIB_ERROR_SUCCESS) { has_resource_information = true; - os::snprintf(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info); + os::snprintf_checked(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info); GuestLib_StatFree(result_info, result_size); } sg_error = GuestLib_StatGet("text", "host", &result_info, &result_size); if (sg_error == VMGUESTLIB_ERROR_SUCCESS) { has_host_information = true; - os::snprintf(host_information, sizeof(host_information), "%s", result_info); + os::snprintf_checked(host_information, sizeof(host_information), "%s", result_info); GuestLib_StatFree(result_info, result_size); } } diff --git a/test/hotspot/gtest/classfile/test_symbolTable.cpp b/test/hotspot/gtest/classfile/test_symbolTable.cpp index 57c6b85c949..02d97ca2155 100644 --- a/test/hotspot/gtest/classfile/test_symbolTable.cpp +++ b/test/hotspot/gtest/classfile/test_symbolTable.cpp @@ -105,7 +105,7 @@ TEST_VM(SymbolTable, test_symbol_refcount_parallel) { char symbol_name[symbol_name_length]; // Find a symbol where there will probably be only one instance. for (int i = 0; i < 100; i++) { - os::snprintf(symbol_name, symbol_name_length, "some_symbol%d", i); + os::snprintf_checked(symbol_name, symbol_name_length, "some_symbol%d", i); TempNewSymbol ts = SymbolTable::new_symbol(symbol_name); if (ts->refcount() == 1) { EXPECT_TRUE(ts->refcount() == 1) << "Symbol is just created"; @@ -158,7 +158,7 @@ TEST_VM(SymbolTable, test_cleanup_delay) { constexpr int symbol_name_length = 30; char symbol_name[symbol_name_length]; for (uint i = 1; i < TempSymbolCleanupDelayer::QueueSize; i++) { - os::snprintf(symbol_name, symbol_name_length, "temp-filler-%d", i); + os::snprintf_checked(symbol_name, symbol_name_length, "temp-filler-%d", i); TempNewSymbol s = SymbolTable::new_symbol(symbol_name); ASSERT_EQ(s->refcount(), 2) << "TempNewSymbol refcount just created is 2"; } @@ -177,7 +177,7 @@ TEST_VM(SymbolTable, test_cleanup_delay_drain) { char symbol_name[symbol_name_length]; TempNewSymbol symbols[TempSymbolCleanupDelayer::QueueSize] = {}; for (uint i = 0; i < TempSymbolCleanupDelayer::QueueSize; i++) { - os::snprintf(symbol_name, symbol_name_length, "temp-%d", i); + os::snprintf_checked(symbol_name, symbol_name_length, "temp-%d", i); TempNewSymbol s = SymbolTable::new_symbol(symbol_name); symbols[i] = s; } diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index c593f8dbb19..842b6547b48 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -256,7 +256,7 @@ static void runUnitTestsInner(int argc, char** argv) { #ifdef __APPLE__ size_t len = strlen(java_home) + strlen("/lib/jli/libjli.dylib") + 1; char* path = new char[len]; - snprintf(path, len, "%s/lib/jli/libjli.dylib", java_home); + os::snprintf_checked(path, len, "%s/lib/jli/libjli.dylib", java_home); dlopen(path, RTLD_NOW | RTLD_GLOBAL); #endif // __APPLE__ diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index efd4027fa3f..fdc3795e9db 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -163,7 +163,7 @@ TEST_VM_F(AsyncLogTest, logBuffer) { LogDecorators()); size_t len = strlen(TestLogFileName) + strlen(LogFileOutput::Prefix) + 1; char* name = NEW_C_HEAP_ARRAY(char, len, mtLogging); - snprintf(name, len, "%s%s", LogFileOutput::Prefix, TestLogFileName); + os::snprintf_checked(name, len, "%s%s", LogFileOutput::Prefix, TestLogFileName); LogFileStreamOutput* output = new LogFileOutput(name); output->initialize(nullptr, nullptr); diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index 83771368b57..9fe0de55515 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -376,7 +376,7 @@ static void record_path(char const* name, char const* len_name, wchar_t* path) { if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { ::testing::Test::RecordProperty(name, buf); - os::snprintf(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path)); + os::snprintf_checked(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path)); ::testing::Test::RecordProperty(len_name, buf); } } From 2427c901b31dbdccc6f8f39404875a0140460479 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 1 Sep 2025 04:03:08 +0000 Subject: [PATCH 058/295] 8366024: Remove unnecessary InstanceKlass::cast() Reviewed-by: coleenp, dholmes --- .../share/classfile/classFileParser.cpp | 16 ++--- .../share/classfile/fieldLayoutBuilder.cpp | 2 +- .../share/classfile/systemDictionary.cpp | 2 +- src/hotspot/share/classfile/vmClasses.cpp | 4 +- .../jfrEventClassTransformer.cpp | 2 +- .../jfr/leakprofiler/chains/edgeUtils.cpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 70 +++++++++---------- src/hotspot/share/oops/instanceKlass.hpp | 10 +-- src/hotspot/share/oops/klass.cpp | 14 ++-- src/hotspot/share/oops/klass.hpp | 1 - src/hotspot/share/oops/klassVtable.cpp | 39 +++++------ src/hotspot/share/oops/klassVtable.hpp | 12 ++-- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 2 +- 16 files changed, 83 insertions(+), 99 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index c678fa5e058..01e35161efd 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -4092,31 +4092,29 @@ static Array* compute_transitive_interfaces(const InstanceKlass* void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass, TRAPS) { assert(this_klass != nullptr, "invariant"); - const Klass* const super = this_klass->super(); + const InstanceKlass* const super = this_klass->java_super(); if (super != nullptr) { - const InstanceKlass* super_ik = InstanceKlass::cast(super); - if (super->is_final()) { - classfile_icce_error("class %s cannot inherit from final class %s", super_ik, THREAD); + classfile_icce_error("class %s cannot inherit from final class %s", super, THREAD); return; } - if (super_ik->is_sealed()) { + if (super->is_sealed()) { stringStream ss; ResourceMark rm(THREAD); - if (!super_ik->has_as_permitted_subclass(this_klass, ss)) { + if (!super->has_as_permitted_subclass(this_klass, ss)) { classfile_icce_error(ss.as_string(), THREAD); return; } } Reflection::VerifyClassAccessResults vca_result = - Reflection::verify_class_access(this_klass, InstanceKlass::cast(super), false); + Reflection::verify_class_access(this_klass, super, false); if (vca_result != Reflection::ACCESS_OK) { ResourceMark rm(THREAD); char* msg = Reflection::verify_class_access_msg(this_klass, - InstanceKlass::cast(super), + super, vca_result); // Names are all known to be < 64k so we know this formatted message is not excessively large. @@ -4218,7 +4216,7 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) // skip supers that don't have final methods. if (k->has_final_method()) { // lookup a matching method in the super class hierarchy - super_m = InstanceKlass::cast(k)->lookup_method(name, signature); + super_m = k->lookup_method(name, signature); if (super_m == nullptr) { break; // didn't find any match; get out } diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index 21f47e3de10..d06f5dd96d1 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -316,7 +316,7 @@ void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_instance block->set_offset(fs.offset()); all_fields->append(block); } - ik = ik->super() == nullptr ? nullptr : InstanceKlass::cast(ik->super()); + ik = ik->java_super() == nullptr ? nullptr : ik->java_super(); } assert(last_offset == -1 || last_offset > 0, "Sanity"); if (last_offset > 0 && diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 783ae9d35ba..ae7432c9fce 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1049,7 +1049,7 @@ bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle // load from the shared archive. if (ik->super() != nullptr) { - bool check_super = check_shared_class_super_type(ik, InstanceKlass::cast(ik->super()), + bool check_super = check_shared_class_super_type(ik, ik->java_super(), class_loader, true, CHECK_false); if (!check_super) { diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 813926e51a2..9b9222268a6 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -225,10 +225,10 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load } // add super and interfaces first - Klass* super = klass->super(); + InstanceKlass* super = klass->java_super(); if (super != nullptr && super->class_loader_data() == nullptr) { assert(super->is_instance_klass(), "Super should be instance klass"); - resolve_shared_class(InstanceKlass::cast(super), loader_data, domain, CHECK); + resolve_shared_class(super, loader_data, domain, CHECK); } Array* ifs = klass->local_interfaces(); diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index 5e7f65aeec1..81e8a82c78d 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -214,7 +214,7 @@ static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_t if (has_annotation(ik, annotation_type, default_value, value)) { return true; } - InstanceKlass* const super = InstanceKlass::cast(ik->super()); + InstanceKlass* const super = ik->java_super(); return super != nullptr && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, default_value, value) : false; } diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index 6a38553403d..c9d79a23c2f 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -76,7 +76,7 @@ const Symbol* EdgeUtils::field_name(const Edge& edge, jshort* modifiers) { } jfs.next(); } - ik = (const InstanceKlass*)ik->super(); + ik = ik->java_super(); } *modifiers = 0; return nullptr; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index e4900249dbd..dbc3ebd9c6e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2012,7 +2012,7 @@ C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, ARGUMENT_PAIR(kl JVMCIObjectArray interfaces = JVMCIENV->new_HotSpotResolvedObjectTypeImpl_array(size, JVMCI_CHECK_NULL); for (int index = 0; index < size; index++) { JVMCIKlassHandle klass(THREAD); - Klass* k = iklass->local_interfaces()->at(index); + InstanceKlass* k = iklass->local_interfaces()->at(index); klass = k; JVMCIObject type = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL); JVMCIENV->put_object_at(interfaces, index, type); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index dcec45ff4e2..a7641b9a546 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -575,7 +575,7 @@ void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, } void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, - const Klass* super_klass, + const InstanceKlass* super_klass, Array* local_interfaces, Array* transitive_interfaces) { // Only deallocate transitive interfaces if not empty, same as super class @@ -584,7 +584,7 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, if (ti != Universe::the_empty_instance_klass_array() && ti != local_interfaces) { // check that the interfaces don't come from super class Array* sti = (super_klass == nullptr) ? nullptr : - InstanceKlass::cast(super_klass)->transitive_interfaces(); + super_klass->transitive_interfaces(); if (ti != sti && ti != nullptr && !ti->is_shared()) { MetadataFactory::free_array(loader_data, ti); } @@ -677,7 +677,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(nullptr, SECONDARY_SUPERS_BITMAP_EMPTY); - deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); + deallocate_interfaces(loader_data, java_super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); @@ -942,7 +942,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { JavaThread* jt = THREAD; // link super class before linking this class - Klass* super_klass = super(); + InstanceKlass* super_klass = java_super(); if (super_klass != nullptr) { if (super_klass->is_interface()) { // check if super class is an interface ResourceMark rm(THREAD); @@ -957,8 +957,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { return false; } - InstanceKlass* ik_super = InstanceKlass::cast(super_klass); - ik_super->link_class_impl(CHECK_false); + super_klass->link_class_impl(CHECK_false); } // link all interfaces implemented by this class before linking this class @@ -1805,15 +1804,15 @@ bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* Klass* InstanceKlass::find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const { const int n = local_interfaces()->length(); for (int i = 0; i < n; i++) { - Klass* intf1 = local_interfaces()->at(i); + InstanceKlass* intf1 = local_interfaces()->at(i); assert(intf1->is_interface(), "just checking type"); // search for field in current interface - if (InstanceKlass::cast(intf1)->find_local_field(name, sig, fd)) { + if (intf1->find_local_field(name, sig, fd)) { assert(fd->is_static(), "interface field must be static"); return intf1; } // search for field in direct superinterfaces - Klass* intf2 = InstanceKlass::cast(intf1)->find_interface_field(name, sig, fd); + Klass* intf2 = intf1->find_interface_field(name, sig, fd); if (intf2 != nullptr) return intf2; } // otherwise field lookup fails @@ -1832,8 +1831,8 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { Klass* supr = super(); - if (supr != nullptr) return InstanceKlass::cast(supr)->find_field(name, sig, fd); + { InstanceKlass* supr = java_super(); + if (supr != nullptr) return supr->find_field(name, sig, fd); } // 4) otherwise field lookup fails return nullptr; @@ -1852,8 +1851,8 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { Klass* supr = super(); - if (supr != nullptr) return InstanceKlass::cast(supr)->find_field(name, sig, is_static, fd); + { InstanceKlass* supr = java_super(); + if (supr != nullptr) return supr->find_field(name, sig, is_static, fd); } // 4) otherwise field lookup fails return nullptr; @@ -1872,12 +1871,12 @@ bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fie bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const { - Klass* klass = const_cast(this); + const InstanceKlass* klass = this; while (klass != nullptr) { - if (InstanceKlass::cast(klass)->find_local_field_from_offset(offset, is_static, fd)) { + if (klass->find_local_field_from_offset(offset, is_static, fd)) { return true; } - klass = klass->super(); + klass = klass->java_super(); } return false; } @@ -1920,7 +1919,7 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, Handle, TRAP } void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = superklass(); + InstanceKlass* super = java_super(); if (super != nullptr) { super->do_nonstatic_fields(cl); } @@ -1937,7 +1936,7 @@ static int compare_fields_by_offset(FieldInfo* a, FieldInfo* b) { } void InstanceKlass::print_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = superklass(); + InstanceKlass* super = java_super(); if (super != nullptr) { super->print_nonstatic_fields(cl); } @@ -2232,17 +2231,17 @@ Method* InstanceKlass::uncached_lookup_method(const Symbol* name, OverpassLookupMode overpass_mode, PrivateLookupMode private_mode) const { OverpassLookupMode overpass_local_mode = overpass_mode; - const Klass* klass = this; + const InstanceKlass* klass = this; while (klass != nullptr) { - Method* const method = InstanceKlass::cast(klass)->find_method_impl(name, - signature, - overpass_local_mode, - StaticLookupMode::find, - private_mode); + Method* const method = klass->find_method_impl(name, + signature, + overpass_local_mode, + StaticLookupMode::find, + private_mode); if (method != nullptr) { return method; } - klass = klass->super(); + klass = klass->java_super(); overpass_local_mode = OverpassLookupMode::skip; // Always ignore overpass methods in superclasses } return nullptr; @@ -2252,12 +2251,12 @@ Method* InstanceKlass::uncached_lookup_method(const Symbol* name, // search through class hierarchy and return true if this class or // one of the superclasses was redefined bool InstanceKlass::has_redefined_this_or_super() const { - const Klass* klass = this; + const InstanceKlass* klass = this; while (klass != nullptr) { - if (InstanceKlass::cast(klass)->has_been_redefined()) { + if (klass->has_been_redefined()) { return true; } - klass = klass->super(); + klass = klass->java_super(); } return false; } @@ -3986,7 +3985,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, // Class hierarchy info debug_stream.print(" klass: " PTR_FORMAT " super: " PTR_FORMAT, - p2i(this), p2i(superklass())); + p2i(this), p2i(java_super())); // Interfaces if (local_interfaces() != nullptr && local_interfaces()->length() > 0) { @@ -3994,7 +3993,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, int length = local_interfaces()->length(); for (int i = 0; i < length; i++) { debug_stream.print(" " PTR_FORMAT, - p2i(InstanceKlass::cast(local_interfaces()->at(i)))); + p2i(local_interfaces()->at(i))); } } @@ -4207,19 +4206,17 @@ void InstanceKlass::oop_verify_on(oop obj, outputStream* st) { obj->oop_iterate(&blk); } - // JNIid class for jfieldIDs only // Note to reviewers: // These JNI functions are just moved over to column 1 and not changed // in the compressed oops workspace. -JNIid::JNIid(Klass* holder, int offset, JNIid* next) { +JNIid::JNIid(InstanceKlass* holder, int offset, JNIid* next) { _holder = holder; _offset = offset; _next = next; DEBUG_ONLY(_is_static_field_id = false;) } - JNIid* JNIid::find(int offset) { JNIid* current = this; while (current != nullptr) { @@ -4237,11 +4234,10 @@ void JNIid::deallocate(JNIid* current) { } } - -void JNIid::verify(Klass* holder) { +void JNIid::verify(InstanceKlass* holder) { int first_field_offset = InstanceMirrorKlass::offset_of_static_fields(); int end_field_offset; - end_field_offset = first_field_offset + (InstanceKlass::cast(holder)->static_field_size() * wordSize); + end_field_offset = first_field_offset + (holder->static_field_size() * wordSize); JNIid* current = this; while (current != nullptr) { @@ -4554,7 +4550,7 @@ void ClassHierarchyIterator::next() { } _visit_subclasses = true; // reset while (_current->next_sibling() == nullptr && _current != _root) { - _current = _current->superklass(); // backtrack; no more sibling subclasses left + _current = _current->java_super(); // backtrack; no more sibling subclasses left } if (_current == _root) { // Iteration is over (back at root after backtracking). Invalidate the iterator. diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 3c0dd84b2d2..a158494736b 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -988,7 +988,7 @@ public: static void deallocate_methods(ClassLoaderData* loader_data, Array* methods); void static deallocate_interfaces(ClassLoaderData* loader_data, - const Klass* super_klass, + const InstanceKlass* super_klass, Array* local_interfaces, Array* transitive_interfaces); void static deallocate_record_components(ClassLoaderData* loader_data, @@ -1205,7 +1205,7 @@ public: class JNIid: public CHeapObj { friend class VMStructs; private: - Klass* _holder; + InstanceKlass* _holder; JNIid* _next; int _offset; #ifdef ASSERT @@ -1214,11 +1214,11 @@ class JNIid: public CHeapObj { public: // Accessors - Klass* holder() const { return _holder; } + InstanceKlass* holder() const { return _holder; } int offset() const { return _offset; } JNIid* next() { return _next; } // Constructor - JNIid(Klass* holder, int offset, JNIid* next); + JNIid(InstanceKlass* holder, int offset, JNIid* next); // Identifier lookup JNIid* find(int offset); @@ -1232,7 +1232,7 @@ class JNIid: public CHeapObj { bool is_static_field_id() const { return _is_static_field_id; } void set_is_static_field_id() { _is_static_field_id = true; } #endif - void verify(Klass* holder); + void verify(InstanceKlass* holder); }; // An iterator that's used to access the inner classes indices in the diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 41ab8e325ab..17e2ccbc911 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -611,12 +611,6 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots, } -// superklass links -InstanceKlass* Klass::superklass() const { - assert(super() == nullptr || super()->is_instance_klass(), "must be instance klass"); - return _super == nullptr ? nullptr : InstanceKlass::cast(_super); -} - // subklass links. Used by the compiler (and vtable initialization) // May be cleaned concurrently, so must use the Compile_lock. // The log parameter is for clean_weak_klass_links to report unlinked classes. @@ -679,11 +673,11 @@ void Klass::append_to_sibling_list() { assert_locked_or_safepoint(Compile_lock); } DEBUG_ONLY(verify();) - // add ourselves to superklass' subklass list - InstanceKlass* super = superklass(); + // add ourselves to super' subklass list + InstanceKlass* super = java_super(); if (super == nullptr) return; // special case: class Object assert((!super->is_interface() // interfaces cannot be supers - && (super->superklass() == nullptr || !is_interface())), + && (super->java_super() == nullptr || !is_interface())), "an interface can only be a subklass of Object"); // Make sure there is no stale subklass head @@ -692,7 +686,7 @@ void Klass::append_to_sibling_list() { for (;;) { Klass* prev_first_subklass = Atomic::load_acquire(&_super->_subklass); if (prev_first_subklass != nullptr) { - // set our sibling to be the superklass' previous first subklass + // set our sibling to be the super' previous first subklass assert(prev_first_subklass->is_loader_alive(), "May not attach not alive klasses"); set_next_sibling(prev_first_subklass); } diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index ac382fdba98..1257f4cbcf8 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -297,7 +297,6 @@ protected: Klass* subklass(bool log = false) const; Klass* next_sibling(bool log = false) const; - InstanceKlass* superklass() const; void append_to_sibling_list(); // add newly created receiver to superklass' subklass list void set_next_link(Klass* k) { _next_link = k; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index e9da33b280e..bb47496b406 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -65,7 +65,7 @@ bool klassVtable::is_preinitialized_vtable() { // treated as any other public method in C for method over-ride purposes. void klassVtable::compute_vtable_size_and_num_mirandas( int* vtable_length_ret, int* num_new_mirandas, - GrowableArray* all_mirandas, const Klass* super, + GrowableArray* all_mirandas, const InstanceKlass* super, Array* methods, AccessFlags class_flags, u2 major_version, Handle classloader, Symbol* classname, Array* local_interfaces) { NoSafepointVerifier nsv; @@ -346,7 +346,7 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper break; } // if no override found yet, continue to search up - superk = superk->super() == nullptr ? nullptr : InstanceKlass::cast(superk->super()); + superk = superk->java_super(); } return superk; @@ -631,7 +631,7 @@ void klassVtable::initialize_vtable_and_check_constraints(TRAPS) { // However, the vtable entries are filled in at link time, and therefore // the superclass' vtable may not yet have been filled in. bool klassVtable::needs_new_vtable_entry(Method* target_method, - const Klass* super, + const InstanceKlass* super, Handle classloader, Symbol* classname, AccessFlags class_flags, @@ -683,7 +683,7 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // a new entry Symbol* name = target_method->name(); Symbol* signature = target_method->signature(); - const Klass* k = super; + const InstanceKlass* k = super; Method* super_method = nullptr; InstanceKlass *holder = nullptr; Method* recheck_method = nullptr; @@ -722,7 +722,7 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // Start with lookup result and continue to search up, for versions supporting transitive override if (major_version >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) { - k = superk->super(); // haven't found an override match yet; continue to look + k = superk->java_super(); // haven't found an override match yet; continue to look } else { break; } @@ -741,9 +741,8 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // miranda method in the super, whose entry it should re-use. // Actually, to handle cases that javac would not generate, we need // this check for all access permissions. - const InstanceKlass *sk = InstanceKlass::cast(super); - if (sk->has_miranda_methods()) { - if (sk->lookup_method_in_all_interfaces(name, signature, Klass::DefaultsLookupMode::find) != nullptr) { + if (super->has_miranda_methods()) { + if (super->lookup_method_in_all_interfaces(name, signature, Klass::DefaultsLookupMode::find) != nullptr) { return false; // found a matching miranda; we do not need a new entry } } @@ -775,7 +774,7 @@ bool klassVtable::is_miranda_entry_at(int i) { if (holder->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(holder) , "this class should implement the interface"); - if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super(), klass()->is_interface())) { + if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->java_super(), klass()->is_interface())) { return true; } } @@ -837,7 +836,7 @@ bool klassVtable::is_miranda_entry_at(int i) { // Part of the Miranda Rights in the US mean that if you do not have // an attorney one will be appointed for you. bool klassVtable::is_miranda(Method* m, Array* class_methods, - Array* default_methods, const Klass* super, + Array* default_methods, const InstanceKlass* super, bool is_interface) { if (m->is_static() || m->is_private() || m->is_overpass()) { return false; @@ -866,12 +865,11 @@ bool klassVtable::is_miranda(Method* m, Array* class_methods, // Overpasses may or may not exist for supers for pass 1, // they should have been created for pass 2 and later. - for (const Klass* cursuper = super; cursuper != nullptr; cursuper = cursuper->super()) - { - Method* found_mth = InstanceKlass::cast(cursuper)->find_local_method(name, signature, - Klass::OverpassLookupMode::find, - Klass::StaticLookupMode::skip, - Klass::PrivateLookupMode::skip); + for (const InstanceKlass* cursuper = super; cursuper != nullptr; cursuper = cursuper->java_super()) { + Method* found_mth = cursuper->find_local_method(name, signature, + Klass::OverpassLookupMode::find, + Klass::StaticLookupMode::skip, + Klass::PrivateLookupMode::skip); // Ignore non-public methods in java.lang.Object if klass is an interface. if (found_mth != nullptr && (!is_interface || !SystemDictionary::is_nonpublic_Object_method(found_mth))) { @@ -893,7 +891,7 @@ bool klassVtable::is_miranda(Method* m, Array* class_methods, void klassVtable::add_new_mirandas_to_lists( GrowableArray* new_mirandas, GrowableArray* all_mirandas, Array* current_interface_methods, Array* class_methods, - Array* default_methods, const Klass* super, bool is_interface) { + Array* default_methods, const InstanceKlass* super, bool is_interface) { // iterate thru the current interface's method to see if it a miranda int num_methods = current_interface_methods->length(); @@ -913,9 +911,8 @@ void klassVtable::add_new_mirandas_to_lists( if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable if (is_miranda(im, class_methods, default_methods, super, is_interface)) { // is it a miranda at all? - const InstanceKlass *sk = InstanceKlass::cast(super); // check if it is a duplicate of a super's miranda - if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::DefaultsLookupMode::find) == nullptr) { + if (super->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::DefaultsLookupMode::find) == nullptr) { new_mirandas->append(im); } if (all_mirandas != nullptr) { @@ -928,7 +925,7 @@ void klassVtable::add_new_mirandas_to_lists( void klassVtable::get_mirandas(GrowableArray* new_mirandas, GrowableArray* all_mirandas, - const Klass* super, + const InstanceKlass* super, Array* class_methods, Array* default_methods, Array* local_interfaces, @@ -962,7 +959,7 @@ void klassVtable::get_mirandas(GrowableArray* new_mirandas, int klassVtable::fill_in_mirandas(Thread* current, int initialized) { ResourceMark rm(current); GrowableArray mirandas(20); - get_mirandas(&mirandas, nullptr, ik()->super(), ik()->methods(), + get_mirandas(&mirandas, nullptr, ik()->java_super(), ik()->methods(), ik()->default_methods(), ik()->local_interfaces(), klass()->is_interface()); for (int i = 0; i < mirandas.length(); i++) { diff --git a/src/hotspot/share/oops/klassVtable.hpp b/src/hotspot/share/oops/klassVtable.hpp index 3bd07a9143e..b8635e7f14b 100644 --- a/src/hotspot/share/oops/klassVtable.hpp +++ b/src/hotspot/share/oops/klassVtable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ class klassVtable { static void compute_vtable_size_and_num_mirandas(int* vtable_length, int* num_new_mirandas, GrowableArray* all_mirandas, - const Klass* super, + const InstanceKlass* super, Array* methods, AccessFlags class_flags, u2 major_version, @@ -116,7 +116,7 @@ class klassVtable { int initialize_from_super(Klass* super); void put_method_at(Method* m, int index); static bool needs_new_vtable_entry(Method* m, - const Klass* super, + const InstanceKlass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, @@ -135,7 +135,7 @@ class klassVtable { bool is_miranda_entry_at(int i); int fill_in_mirandas(Thread* current, int initialized); static bool is_miranda(Method* m, Array* class_methods, - Array* default_methods, const Klass* super, + Array* default_methods, const InstanceKlass* super, bool is_interface); static void add_new_mirandas_to_lists( GrowableArray* new_mirandas, @@ -143,12 +143,12 @@ class klassVtable { Array* current_interface_methods, Array* class_methods, Array* default_methods, - const Klass* super, + const InstanceKlass* super, bool is_interface); static void get_mirandas( GrowableArray* new_mirandas, GrowableArray* all_mirandas, - const Klass* super, + const InstanceKlass* super, Array* class_methods, Array* default_methods, Array* local_interfaces, diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index abec3bc59b6..f4ec7f8ccbf 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1177,7 +1177,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) if (klass->is_instance_klass()) { // Regular instance klass, fill in all local interfaces for (int index = 0; index < size; index++) { - Klass* k = InstanceKlass::cast(klass)->local_interfaces()->at(index); + InstanceKlass* k = InstanceKlass::cast(klass)->local_interfaces()->at(index); result->obj_at_put(index, k->java_mirror()); } } else { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index dd8ee7c93fa..efc7bfde3dd 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1476,7 +1476,7 @@ public: // Gets the fields of `klass` that are eliminated by escape analysis and need to be reassigned static GrowableArray* get_reassigned_fields(InstanceKlass* klass, GrowableArray* fields, bool is_jvmci) { - InstanceKlass* super = klass->superklass(); + InstanceKlass* super = klass->java_super(); if (super != nullptr) { get_reassigned_fields(super, fields, is_jvmci); } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 6fc16f9b045..b95c1aaf60c 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -321,7 +321,7 @@ /* JNI IDs */ \ /***********/ \ \ - nonstatic_field(JNIid, _holder, Klass*) \ + nonstatic_field(JNIid, _holder, InstanceKlass*) \ nonstatic_field(JNIid, _next, JNIid*) \ nonstatic_field(JNIid, _offset, int) \ \ From a668f437e481d02cbb82d4f40dd14ec3a6036399 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 1 Sep 2025 05:54:54 +0000 Subject: [PATCH 059/295] 8365620: Using enhanced switch in MethodHandleDesc Reviewed-by: liach --- .../java/lang/constant/MethodHandleDesc.java | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) 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 18786481fa6..0ac45657d5f 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java @@ -82,15 +82,11 @@ public sealed interface MethodHandleDesc ClassDesc owner, String name, String lookupDescriptor) { - switch (kind) { - case GETTER: - case SETTER: - case STATIC_GETTER: - case STATIC_SETTER: - return ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor)); - default: - return new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor)); - } + return switch (kind) { + case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER + -> ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor)); + default -> new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor)); + }; } /** @@ -122,23 +118,13 @@ public sealed interface MethodHandleDesc ClassDesc owner, String name, MethodTypeDesc lookupMethodType) { - switch (kind) { - case GETTER: - case SETTER: - case STATIC_GETTER: - case STATIC_SETTER: - throw new IllegalArgumentException(kind.toString()); - case VIRTUAL: - case SPECIAL: - case INTERFACE_VIRTUAL: - case INTERFACE_SPECIAL: - case INTERFACE_STATIC: - case STATIC: - case CONSTRUCTOR: - return new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType); - default: - throw new IllegalArgumentException(kind.toString()); - } + return switch (kind) { + case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER + -> throw new IllegalArgumentException(kind.toString()); + case VIRTUAL, SPECIAL, INTERFACE_VIRTUAL, INTERFACE_SPECIAL, INTERFACE_STATIC, STATIC, CONSTRUCTOR + -> new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType); + default -> throw new IllegalArgumentException(kind.toString()); + }; } /** From 28942406020881be79b7543105b9eb2a0dda429e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 1 Sep 2025 05:55:08 +0000 Subject: [PATCH 060/295] 8177650: JShell tool: packages in classpath don't appear in completions Reviewed-by: asotona --- .../jdk/jshell/SourceCodeAnalysisImpl.java | 69 ++--- test/langtools/jdk/jshell/Compiler.java | 8 +- .../jdk/jshell/CompletionSuggestionTest.java | 16 ++ .../langtools/jdk/jshell/ReplToolTesting.java | 33 ++- .../jdk/jshell/ToolCompletionTest.java | 257 ++++++++++++++++++ 5 files changed, 350 insertions(+), 33 deletions(-) create mode 100644 test/langtools/jdk/jshell/ToolCompletionTest.java diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index cb4861651e3..fffdfd5b33c 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -92,7 +92,6 @@ import javax.lang.model.type.TypeMirror; import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA; import java.io.IOException; -import java.net.URI; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -101,6 +100,7 @@ import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.ProviderNotFoundException; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.Collection; @@ -2002,12 +2002,22 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { //update indexes, either initially or after a classpath change: private void refreshIndexes(int version) { try { - Collection paths = new ArrayList<>(); - MemoryFileManager fm = proc.taskFactory.fileManager(); - - appendPaths(fm, StandardLocation.PLATFORM_CLASS_PATH, paths); - appendPaths(fm, StandardLocation.CLASS_PATH, paths); - appendPaths(fm, StandardLocation.SOURCE_PATH, paths); + Collection paths = proc.taskFactory.parse("", task -> { + MemoryFileManager fm = proc.taskFactory.fileManager(); + Collection _paths = new ArrayList<>(); + try { + appendPaths(fm, StandardLocation.PLATFORM_CLASS_PATH, _paths); + appendPaths(fm, StandardLocation.CLASS_PATH, _paths); + appendPaths(fm, StandardLocation.SOURCE_PATH, _paths); + appendModulePaths(fm, StandardLocation.SYSTEM_MODULES, _paths); + appendModulePaths(fm, StandardLocation.UPGRADE_MODULE_PATH, _paths); + appendModulePaths(fm, StandardLocation.MODULE_PATH, _paths); + return _paths; + } catch (Exception ex) { + proc.debug(ex, "SourceCodeAnalysisImpl.refreshIndexes(" + version + ")"); + return List.of(); + } + }); Map newIndexes = new HashMap<>(); @@ -2060,27 +2070,24 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } } + private void appendModulePaths(MemoryFileManager fm, Location loc, Collection paths) throws IOException { + for (Set moduleLocations : fm.listLocationsForModules(loc)) { + for (Location moduleLocation : moduleLocations) { + Iterable modulePaths = fm.getLocationAsPaths(moduleLocation); + + if (modulePaths == null) { + continue; + } + + modulePaths.forEach(paths::add); + } + } + } + //create/update index a given JavaFileManager entry (which may be a JDK installation, a jar/zip file or a directory): //if an index exists for the given entry, the existing index is kept unless the timestamp is modified private ClassIndex indexForPath(Path path) { - if (isJRTMarkerFile(path)) { - FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/")); - Path modules = jrtfs.getPath("modules"); - return PATH_TO_INDEX.compute(path, (p, index) -> { - try { - long lastModified = Files.getLastModifiedTime(modules).toMillis(); - if (index == null || index.timestamp != lastModified) { - try (DirectoryStream stream = Files.newDirectoryStream(modules)) { - index = doIndex(lastModified, path, stream); - } - } - return index; - } catch (IOException ex) { - proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")"); - return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap()); - } - }); - } else if (!Files.isDirectory(path)) { + if (!Files.isDirectory(path)) { if (Files.exists(path)) { return PATH_TO_INDEX.compute(path, (p, index) -> { try { @@ -2093,7 +2100,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } } return index; - } catch (IOException ex) { + } catch (IOException | ProviderNotFoundException ex) { proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")"); return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap()); } @@ -2112,10 +2119,6 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } } - static boolean isJRTMarkerFile(Path path) { - return path.equals(Paths.get(System.getProperty("java.home"), "lib", "modules")); - } - //create an index based on the content of the given dirs; the original JavaFileManager entry is originalPath. private ClassIndex doIndex(long timestamp, Path originalPath, Iterable dirs) { Set packages = new HashSet<>(); @@ -2200,13 +2203,17 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { upToDate = classpathVersion == indexVersion; } while (!upToDate) { - INDEXER.submit(() -> {}).get(); + waitCurrentBackgroundTasksFinished(); synchronized (currentIndexes) { upToDate = classpathVersion == indexVersion; } } } + public static void waitCurrentBackgroundTasksFinished() throws Exception { + INDEXER.submit(() -> {}).get(); + } + /** * A candidate for continuation of the given user's input. */ diff --git a/test/langtools/jdk/jshell/Compiler.java b/test/langtools/jdk/jshell/Compiler.java index 6f6f49da501..a255008b15d 100644 --- a/test/langtools/jdk/jshell/Compiler.java +++ b/test/langtools/jdk/jshell/Compiler.java @@ -72,11 +72,17 @@ public class Compiler { } public void jar(Path directory, String jarName, String...files) { + Path classDirPath = getClassDir(); + Path baseDir = classDirPath.resolve(directory); + Path jarPath = baseDir.resolve(jarName); + jar(directory, jarPath, files); + } + + public void jar(Path directory, Path jarPath, String...files) { Manifest manifest = new Manifest(); manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); Path classDirPath = getClassDir(); Path baseDir = classDirPath.resolve(directory); - Path jarPath = baseDir.resolve(jarName); new JarTask(tb, jarPath.toString()) .manifest(manifest) .baseDir(baseDir.toString()) diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index 6bc7c41e62c..fb9e8eacc4a 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -834,4 +834,20 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletionIncludesExcludes("import module ja|", Set.of("java.base"), Set.of("jdk.compiler")); assertCompletion("import module java/*c*/./*c*/ba|", "java.base"); } + + public void testCustomClassPathIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + "package p1.p2;\n" + + "public class Test {\n" + + "}", + "package p1.p3;\n" + + "public class Test {\n" + + "}"); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + addToClasspath(compiler.getPath(p1.resolve(jarName))); + + assertCompletion("p1.|", "p2.", "p3."); + } } diff --git a/test/langtools/jdk/jshell/ReplToolTesting.java b/test/langtools/jdk/jshell/ReplToolTesting.java index 8bfae2fc390..5ca010af3c2 100644 --- a/test/langtools/jdk/jshell/ReplToolTesting.java +++ b/test/langtools/jdk/jshell/ReplToolTesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -566,6 +567,36 @@ public class ReplToolTesting { } } + public void assertCompletions(boolean after, String input, String expectedCompletionsPattern) { + if (!after) { + try { + Class sourceCodeAnalysisImpl = Class.forName("jdk.jshell.SourceCodeAnalysisImpl"); + Method waitBackgroundTaskFinished = sourceCodeAnalysisImpl.getDeclaredMethod("waitCurrentBackgroundTasksFinished"); + + waitBackgroundTaskFinished.setAccessible(true); + waitBackgroundTaskFinished.invoke(null); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex.getMessage(), ex); + } + + setCommandInput(input + "\t"); + } else { + assertOutput(getCommandOutput().trim(), "", "command output: " + input); + assertOutput(getCommandErrorOutput(), "", "command error: " + input); + assertOutput(getUserOutput(), "", "user output: " + input); + assertOutput(getUserErrorOutput(), "", "user error: " + input); + String actualOutput = getTerminalOutput(); + Pattern compiledPattern = + Pattern.compile(expectedCompletionsPattern, Pattern.DOTALL); + if (!compiledPattern.asMatchPredicate().test(actualOutput)) { + throw new AssertionError("Actual output:\n" + + actualOutput + "\n" + + "does not match expected pattern: " + + expectedCompletionsPattern); + } + } + } + private String normalizeLineEndings(String text) { return normalizeLineEndings(System.getProperty("line.separator"), text); } diff --git a/test/langtools/jdk/jshell/ToolCompletionTest.java b/test/langtools/jdk/jshell/ToolCompletionTest.java new file mode 100644 index 00000000000..9997db45c4d --- /dev/null +++ b/test/langtools/jdk/jshell/ToolCompletionTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8177650 + * @summary Verify JShell tool code completion + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * jdk.jshell/jdk.jshell:+open + * jdk.jshell/jdk.internal.jshell.tool + * java.desktop + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask + * @build ReplToolTesting TestingInputStream Compiler + * @run testng ToolCompletionTest + */ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.testng.annotations.Test; + +public class ToolCompletionTest extends ReplToolTesting { + + private final Compiler compiler = new Compiler(); + private final Path outDir = Paths.get("tool_completion_test"); + + @Test + public void testClassPathOnCmdLineIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "--class-path", compiler.getPath(p1.resolve(jarName)).toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testClassPathViaEnvIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup"}, + (a) -> assertCommand(a, "/env --class-path " + compiler.getPath(p1.resolve(jarName)).toString(), null), + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testClassPathChangeIndexing() { + //verify that changing the classpath has effect: + Path dir1 = outDir.resolve("dir1"); + compiler.compile(dir1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName1 = "test1.jar"; + compiler.jar(dir1, jarName1, "p1/p2/Test.class", "p1/p3/Test.class"); + + Path dir2 = outDir.resolve("dir2"); + compiler.compile(dir2, + """ + package p1.p5; + public class Test { + } + """, + """ + package p1.p6; + public class Test { + } + """); + String jarName2 = "test2.jar"; + compiler.jar(dir2, jarName2, "p1/p5/Test.class", "p1/p6/Test.class"); + + test(false, new String[]{"--no-startup", "--class-path", compiler.getPath(dir1.resolve(jarName1)).toString()}, + (a) -> assertCommand(a, "1", null), + (a) -> assertCommand(a, "/env --class-path " + compiler.getPath(dir2.resolve(jarName2)).toString(), null), + (a) -> assertCompletions(a, "p1.", ".*p5\\..*p6\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testModulePathOnCmdLineIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + module m { + exports p1.p2; + exports p1.p3; + } + """, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "--module-path", compiler.getPath(p1.resolve(jarName)).toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testModulePathOnCmdLineIndexing2() throws IOException { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + module m { + exports p1.p2; + exports p1.p3; + } + """, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + Path lib = outDir.resolve("lib"); + Files.createDirectories(lib); + compiler.jar(p1, lib.resolve(jarName), "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "--module-path", lib.toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testUpgradeModulePathIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + module m { + exports p1.p2; + exports p1.p3; + } + """, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "-C--upgrade-module-path", "-C" + compiler.getPath(p1.resolve(jarName)).toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testBootClassPathPrepend() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "-C-Xbootclasspath/p:" + compiler.getPath(p1.resolve(jarName)).toString(), "-C--source=8"}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } +} From 685da0323b27abda5ab0484f4c8abaaeeff882ea Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 1 Sep 2025 06:25:45 +0000 Subject: [PATCH 061/295] 8345810: Custom launchers must be linked with pthread to avoid dynamic linker issues Reviewed-by: asemenyuk, erikj, dholmes --- make/modules/jdk.jpackage/Lib.gmk | 4 ++-- make/test/JtregNativeJdk.gmk | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/make/modules/jdk.jpackage/Lib.gmk b/make/modules/jdk.jpackage/Lib.gmk index d2dd9d92a03..51d70c6d835 100644 --- a/make/modules/jdk.jpackage/Lib.gmk +++ b/make/modules/jdk.jpackage/Lib.gmk @@ -68,7 +68,7 @@ $(eval $(call SetupJdkExecutable, BUILD_JPACKAGEAPPLAUNCHER, \ -rpath @executable_path/../PlugIns/, \ LIBS_macosx := -framework Cocoa, \ LIBS_windows := msi.lib ole32.lib shell32.lib shlwapi.lib user32.lib, \ - LIBS_linux := $(LIBDL), \ + LIBS_linux := $(LIBDL) $(LIBPTHREAD), \ MANIFEST := $(JAVA_MANIFEST), \ MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS) \ )) @@ -97,7 +97,7 @@ ifeq ($(call isTargetOs, linux), true) DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \ LD_SET_ORIGIN := false, \ - LIBS_linux := $(LIBDL), \ + LIBS_linux := $(LIBDL) $(LIBPTHREAD), \ )) TARGETS += $(BUILD_LIBJPACKAGEAPPLAUNCHERAUX) diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 7578d4a50d0..a204467a77b 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -138,6 +138,7 @@ ifneq ($(filter build-test-jdk-jtreg-native, $(MAKECMDGOALS)), ) OUTPUT_DIR := $(BUILD_JDK_JTREG_OUTPUT_DIR), \ EXCLUDE := $(BUILD_JDK_JTREG_EXCLUDE), \ EXTRA_FILES := $(BUILD_JDK_JTREG_EXTRA_FILES), \ + LIBS := $(LIBPTHREAD), \ )) endif From 12dc568b3d270e4ab6dcd07e1bcddbb024ad724a Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 1 Sep 2025 06:28:10 +0000 Subject: [PATCH 062/295] 8366331: Sort share/prims includes Reviewed-by: shade, lmesnik --- src/hotspot/share/prims/foreignGlobals.cpp | 1 - src/hotspot/share/prims/foreignGlobals.inline.hpp | 2 +- src/hotspot/share/prims/jni.cpp | 2 -- src/hotspot/share/prims/jvm.cpp | 9 ++++----- src/hotspot/share/prims/jvmtiAgent.cpp | 2 +- src/hotspot/share/prims/jvmtiAgentList.cpp | 2 +- src/hotspot/share/prims/jvmtiEnv.cpp | 2 +- src/hotspot/share/prims/jvmtiEnvBase.cpp | 2 +- src/hotspot/share/prims/jvmtiEnvBase.hpp | 2 +- src/hotspot/share/prims/jvmtiEventController.cpp | 3 +-- src/hotspot/share/prims/jvmtiExport.cpp | 2 -- src/hotspot/share/prims/jvmtiManageCapabilities.cpp | 2 +- src/hotspot/share/prims/jvmtiRedefineClasses.cpp | 4 ++-- src/hotspot/share/prims/jvmtiTagMap.cpp | 7 +++---- src/hotspot/share/prims/jvmtiTrace.cpp | 1 - src/hotspot/share/prims/jvmtiUtil.cpp | 1 - src/hotspot/share/prims/methodHandles.cpp | 4 ++-- src/hotspot/share/prims/methodHandles.hpp | 2 +- src/hotspot/share/prims/nativeEntryPoint.cpp | 6 +++--- src/hotspot/share/prims/nativeLookup.cpp | 4 ++-- src/hotspot/share/prims/stackwalk.cpp | 2 +- src/hotspot/share/prims/unsafe.cpp | 2 +- src/hotspot/share/prims/vmstorage.hpp | 4 ++-- src/hotspot/share/prims/wbtestmethods/parserTests.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 26 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/hotspot/share/prims/foreignGlobals.cpp b/src/hotspot/share/prims/foreignGlobals.cpp index f8aa73bed05..3d69a91347b 100644 --- a/src/hotspot/share/prims/foreignGlobals.cpp +++ b/src/hotspot/share/prims/foreignGlobals.cpp @@ -21,7 +21,6 @@ * questions. */ -#include "foreignGlobals.hpp" #include "classfile/javaClasses.hpp" #include "memory/resourceArea.hpp" #include "prims/foreignGlobals.inline.hpp" diff --git a/src/hotspot/share/prims/foreignGlobals.inline.hpp b/src/hotspot/share/prims/foreignGlobals.inline.hpp index bc5c47bcbf5..f5c79997764 100644 --- a/src/hotspot/share/prims/foreignGlobals.inline.hpp +++ b/src/hotspot/share/prims/foreignGlobals.inline.hpp @@ -27,9 +27,9 @@ #include "prims/foreignGlobals.hpp" #include "classfile/javaClasses.hpp" -#include "oops/oopsHierarchy.hpp" #include "oops/objArrayOop.hpp" #include "oops/oopCast.inline.hpp" +#include "oops/oopsHierarchy.hpp" template void ForeignGlobals::parse_register_array(objArrayOop jarray, StorageType type_index, GrowableArray& array, T (*converter)(int)) { diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 5a43baeb8d8..cd356863a8e 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -29,7 +29,6 @@ #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoadInfo.hpp" -#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/javaThreadStatus.hpp" #include "classfile/moduleEntry.hpp" @@ -45,7 +44,6 @@ #include "jni.h" #include "jvm.h" #include "logging/log.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index f4ec7f8ccbf..0d705c84f82 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -32,7 +32,6 @@ #include "cds/lambdaProxyClassDictionary.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.inline.hpp" -#include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoadInfo.hpp" #include "classfile/javaAssertions.hpp" @@ -61,10 +60,10 @@ #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/method.hpp" -#include "oops/recordComponent.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/recordComponent.hpp" #include "prims/foreignGlobals.hpp" #include "prims/jvm_misc.hpp" #include "prims/jvmtiExport.hpp" @@ -73,12 +72,12 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/continuation.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/handshake.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/handshake.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/javaThread.hpp" @@ -92,8 +91,8 @@ #include "runtime/threadIdentifier.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vframe.inline.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadService.hpp" diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp index 4bf7a447398..192bba72fbc 100644 --- a/src/hotspot/share/prims/jvmtiAgent.cpp +++ b/src/hotspot/share/prims/jvmtiAgent.cpp @@ -32,11 +32,11 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" -#include "runtime/globals_extension.hpp" #include "runtime/os.inline.hpp" #include "runtime/thread.inline.hpp" #include "utilities/defaultStream.hpp" diff --git a/src/hotspot/share/prims/jvmtiAgentList.cpp b/src/hotspot/share/prims/jvmtiAgentList.cpp index ec64ccaf70c..3c01bee2cd2 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.cpp +++ b/src/hotspot/share/prims/jvmtiAgentList.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "cds/cdsConfig.hpp" #include "cds/cds_globals.hpp" +#include "cds/cdsConfig.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" #include "prims/jvmtiAgentList.hpp" diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 473db4f2fbc..bc4013a7cab 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -23,8 +23,8 @@ */ #include "classfile/javaClasses.inline.hpp" -#include "classfile/stringTable.hpp" #include "classfile/modules.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index bbd4f7e1154..7450b079d18 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -60,8 +60,8 @@ #include "runtime/threadSMR.inline.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframe_hp.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "services/threadService.hpp" diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp index 66f10c85bc9..809385a0604 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_PRIMS_JVMTIENVBASE_HPP #define SHARE_PRIMS_JVMTIENVBASE_HPP +#include "oops/oopHandle.hpp" #include "prims/jvmtiEnvThreadState.hpp" #include "prims/jvmtiEventController.hpp" #include "prims/jvmtiThreadState.hpp" -#include "oops/oopHandle.hpp" #include "runtime/atomic.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/frame.hpp" diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index facbaaf9ad0..873470db17d 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -27,7 +27,6 @@ #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" -#include "prims/jvmtiEventController.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiImpl.hpp" @@ -41,8 +40,8 @@ #include "runtime/threadSMR.hpp" #include "runtime/vframe.hpp" #include "runtime/vframe_hp.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #ifdef JVMTI_TRACE #define EC_TRACE(out) do { \ diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index a82ad2db6b6..26284b41ef0 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -44,7 +44,6 @@ #include "oops/oopHandle.inline.hpp" #include "prims/jvmtiAgentList.hpp" #include "prims/jvmtiCodeBlobEvents.hpp" -#include "prims/jvmtiEventController.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiImpl.hpp" @@ -61,7 +60,6 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" diff --git a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp index b9de8d0b8f7..29502bb8cd5 100644 --- a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp @@ -24,9 +24,9 @@ #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" -#include "runtime/mutexLocker.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiManageCapabilities.hpp" +#include "runtime/mutexLocker.hpp" static const jint CAPA_SIZE = (JVMTI_INTERNAL_CAPABILITY_COUNT + 7) / 8; diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index d5509896064..e52fdd164f0 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -28,10 +28,10 @@ #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoadInfo.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/klassFactory.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/stackMapTable.hpp" #include "classfile/symbolTable.hpp" -#include "classfile/klassFactory.hpp" #include "classfile/verifier.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" @@ -55,8 +55,8 @@ #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiThreadState.inline.hpp" -#include "prims/resolvedMethodTable.hpp" #include "prims/methodComparator.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 8c6376ac901..0375756e219 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -42,7 +42,6 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" -#include "prims/jvmtiEventController.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiImpl.hpp" @@ -61,13 +60,13 @@ #include "runtime/mutexLocker.hpp" #include "runtime/reflectionUtils.hpp" #include "runtime/safepoint.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/threadSMR.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframe.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" -#include "utilities/objectBitSet.inline.hpp" +#include "runtime/vmThread.hpp" #include "utilities/macros.hpp" +#include "utilities/objectBitSet.inline.hpp" typedef ObjectBitSet JVMTIBitSet; diff --git a/src/hotspot/share/prims/jvmtiTrace.cpp b/src/hotspot/share/prims/jvmtiTrace.cpp index 8dad64cb993..d74f977e7f7 100644 --- a/src/hotspot/share/prims/jvmtiTrace.cpp +++ b/src/hotspot/share/prims/jvmtiTrace.cpp @@ -28,7 +28,6 @@ #include "logging/logConfiguration.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiTrace.hpp" -#include "runtime/javaThread.hpp" #include "runtime/javaThread.inline.hpp" // diff --git a/src/hotspot/share/prims/jvmtiUtil.cpp b/src/hotspot/share/prims/jvmtiUtil.cpp index c6c431d7464..2d31f7187f6 100644 --- a/src/hotspot/share/prims/jvmtiUtil.cpp +++ b/src/hotspot/share/prims/jvmtiUtil.cpp @@ -23,7 +23,6 @@ */ #include "prims/jvmtiUtil.hpp" -#include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/vmOperations.hpp" diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 16617250198..c46b46b1af1 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -31,8 +31,8 @@ #include "code/dependencyContext.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/oopMapCache.hpp" #include "interpreter/linkResolver.hpp" +#include "interpreter/oopMapCache.hpp" #include "jvm_io.h" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -52,11 +52,11 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/reflection.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "sanitizers/leak.hpp" #include "utilities/exceptions.hpp" diff --git a/src/hotspot/share/prims/methodHandles.hpp b/src/hotspot/share/prims/methodHandles.hpp index a44f5a66449..1a419cbb53d 100644 --- a/src/hotspot/share/prims/methodHandles.hpp +++ b/src/hotspot/share/prims/methodHandles.hpp @@ -28,8 +28,8 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "oops/method.hpp" -#include "runtime/frame.hpp" #include "runtime/fieldDescriptor.hpp" +#include "runtime/frame.hpp" #include "runtime/globals.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/prims/nativeEntryPoint.cpp b/src/hotspot/share/prims/nativeEntryPoint.cpp index 172538052f6..6a3d3ebbc3d 100644 --- a/src/hotspot/share/prims/nativeEntryPoint.cpp +++ b/src/hotspot/share/prims/nativeEntryPoint.cpp @@ -22,16 +22,16 @@ * */ -#include "runtime/interfaceSupport.inline.hpp" #include "classfile/javaClasses.inline.hpp" #include "code/codeCache.hpp" #include "code/vmreg.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" -#include "oops/typeArrayOop.inline.hpp" #include "oops/oopCast.inline.hpp" -#include "prims/foreignGlobals.inline.hpp" +#include "oops/typeArrayOop.inline.hpp" #include "prims/downcallLinker.hpp" +#include "prims/foreignGlobals.inline.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" JNI_ENTRY(jlong, NEP_makeDowncallStub(JNIEnv* env, jclass _unused, jobject method_type, jobject jabi, diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 8c8d8510dfc..1d2c78ab3cc 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -36,12 +36,12 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -#include "prims/jvmtiAgentList.hpp" #include "prims/jvm_misc.hpp" +#include "prims/jvmtiAgentList.hpp" #include "prims/jvmtiExport.hpp" #include "prims/nativeLookup.hpp" -#include "prims/unsafe.hpp" #include "prims/scopedMemoryAccess.hpp" +#include "prims/unsafe.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp index 3141700b277..304648a8eb2 100644 --- a/src/hotspot/share/prims/stackwalk.cpp +++ b/src/hotspot/share/prims/stackwalk.cpp @@ -31,8 +31,8 @@ #include "memory/universe.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" -#include "oops/oop.inline.hpp" #include "oops/objArrayOop.inline.hpp" +#include "oops/oop.inline.hpp" #include "prims/stackwalk.hpp" #include "runtime/continuationJavaClasses.inline.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 80dfaf90a28..b4718a9a18a 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -52,8 +52,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/threadSMR.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "sanitizers/ub.hpp" #include "services/threadService.hpp" #include "utilities/align.hpp" diff --git a/src/hotspot/share/prims/vmstorage.hpp b/src/hotspot/share/prims/vmstorage.hpp index a50f95ffc56..f605dc28a9f 100644 --- a/src/hotspot/share/prims/vmstorage.hpp +++ b/src/hotspot/share/prims/vmstorage.hpp @@ -24,13 +24,13 @@ #ifndef SHARE_PRIMS_VMSTORAGE_HPP #define SHARE_PRIMS_VMSTORAGE_HPP -#include - #include "code/vmreg.hpp" #include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include + enum class StorageType : int8_t; // defined in arch specific headers class VMStorage { diff --git a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp index c06cd6cbd81..dc0604aa31d 100644 --- a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp +++ b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp @@ -29,8 +29,8 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" -#include "prims/whitebox.inline.hpp" #include "prims/wbtestmethods/parserTests.hpp" +#include "prims/whitebox.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "services/diagnosticArgument.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 68fab39b23a..1db9c1c00dd 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -126,8 +126,8 @@ #endif #ifdef LINUX #include "cgroupSubsystem_linux.hpp" -#include "osContainer_linux.hpp" #include "os_linux.hpp" +#include "osContainer_linux.hpp" #endif #define CHECK_JNI_EXCEPTION_(env, value) \ diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index f7b70079673..e2724a93890 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -60,6 +60,7 @@ public class TestIncludesAreSorted { "share/oops", "share/opto", "share/precompiled", + "share/prims", "share/services", "share/utilities" }; From 86f48ab559bb1749109217aaecd1203209a5be19 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Mon, 1 Sep 2025 06:35:10 +0000 Subject: [PATCH 063/295] 8366157: Clarify in man pages that only G1 and Parallel supports MaxGCPauseMillis Reviewed-by: tschatzl, sjohanss --- src/java.base/share/man/java.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index f7a31fff836..9a750f8cf1f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2501,10 +2501,9 @@ Java HotSpot VM. `-XX:MaxGCPauseMillis=`*time* : Sets a target for the maximum GC pause time (in milliseconds). This is a - soft goal, and the JVM will make its best effort to achieve it. The - specified value doesn't adapt to your heap size. By default, for G1 the - maximum pause time target is 200 milliseconds. The other generational - collectors do not use a pause time goal by default. + soft goal, and the JVM will make its best effort to achieve it. Only G1 + and Parallel support a maximum GC pause time target. For G1, the default + maximum pause time target is 200 milliseconds. The following example shows how to set the maximum target pause time to 500 ms: From ba90ccc6a8ca7b0b728568ea614470c85a5f7f8a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Sep 2025 06:46:23 +0000 Subject: [PATCH 064/295] 8362516: Support of GCC static analyzer (-fanalyzer) Reviewed-by: erikj --- make/autoconf/configure.ac | 3 +++ make/autoconf/jdk-options.m4 | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index e05b5ae3b90..2e608f893d6 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -221,6 +221,9 @@ JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER # LeakSanitizer JDKOPT_SETUP_LEAK_SANITIZER +# Setup static analyzer +JDKOPT_SETUP_STATIC_ANALYZER + # Fallback linker # This needs to go before 'LIB_DETERMINE_DEPENDENCIES' JDKOPT_SETUP_FALLBACK_LINKER diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 289ed935fdf..d4299078abf 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -479,6 +479,31 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER], AC_SUBST(ASAN_ENABLED) ]) +################################################################################ +# +# Static analyzer +# +AC_DEFUN_ONCE([JDKOPT_SETUP_STATIC_ANALYZER], +[ + UTIL_ARG_ENABLE(NAME: static-analyzer, DEFAULT: false, RESULT: STATIC_ANALYZER_ENABLED, + DESC: [enable the GCC static analyzer], + CHECK_AVAILABLE: [ + AC_MSG_CHECKING([if static analyzer is available]) + if test "x$TOOLCHAIN_TYPE" = "xgcc"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AVAILABLE=false + fi + ], + IF_ENABLED: [ + STATIC_ANALYZER_CFLAGS="-fanalyzer -Wno-analyzer-fd-leak" + CFLAGS_JDKLIB="$CFLAGS_JDKLIB $STATIC_ANALYZER_CFLAGS" + CFLAGS_JDKEXE="$CFLAGS_JDKEXE $STATIC_ANALYZER_CFLAGS" + ]) + AC_SUBST(STATIC_ANALYZER_ENABLED) +]) + ################################################################################ # # LeakSanitizer From a6e2a329a07c71582ac696809fb5349c6a0b681c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Sep 2025 06:48:48 +0000 Subject: [PATCH 065/295] 8366092: [GCC static analyzer] UnixOperatingSystem.c warning: use of uninitialized value 'systemTicks' Reviewed-by: kevinw, asteiner --- .../linux/native/libmanagement_ext/UnixOperatingSystem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c b/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c index af7d52424b7..326dd916f7e 100644 --- a/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c +++ b/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +195,7 @@ static int get_jvmticks(ticks *pticks) { uint64_t userTicks; uint64_t systemTicks; - if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) { + if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) { return -1; } From dbac620b996713087f0d1b1189e543e51a0bb09f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Sep 2025 06:56:48 +0000 Subject: [PATCH 066/295] 8366357: C2 SuperWord: refactor VTransformNode::apply with VTransformApplyState Reviewed-by: chagedorn, kvn, mhaessig --- src/hotspot/share/opto/superword.cpp | 19 ++-- src/hotspot/share/opto/vtransform.cpp | 123 ++++++++++++-------------- src/hotspot/share/opto/vtransform.hpp | 63 ++++++++----- 3 files changed, 105 insertions(+), 100 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index cb92febf803..7b47992e77e 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2108,19 +2108,14 @@ void VTransformGraph::apply_memops_reordering_with_schedule() const { 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); + VTransformApplyState apply_state(_vloop_analyzer, _vtnodes.length()); for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); - VTransformApplyResult result = vtn->apply(_vloop_analyzer, - vtnode_idx_to_transformed_node); + VTransformApplyResult result = vtn->apply(apply_state); NOT_PRODUCT( if (_trace._verbose) { result.trace(vtn); } ) - vtnode_idx_to_transformed_node.at_put(vtn->_idx, result.node()); + apply_state.set_transformed_node(vtn, result.node()); max_vector_length = MAX2(max_vector_length, result.vector_length()); max_vector_width = MAX2(max_vector_width, result.vector_width()); } @@ -3074,7 +3069,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { const bool is_sub = iv_scale * iv_stride > 0; // 1.1: con - Node* xbic = igvn().intcon(is_sub ? -con : con); + Node* xbic = phase()->intcon(is_sub ? -con : con); TRACE_ALIGN_VECTOR_NODE(xbic); // 1.2: invar = SUM(invar_summands) @@ -3091,7 +3086,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { phase()->register_new_node(invar_variable, pre_ctrl); TRACE_ALIGN_VECTOR_NODE(invar_variable); } - Node* invar_scale_con = igvn().intcon(invar_scale); + Node* invar_scale_con = phase()->intcon(invar_scale); TRACE_ALIGN_VECTOR_NODE(invar_scale_con); Node* invar_summand = new MulINode(invar_variable, invar_scale_con); phase()->register_new_node(invar_summand, pre_ctrl); @@ -3143,7 +3138,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { // 2: Compute (14): // XBIC = xbic / abs(iv_scale) // The division is executed as shift - Node* log2_abs_iv_scale = igvn().intcon(exact_log2(abs(iv_scale))); + Node* log2_abs_iv_scale = phase()->intcon(exact_log2(abs(iv_scale))); Node* XBIC = new URShiftINode(xbic, log2_abs_iv_scale); phase()->register_new_node(XBIC, pre_ctrl); TRACE_ALIGN_VECTOR_NODE(log2_abs_iv_scale); @@ -3168,7 +3163,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { // = XBIC_OP_old_limit AND (AW - 1) // Since AW is a power of 2, the modulo operation can be replaced with // a bitmask operation. - Node* mask_AW = igvn().intcon(AW-1); + Node* mask_AW = phase()->intcon(AW-1); Node* adjust_pre_iter = new AndINode(XBIC_OP_old_limit, mask_AW); phase()->register_new_node(adjust_pre_iter, pre_ctrl); TRACE_ALIGN_VECTOR_NODE(mask_AW); diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 1675b8d9fdb..f8efe333941 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -203,13 +203,13 @@ void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { TRACE_SPECULATIVE_ALIGNMENT_CHECK(node); } - Node* mask_alignment = igvn().intcon(alignment-1); + Node* mask_alignment = phase()->intcon(alignment-1); Node* base_alignment = new AndINode(node, mask_alignment); phase()->register_new_node(base_alignment, ctrl); TRACE_SPECULATIVE_ALIGNMENT_CHECK(mask_alignment); TRACE_SPECULATIVE_ALIGNMENT_CHECK(base_alignment); - Node* zero = igvn().intcon(0); + Node* zero = phase()->intcon(0); Node* cmp_alignment = CmpNode::make(base_alignment, zero, T_INT, false); BoolNode* bol_alignment = new BoolNode(cmp_alignment, BoolTest::eq); phase()->register_new_node(cmp_alignment, ctrl); @@ -697,69 +697,68 @@ bool VTransformGraph::has_store_to_load_forwarding_failure(const VLoopAnalyzer& return false; } -Node* VTransformNode::find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const { - Node* n = vnode_idx_to_transformed_node.at(in_req(i)->_idx); - assert(n != nullptr, "must find input IR node"); +void VTransformApplyState::set_transformed_node(VTransformNode* vtn, Node* n) { + assert(_vtnode_idx_to_transformed_node.at(vtn->_idx) == nullptr, "only set once"); + _vtnode_idx_to_transformed_node.at_put(vtn->_idx, n); +} + +Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { + Node* n = _vtnode_idx_to_transformed_node.at(vtn->_idx); + assert(n != nullptr, "must find IR node for vtnode"); return n; } -VTransformApplyResult VTransformScalarNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformScalarNode::apply(VTransformApplyState& apply_state) 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); +VTransformApplyResult VTransformReplicateNode::apply(VTransformApplyState& apply_state) const { + Node* val = apply_state.transformed_node(in_req(1)); VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); - register_new_node_from_vectorization(vloop_analyzer, vn, val); + register_new_node_from_vectorization(apply_state, 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); +VTransformApplyResult VTransformConvI2LNode::apply(VTransformApplyState& apply_state) const { + Node* val = apply_state.transformed_node(in_req(1)); Node* n = new ConvI2LNode(val); - register_new_node_from_vectorization(vloop_analyzer, n, val); + register_new_node_from_vectorization(apply_state, 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); +VTransformApplyResult VTransformShiftCountNode::apply(VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + Node* shift_count_in = apply_state.transformed_node(in_req(1)); 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); + Node* shift_count_masked = new AndINode(shift_count_in, phase->intcon(_mask)); + register_new_node_from_vectorization(apply_state, 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); + register_new_node_from_vectorization(apply_state, 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); +VTransformApplyResult VTransformPopulateIndexNode::apply(VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + Node* val = apply_state.transformed_node(in_req(1)); 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); + VectorNode* vn = new PopulateIndexNode(val, phase->intcon(1), vt); + register_new_node_from_vectorization(apply_state, 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 { +VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyState& apply_state) const { Node* first = nodes().at(0); uint vlen = nodes().length(); int opc = first->Opcode(); - BasicType bt = vloop_analyzer.types().velt_basic_type(first); + BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); if (first->is_Cmp()) { // Cmp + Bool -> VectorMaskCmp @@ -769,9 +768,9 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer 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; + Node* in1 = apply_state.transformed_node(in_req(1)); + Node* in2 = (req() >= 3) ? apply_state.transformed_node(in_req(2)) : nullptr; + Node* in3 = (req() >= 4) ? apply_state.transformed_node(in_req(3)) : nullptr; if (first->is_CMove()) { assert(req() == 4, "three inputs expected: mask, blend1, blend2"); @@ -791,7 +790,7 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer // 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); + register_new_node_from_vectorization(apply_state, 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 || @@ -809,50 +808,47 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary } - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, 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 { +VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& apply_state) const { BoolNode* first = nodes().at(0)->as_Bool(); uint vlen = nodes().length(); - BasicType bt = vloop_analyzer.types().velt_basic_type(first); + BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); // Cmp + Bool -> VectorMaskCmp VTransformElementWiseVectorNode* vtn_cmp = in_req(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); + Node* cmp_in1 = apply_state.transformed_node(vtn_cmp->in_req(1)); + Node* cmp_in2 = apply_state.transformed_node(vtn_cmp->in_req(2)); BoolTest::mask mask = test()._mask; - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); - ConINode* mask_node = phase->igvn().intcon((int)mask); + PhaseIdealLoop* phase = apply_state.phase(); + ConINode* mask_node = phase->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); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, 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 { +VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& apply_state) 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); + Node* init = apply_state.transformed_node(in_req(1)); + Node* vec = apply_state.transformed_node(in_req(2)); ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, 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 { +VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& apply_state) const { LoadNode* first = nodes().at(0)->as_Load(); uint vlen = nodes().length(); Node* ctrl = first->in(MemNode::Control); @@ -860,14 +856,14 @@ VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop 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); + BasicType bt = apply_state.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. - const VPointer& load_p = vpointer(vloop_analyzer); + const VPointer& load_p = vpointer(apply_state.vloop_analyzer()); while (mem->is_StoreVector()) { - VPointer store_p(mem->as_Mem(), vloop_analyzer.vloop()); + VPointer store_p(mem->as_Mem(), apply_state.vloop()); if (store_p.never_overlaps_with(load_p)) { mem = mem->in(MemNode::Memory); } else { @@ -878,12 +874,11 @@ VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop 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); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, 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 { +VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& apply_state) const { StoreNode* first = nodes().at(0)->as_Store(); uint vlen = nodes().length(); Node* ctrl = first->in(MemNode::Control); @@ -892,18 +887,18 @@ VTransformApplyResult VTransformStoreVectorNode::apply(const VLoopAnalyzer& vloo int opc = first->Opcode(); const TypePtr* adr_type = first->adr_type(); - Node* value = find_transformed_input(MemNode::ValueIn, vnode_idx_to_transformed_node); + Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); 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); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, 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(); +void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { + PhaseIdealLoop* phase = apply_state.phase(); Node* first = nodes().at(0); - register_new_node_from_vectorization(vloop_analyzer, vn, first); + register_new_node_from_vectorization(apply_state, vn, first); for (int i = 0; i < _nodes.length(); i++) { Node* n = _nodes.at(i); @@ -911,8 +906,8 @@ void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scal } } -void VTransformNode::register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const { - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); +void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const { + PhaseIdealLoop* phase = apply_state.phase(); phase->register_new_node_with_ctrl_of(vn, old_node); phase->igvn()._worklist.push(vn); VectorNode::trace_new_vector(vn, "AutoVectorization"); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 397d712366b..fb76a3b89d6 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -260,6 +260,32 @@ private: void apply_vectorization() const; }; +// Keeps track of the state during "VTransform::apply" +// -> keep track of the already transformed nodes +class VTransformApplyState : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + + // 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". + GrowableArray _vtnode_idx_to_transformed_node; + +public: + VTransformApplyState(const VLoopAnalyzer& vloop_analyzer, int num_vtnodes) : + _vloop_analyzer(vloop_analyzer), + _vtnode_idx_to_transformed_node(num_vtnodes, num_vtnodes, nullptr) + { + } + + const VLoop& vloop() const { return _vloop_analyzer.vloop(); } + PhaseIdealLoop* phase() const { return vloop().phase(); } + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + + void set_transformed_node(VTransformNode* vtn, Node* n); + Node* transformed_node(const VTransformNode* vtn) 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. @@ -410,12 +436,11 @@ public: virtual bool is_load_or_store_in_loop() const { return false; } virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const { ShouldNotReachHere(); } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const = 0; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) 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; + void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const; NOT_PRODUCT(virtual const char* name() const = 0;) NOT_PRODUCT(void print() const;) @@ -435,8 +460,7 @@ public: virtual bool is_load_in_loop() const override { return _node->is_Load(); } virtual bool is_load_or_store_in_loop() const override { return _node->is_Load() || _node->is_Store(); } virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const override { return vloop_analyzer.vpointers().vpointer(node()->as_Mem()); } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "Scalar"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -462,8 +486,7 @@ private: public: VTransformReplicateNode(VTransform& vtransform, int vlen, BasicType 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "Replicate"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -472,8 +495,7 @@ public: 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ConvI2L"; };) }; @@ -487,8 +509,7 @@ private: 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ShiftCount"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -501,8 +522,7 @@ private: 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "PopulateIndex"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -523,7 +543,7 @@ public: 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; + void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -533,8 +553,7 @@ 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) }; @@ -554,8 +573,7 @@ public: 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) }; @@ -565,8 +583,7 @@ public: 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; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) }; @@ -592,8 +609,7 @@ public: LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "LoadVector"; };) }; @@ -604,8 +620,7 @@ public: VTransformMemVectorNode(vtransform, 4, number_of_nodes, vpointer) {} virtual VTransformStoreVectorNode* isa_StoreVector() override { return this; } virtual bool is_load_in_loop() const override { return false; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "StoreVector"; };) }; From d5d94db12a6d82a6fe9da18b5f8ce3733a6ee7e7 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 1 Sep 2025 07:43:25 +0000 Subject: [PATCH 067/295] 8357086: os::xxx functions returning memory size should return size_t Reviewed-by: stefank, dholmes --- src/hotspot/os/aix/os_aix.cpp | 37 +++--- src/hotspot/os/aix/os_aix.hpp | 8 +- src/hotspot/os/bsd/os_bsd.cpp | 55 +++++---- src/hotspot/os/bsd/os_bsd.hpp | 8 +- .../os/linux/cgroupSubsystem_linux.cpp | 12 +- src/hotspot/os/linux/cgroupUtil_linux.cpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 106 +++++++++++------- src/hotspot/os/linux/os_linux.hpp | 8 +- src/hotspot/os/windows/os_windows.cpp | 56 ++++++--- src/hotspot/os/windows/os_windows.hpp | 8 +- src/hotspot/share/compiler/compileBroker.cpp | 4 +- src/hotspot/share/gc/shared/gcInitLogger.cpp | 5 +- src/hotspot/share/gc/z/zLargePages.cpp | 3 +- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 9 +- .../share/jfr/periodic/jfrPeriodic.cpp | 17 ++- .../share/prims/jvmtiRedefineClasses.cpp | 20 ++-- src/hotspot/share/prims/whitebox.cpp | 9 +- src/hotspot/share/runtime/arguments.cpp | 7 +- src/hotspot/share/runtime/os.cpp | 23 ++-- src/hotspot/share/runtime/os.hpp | 12 +- src/hotspot/share/services/heapDumper.cpp | 5 +- src/hotspot/share/services/management.cpp | 2 +- 22 files changed, 254 insertions(+), 162 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index c58e240719b..aa119210f47 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -169,7 +169,7 @@ static void vmembk_print_on(outputStream* os); //////////////////////////////////////////////////////////////////////////////// // global variables (for a description see os_aix.hpp) -julong os::Aix::_physical_memory = 0; +size_t os::Aix::_physical_memory = 0; pthread_t os::Aix::_main_thread = ((pthread_t)0); @@ -254,40 +254,43 @@ static bool is_close_to_brk(address a) { return false; } -julong os::free_memory() { - return Aix::available_memory(); +bool os::free_memory(size_t& value) { + return Aix::available_memory(value); } -julong os::available_memory() { - return Aix::available_memory(); +bool os::available_memory(size_t& value) { + return Aix::available_memory(value); } -julong os::Aix::available_memory() { +bool os::Aix::available_memory(size_t& value) { os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { - return mi.real_free; + value = static_cast(mi.real_free); + return true; } else { - return ULONG_MAX; + return false; } } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { - return -1; + return false; } - return (jlong)(memory_info.pgsp_total * 4 * K); + value = static_cast(memory_info.pgsp_total * 4 * K); + return true; } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { - return -1; + return false; } - return (jlong)(memory_info.pgsp_free * 4 * K); + value = static_cast(memory_info.pgsp_free * 4 * K); + return true; } -julong os::physical_memory() { +size_t os::physical_memory() { return Aix::physical_memory(); } @@ -326,7 +329,7 @@ void os::Aix::initialize_system_info() { if (!os::Aix::get_meminfo(&mi)) { assert(false, "os::Aix::get_meminfo failed."); } - _physical_memory = (julong) mi.real_total; + _physical_memory = static_cast(mi.real_total); } // Helper function for tracing page sizes. @@ -2193,7 +2196,7 @@ jint os::init_2(void) { os::Posix::init_2(); trcVerbose("processor count: %d", os::_processor_count); - trcVerbose("physical memory: %lu", Aix::_physical_memory); + trcVerbose("physical memory: %zu", Aix::_physical_memory); // Initially build up the loaded dll map. LoadedLibraries::reload(); diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index d17c022e411..1530f2adb76 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -35,7 +35,7 @@ class os::Aix { private: - static julong _physical_memory; + static size_t _physical_memory; static pthread_t _main_thread; // 0 = uninitialized, otherwise 16 bit number: @@ -54,9 +54,9 @@ class os::Aix { // 1 - EXTSHM=ON static int _extshm; - static julong available_memory(); - static julong free_memory(); - static julong physical_memory() { return _physical_memory; } + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); + static size_t physical_memory() { return _physical_memory; } static void initialize_system_info(); // OS recognitions (AIX OS level) call this before calling Aix::os_version(). diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 6ef43ba991e..4f5fed2c8c0 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -114,7 +114,7 @@ //////////////////////////////////////////////////////////////////////////////// // global variables -julong os::Bsd::_physical_memory = 0; +size_t os::Bsd::_physical_memory = 0; #ifdef __APPLE__ mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0}; @@ -133,19 +133,19 @@ static volatile int processor_id_next = 0; //////////////////////////////////////////////////////////////////////////////// // utility functions -julong os::available_memory() { - return Bsd::available_memory(); +bool os::available_memory(size_t& value) { + return Bsd::available_memory(value); } -julong os::free_memory() { - return Bsd::available_memory(); +bool os::free_memory(size_t& value) { + return Bsd::available_memory(value); } // Available here means free. Note that this number is of no much use. As an estimate // for future memory pressure it is far too conservative, since MacOS will use a lot // of unused memory for caches, and return it willingly in case of needs. -julong os::Bsd::available_memory() { - uint64_t available = physical_memory() >> 2; +bool os::Bsd::available_memory(size_t& value) { + uint64_t available = static_cast(physical_memory() >> 2); #ifdef __APPLE__ mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; vm_statistics64_data_t vmstat; @@ -156,9 +156,12 @@ julong os::Bsd::available_memory() { if (kerr == KERN_SUCCESS) { // free_count is just a lowerbound, other page categories can be freed too and make memory available available = (vmstat.free_count + vmstat.inactive_count + vmstat.purgeable_count) * os::vm_page_size(); + } else { + return false; } #endif - return available; + value = static_cast(available); + return true; } // for more info see : @@ -177,33 +180,35 @@ void os::Bsd::print_uptime_info(outputStream* st) { } } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { - return -1; + return false; } - return (jlong)vmusage.xsu_total; + value = static_cast(vmusage.xsu_total); + return true; #else - return -1; + return false; #endif } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { - return -1; + return false; } - return (jlong)vmusage.xsu_avail; + value = static_cast(vmusage.xsu_avail); + return true; #else - return -1; + return false; #endif } -julong os::physical_memory() { +size_t os::physical_memory() { return Bsd::physical_memory(); } @@ -281,7 +286,7 @@ void os::Bsd::initialize_system_info() { len = sizeof(mem_val); if (sysctl(mib, 2, &mem_val, &len, nullptr, 0) != -1) { assert(len == sizeof(mem_val), "unexpected data size"); - _physical_memory = mem_val; + _physical_memory = static_cast(mem_val); } else { _physical_memory = 256 * 1024 * 1024; // fallback (XXXBSD?) } @@ -292,7 +297,7 @@ void os::Bsd::initialize_system_info() { // datasize rlimit restricts us anyway. struct rlimit limits; getrlimit(RLIMIT_DATA, &limits); - _physical_memory = MIN2(_physical_memory, (julong)limits.rlim_cur); + _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur)); } #endif } @@ -1464,11 +1469,13 @@ void os::print_memory_info(outputStream* st) { st->print("Memory:"); st->print(" %zuk page", os::vm_page_size()>>10); - - st->print(", physical " UINT64_FORMAT "k", - os::physical_memory() >> 10); - st->print("(" UINT64_FORMAT "k free)", - os::available_memory() >> 10); + size_t phys_mem = os::physical_memory(); + st->print(", physical %zuk", + phys_mem >> 10); + size_t avail_mem = 0; + (void)os::available_memory(avail_mem); + st->print("(%zuk free)", + avail_mem >> 10); if((sysctlbyname("vm.swapusage", &swap_usage, &size, nullptr, 0) == 0) || (errno == ENOMEM)) { if (size >= offset_of(xsw_usage, xsu_used)) { diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 72de9ca5971..173cc5a40ad 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -42,12 +42,12 @@ class os::Bsd { protected: - static julong _physical_memory; + static size_t _physical_memory; static pthread_t _main_thread; - static julong available_memory(); - static julong free_memory(); - static julong physical_memory() { return _physical_memory; } + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); + static size_t physical_memory() { return _physical_memory; } static void initialize_system_info(); static void rebuild_cpu_to_node_map(); diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index a9cabc87335..3186d97ec61 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -670,8 +670,8 @@ jlong CgroupSubsystem::memory_limit_in_bytes() { 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); + julong phys_mem = static_cast(os::Linux::physical_memory()); + log_trace(os, container)("total physical memory: " JULONG_FORMAT, 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); @@ -841,19 +841,19 @@ jlong CgroupController::limit_from_str(char* limit_str) { // CgroupSubsystem implementations jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() { - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(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 phys_mem = static_cast(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(); + julong phys_mem = static_cast(os::Linux::physical_memory()); return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem); } @@ -894,6 +894,6 @@ jlong CgroupSubsystem::cpu_usage_in_micros() { } void CgroupSubsystem::print_version_specific_info(outputStream* st) { - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); memory_controller()->controller()->print_version_specific_info(st, phys_mem); } diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index b52ef87dcae..72dda36504d 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -65,7 +65,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { char* cg_path = os::strdup(orig); char* last_slash; assert(cg_path[0] == '/', "cgroup path must start with '/'"); - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); char* limit_cg_path = nullptr; jlong limit = mem->read_memory_limit_in_bytes(phys_mem); jlong lowest_limit = limit < 0 ? phys_mem : limit; diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index cee8a11b1d2..ba026442f7f 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -157,7 +157,7 @@ enum CoredumpFilterBit { //////////////////////////////////////////////////////////////////////////////// // global variables -julong os::Linux::_physical_memory = 0; +size_t os::Linux::_physical_memory = 0; address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; @@ -232,15 +232,16 @@ julong os::Linux::available_memory_in_container() { return avail_mem; } -julong os::available_memory() { - return Linux::available_memory(); +bool os::available_memory(size_t& value) { + return Linux::available_memory(value); } -julong os::Linux::available_memory() { +bool os::Linux::available_memory(size_t& value) { julong avail_mem = available_memory_in_container(); if (avail_mem != static_cast(-1L)) { log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); - return avail_mem; + value = static_cast(avail_mem); + return true; } FILE *fp = os::fopen("/proc/meminfo", "r"); @@ -255,66 +256,88 @@ julong os::Linux::available_memory() { fclose(fp); } if (avail_mem == static_cast(-1L)) { - avail_mem = free_memory(); + size_t free_mem = 0; + if (!free_memory(free_mem)) { + return false; + } + avail_mem = static_cast(free_mem); } log_trace(os)("available memory: " JULONG_FORMAT, avail_mem); - return avail_mem; + value = static_cast(avail_mem); + return true; } -julong os::free_memory() { - return Linux::free_memory(); +bool os::free_memory(size_t& value) { + return Linux::free_memory(value); } -julong os::Linux::free_memory() { +bool os::Linux::free_memory(size_t& value) { // values in struct sysinfo are "unsigned long" struct sysinfo si; julong free_mem = available_memory_in_container(); if (free_mem != static_cast(-1L)) { log_trace(os)("free container memory: " JULONG_FORMAT, free_mem); - return free_mem; + value = static_cast(free_mem); + return true; } - sysinfo(&si); + int ret = sysinfo(&si); + if (ret != 0) { + return false; + } free_mem = (julong)si.freeram * si.mem_unit; log_trace(os)("free memory: " JULONG_FORMAT, free_mem); - return free_mem; + value = static_cast(free_mem); + return true; } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { if (OSContainer::is_containerized()) { - if (OSContainer::memory_limit_in_bytes() > 0) { - return (jlong)(OSContainer::memory_and_swap_limit_in_bytes() - OSContainer::memory_limit_in_bytes()); + jlong memory_and_swap_limit_in_bytes = OSContainer::memory_and_swap_limit_in_bytes(); + jlong memory_limit_in_bytes = OSContainer::memory_limit_in_bytes(); + if (memory_limit_in_bytes > 0 && memory_and_swap_limit_in_bytes > 0) { + value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes); + return true; } - } + } // fallback to the host swap space if the container did return the unbound value of -1 struct sysinfo si; int ret = sysinfo(&si); if (ret != 0) { - return -1; + assert(false, "sysinfo failed in total_swap_space(): %s", os::strerror(errno)); + return false; } - return (jlong)(si.totalswap * si.mem_unit); + value = static_cast(si.totalswap * si.mem_unit); + return true; } -static jlong host_free_swap() { +static bool host_free_swap_f(size_t& value) { struct sysinfo si; int ret = sysinfo(&si); if (ret != 0) { - return -1; + assert(false, "sysinfo failed in host_free_swap_f(): %s", os::strerror(errno)); + return false; } - return (jlong)(si.freeswap * si.mem_unit); + value = static_cast(si.freeswap * si.mem_unit); + return true; } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { // os::total_swap_space() might return the containerized limit which might be // less than host_free_swap(). The upper bound of free swap needs to be the lower of the two. - jlong host_free_swap_val = MIN2(os::total_swap_space(), host_free_swap()); - assert(host_free_swap_val >= 0, "sysinfo failed?"); + size_t total_swap_space = 0; + size_t host_free_swap = 0; + if (!os::total_swap_space(total_swap_space) || !host_free_swap_f(host_free_swap)) { + return false; + } + size_t host_free_swap_val = MIN2(total_swap_space, host_free_swap); if (OSContainer::is_containerized()) { jlong mem_swap_limit = OSContainer::memory_and_swap_limit_in_bytes(); jlong mem_limit = OSContainer::memory_limit_in_bytes(); if (mem_swap_limit >= 0 && mem_limit >= 0) { jlong delta_limit = mem_swap_limit - mem_limit; if (delta_limit <= 0) { - return 0; + value = 0; + return true; } jlong mem_swap_usage = OSContainer::memory_and_swap_usage_in_bytes(); jlong mem_usage = OSContainer::memory_usage_in_bytes(); @@ -322,30 +345,31 @@ jlong os::free_swap_space() { jlong delta_usage = mem_swap_usage - mem_usage; if (delta_usage >= 0) { jlong free_swap = delta_limit - delta_usage; - return free_swap >= 0 ? free_swap : 0; + value = free_swap >= 0 ? static_cast(free_swap) : 0; + return true; } } } // unlimited or not supported. Fall through to return host value log_trace(os,container)("os::free_swap_space: container_swap_limit=" JLONG_FORMAT - " container_mem_limit=" JLONG_FORMAT " returning host value: " JLONG_FORMAT, + " container_mem_limit=" JLONG_FORMAT " returning host value: %zu", mem_swap_limit, mem_limit, host_free_swap_val); } - return host_free_swap_val; + value = host_free_swap_val; + return true; } -julong os::physical_memory() { - jlong phys_mem = 0; +size_t os::physical_memory() { if (OSContainer::is_containerized()) { jlong mem_limit; if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) { log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit); - return mem_limit; + return static_cast(mem_limit); } } - phys_mem = Linux::physical_memory(); - log_trace(os)("total system memory: " JLONG_FORMAT, phys_mem); + size_t phys_mem = Linux::physical_memory(); + log_trace(os)("total system memory: %zu", phys_mem); return phys_mem; } @@ -520,7 +544,7 @@ void os::Linux::initialize_system_info() { fclose(fp); } } - _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE); + _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); assert(processor_count() > 0, "linux error"); } @@ -2548,11 +2572,13 @@ void os::print_memory_info(outputStream* st) { // values in struct sysinfo are "unsigned long" struct sysinfo si; sysinfo(&si); - - st->print(", physical " UINT64_FORMAT "k", - os::physical_memory() >> 10); - st->print("(" UINT64_FORMAT "k free)", - os::available_memory() >> 10); + size_t phys_mem = physical_memory(); + st->print(", physical %zuk", + phys_mem >> 10); + size_t avail_mem = 0; + (void)os::available_memory(avail_mem); + st->print("(%zuk free)", + avail_mem >> 10); st->print(", swap " UINT64_FORMAT "k", ((jlong)si.totalswap * si.mem_unit) >> 10); st->print("(" UINT64_FORMAT "k free)", diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index bd2e1ea3230..d3e0d6c5668 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -50,11 +50,11 @@ class os::Linux { protected: - static julong _physical_memory; + static size_t _physical_memory; static pthread_t _main_thread; - static julong available_memory(); - static julong free_memory(); + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); static void initialize_system_info(); @@ -117,7 +117,7 @@ class os::Linux { static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; } static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; } - static julong physical_memory() { return _physical_memory; } + static size_t physical_memory() { return _physical_memory; } static julong host_swap(); static intptr_t* ucontext_get_sp(const ucontext_t* uc); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 27bf196075a..3f3d9f6ac63 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -848,39 +848,56 @@ jlong os::elapsed_frequency() { } -julong os::available_memory() { - return win32::available_memory(); +bool os::available_memory(size_t& value) { + return win32::available_memory(value); } -julong os::free_memory() { - return win32::available_memory(); +bool os::free_memory(size_t& value) { + return win32::available_memory(value); } -julong os::win32::available_memory() { +bool os::win32::available_memory(size_t& value) { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - - return (julong)ms.ullAvailPhys; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res == TRUE) { + value = static_cast(ms.ullAvailPhys); + return true; + } else { + assert(false, "GlobalMemoryStatusEx failed in os::win32::available_memory(): %lu", ::GetLastError()); + return false; + } } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullTotalPageFile; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res == TRUE) { + value = static_cast(ms.ullTotalPageFile); + return true; + } else { + assert(false, "GlobalMemoryStatusEx failed in os::total_swap_space(): %lu", ::GetLastError()); + return false; + } } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullAvailPageFile; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res == TRUE) { + value = static_cast(ms.ullAvailPageFile); + return true; + } else { + assert(false, "GlobalMemoryStatusEx failed in os::free_swap_space(): %lu", ::GetLastError()); + return false; + } } -julong os::physical_memory() { +size_t os::physical_memory() { return win32::physical_memory(); } @@ -3948,7 +3965,7 @@ int os::current_process_id() { int os::win32::_processor_type = 0; // Processor level is not available on non-NT systems, use vm_version instead int os::win32::_processor_level = 0; -julong os::win32::_physical_memory = 0; +size_t os::win32::_physical_memory = 0; bool os::win32::_is_windows_server = false; @@ -4178,8 +4195,11 @@ void os::win32::initialize_system_info() { // also returns dwAvailPhys (free physical memory bytes), dwTotalVirtual, dwAvailVirtual, // dwMemoryLoad (% of memory in use) - GlobalMemoryStatusEx(&ms); - _physical_memory = ms.ullTotalPhys; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res != TRUE) { + assert(false, "GlobalMemoryStatusEx failed in os::win32::initialize_system_info(): %lu", ::GetLastError()); + } + _physical_memory = static_cast(ms.ullTotalPhys); if (FLAG_IS_DEFAULT(MaxRAM)) { // Adjust MaxRAM according to the maximum virtual address space available. diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 1aba43fb3d2..1426dc8be93 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -40,7 +40,7 @@ class os::win32 { protected: static int _processor_type; static int _processor_level; - static julong _physical_memory; + static size_t _physical_memory; static bool _is_windows_server; static bool _has_exit_bug; static bool _processor_group_warning_displayed; @@ -102,9 +102,9 @@ class os::win32 { static int processor_level() { return _processor_level; } - static julong available_memory(); - static julong free_memory(); - static julong physical_memory() { return _physical_memory; } + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); + static size_t physical_memory() { return _physical_memory; } // load dll from Windows system directory or Windows directory static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen); diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 177b8b1c161..5f3bdc5ee3c 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1061,7 +1061,9 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { if (new_c2_count <= old_c2_count && new_c1_count <= old_c1_count) return; // Now, we do the more expensive operations. - julong free_memory = os::free_memory(); + size_t free_memory = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::free_memory(free_memory); // If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All). size_t available_cc_np = CodeCache::unallocated_capacity(CodeBlobType::MethodNonProfiled), available_cc_p = CodeCache::unallocated_capacity(CodeBlobType::MethodProfiled); diff --git a/src/hotspot/share/gc/shared/gcInitLogger.cpp b/src/hotspot/share/gc/shared/gcInitLogger.cpp index 91bebf726c1..763c265b65e 100644 --- a/src/hotspot/share/gc/shared/gcInitLogger.cpp +++ b/src/hotspot/share/gc/shared/gcInitLogger.cpp @@ -62,9 +62,8 @@ void GCInitLogger::print_cpu() { } void GCInitLogger::print_memory() { - julong memory = os::physical_memory(); - log_info_p(gc, init)("Memory: " JULONG_FORMAT "%s", - byte_size_in_proper_unit(memory), proper_unit_for_byte_size(memory)); + size_t memory = os::physical_memory(); + log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); } void GCInitLogger::print_large_pages() { diff --git a/src/hotspot/share/gc/z/zLargePages.cpp b/src/hotspot/share/gc/z/zLargePages.cpp index 56c94a75713..639c9b0a04f 100644 --- a/src/hotspot/share/gc/z/zLargePages.cpp +++ b/src/hotspot/share/gc/z/zLargePages.cpp @@ -31,7 +31,8 @@ bool ZLargePages::_os_enforced_transparent_mode; void ZLargePages::initialize() { pd_initialize(); - log_info_p(gc, init)("Memory: " JULONG_FORMAT "M", os::physical_memory() / M); + const size_t memory = os::physical_memory(); + log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); log_info_p(gc, init)("Large Page Support: %s", to_string()); } diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 1d1f3a62866..57bea5c268b 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -412,9 +412,9 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_memory(JNIEnv* env, jclass jvm)) #ifdef LINUX // We want the host memory, not the container limit. // os::physical_memory() would return the container limit. - return os::Linux::physical_memory(); + return static_cast(os::Linux::physical_memory()); #else - return os::physical_memory(); + return static_cast(os::physical_memory()); #endif JVM_END @@ -423,7 +423,10 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) // We want the host swap memory, not the container value. return os::Linux::host_swap(); #else - return os::total_swap_space(); + size_t total_swap_space = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::total_swap_space(total_swap_space); + return static_cast(total_swap_space); #endif JVM_END diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 49669d1675d..a8a9e191ed8 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -528,17 +528,26 @@ TRACE_REQUEST_FUNC(ThreadAllocationStatistics) { * the total memory reported is the amount of memory configured for the guest OS by the hypervisor. */ TRACE_REQUEST_FUNC(PhysicalMemory) { - u8 totalPhysicalMemory = os::physical_memory(); + u8 totalPhysicalMemory = static_cast(os::physical_memory()); EventPhysicalMemory event; event.set_totalSize(totalPhysicalMemory); - event.set_usedSize(totalPhysicalMemory - os::available_memory()); + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); + event.set_usedSize(totalPhysicalMemory - static_cast(avail_mem)); event.commit(); } TRACE_REQUEST_FUNC(SwapSpace) { EventSwapSpace event; - event.set_totalSize(os::total_swap_space()); - event.set_freeSize(os::free_swap_space()); + size_t total_swap_space = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::total_swap_space(total_swap_space); + event.set_totalSize(static_cast(total_swap_space)); + size_t free_swap_space = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::free_swap_space(free_swap_space); + event.set_freeSize(static_cast(free_swap_space)); event.commit(); } diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index e52fdd164f0..dc2d621f694 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1358,10 +1358,12 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { // constant pools HandleMark hm(current); InstanceKlass* the_class = get_ik(_class_defs[i].klass); - + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)", - the_class->external_name(), _class_load_kind, os::available_memory() >> 10); + ("loading name=%s kind=%d (avail_mem=%zuK)", + the_class->external_name(), _class_load_kind, avail_mem >> 10); ClassFileStream st((u1*)_class_defs[i].class_bytes, _class_defs[i].class_byte_count, @@ -1525,9 +1527,10 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { return JVMTI_ERROR_INTERNAL; } } - + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", the_class->external_name(), os::available_memory() >> 10); + ("loaded name=%s (avail_mem=%zuK)", the_class->external_name(), avail_mem >> 10); } return JVMTI_ERROR_NONE; @@ -4435,9 +4438,12 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas ResourceMark rm(current); // increment the classRedefinedCount field in the_class and in any // direct and indirect subclasses of the_class + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); log_info(redefine, class, load) - ("redefined name=%s, count=%d (avail_mem=" UINT64_FORMAT "K)", - the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), os::available_memory() >> 10); + ("redefined name=%s, count=%d (avail_mem=%zuK)", + the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), avail_mem >> 10); Events::log_redefinition(current, "redefined class name=%s, count=%d", the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror())); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1db9c1c00dd..a22cb9d51ce 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2505,13 +2505,16 @@ WB_END // Physical memory of the host machine (including containers) WB_ENTRY(jlong, WB_HostPhysicalMemory(JNIEnv* env, jobject o)) - LINUX_ONLY(return os::Linux::physical_memory();) - return os::physical_memory(); + LINUX_ONLY(return static_cast(os::Linux::physical_memory());) + return static_cast(os::physical_memory()); WB_END // Available memory of the host machine (container-aware) WB_ENTRY(jlong, WB_HostAvailableMemory(JNIEnv* env, jobject o)) - return os::available_memory(); + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); + return static_cast(avail_mem); WB_END // Physical swap of the host machine (including containers), Linux only. diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index cc14e5da2c3..063090b93c9 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1517,13 +1517,13 @@ void Arguments::set_heap_size() { !FLAG_IS_DEFAULT(MaxRAM)); if (override_coop_limit) { if (FLAG_IS_DEFAULT(MaxRAM)) { - phys_mem = os::physical_memory(); + phys_mem = static_cast(os::physical_memory()); FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem); } else { phys_mem = (julong)MaxRAM; } } else { - phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM) + phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(static_cast(os::physical_memory()), (julong)MaxRAM) : (julong)MaxRAM; } @@ -1645,7 +1645,8 @@ jint Arguments::set_aggressive_heap_flags() { // Thus, we need to make sure we're using a julong for intermediate // calculations. julong initHeapSize; - julong total_memory = os::physical_memory(); + size_t phys_mem = os::physical_memory(); + julong total_memory = static_cast(phys_mem); if (total_memory < (julong) 256 * M) { jio_fprintf(defaultStream::error_stream(), diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index e02d13edb8e..3152f734dfa 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1184,9 +1184,10 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) { #endif // PRODUCT get_summary_cpu_info(buf, buflen); st->print("%s, ", buf); - size_t mem = physical_memory()/G; + size_t phys_mem = physical_memory(); + size_t mem = phys_mem/G; if (mem == 0) { // for low memory systems - mem = physical_memory()/M; + mem = phys_mem/M; st->print("%d cores, %zuM, ", processor_count(), mem); } else { st->print("%d cores, %zuG, ", processor_count(), mem); @@ -1941,10 +1942,10 @@ bool os::is_server_class_machine() { // We allow some part (1/8?) of the memory to be "missing", // based on the sizes of DIMMs, and maybe graphics cards. const julong missing_memory = 256UL * M; - + size_t phys_mem = os::physical_memory(); /* Is this a server class machine? */ if ((os::active_processor_count() >= (int)server_processors) && - (os::physical_memory() >= (server_memory - missing_memory))) { + (phys_mem >= (server_memory - missing_memory))) { const unsigned int logical_processors = VM_Version::logical_processors_per_package(); if (logical_processors > 1) { @@ -2203,16 +2204,24 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { p2i(addr), p2i(addr) + bytes); } -julong os::used_memory() { +bool os::used_memory(size_t& value) { #ifdef LINUX if (OSContainer::is_containerized()) { jlong mem_usage = OSContainer::memory_usage_in_bytes(); if (mem_usage > 0) { - return mem_usage; + value = static_cast(mem_usage); + return true; + } else { + return false; } } #endif - return os::physical_memory() - os::available_memory(); + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); + size_t phys_mem = os::physical_memory(); + value = phys_mem - avail_mem; + return true; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 6d40a646358..9db4380fc07 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -332,14 +332,14 @@ class os: AllStatic { // For example, on Linux, "available" memory (`MemAvailable` in `/proc/meminfo`) is greater // 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(); + [[nodiscard]] static bool available_memory(size_t& value); + [[nodiscard]] static bool used_memory(size_t& value); + [[nodiscard]] static bool free_memory(size_t& value); - static jlong total_swap_space(); - static jlong free_swap_space(); + [[nodiscard]] static bool total_swap_space(size_t& value); + [[nodiscard]] static bool free_swap_space(size_t& value); - static julong physical_memory(); + static size_t physical_memory(); static bool is_server_class_machine(); static size_t rss(); diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index cd679986a6c..59460dbf89b 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2612,7 +2612,10 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool // (DumpWriter buffer, DumperClassCacheTable, GZipCompressor buffers). // For the OOM handling we may already be limited in memory. // Lets ensure we have at least 20MB per thread. - julong max_threads = os::free_memory() / (20 * M); + size_t free_memory = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::free_memory(free_memory); + julong max_threads = free_memory / (20 * M); if (num_dump_threads > max_threads) { num_dump_threads = MAX2(1, (uint)max_threads); } diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 5b0fc96771a..cfe13d0c8f1 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -975,7 +975,7 @@ static jlong get_long_attribute(jmmLongAttribute att) { return ClassLoadingService::class_method_data_size(); case JMM_OS_MEM_TOTAL_PHYSICAL_BYTES: - return os::physical_memory(); + return static_cast(os::physical_memory()); default: return -1; From a9f3cb23d1802ef3d3042a7f521a0747f70bc732 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 1 Sep 2025 07:47:44 +0000 Subject: [PATCH 068/295] 8366462: Test gc/z/TestCommitFailure.java#Normal failed: expected output missing Reviewed-by: dholmes, eosterlund --- test/hotspot/jtreg/gc/z/TestCommitFailure.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/z/TestCommitFailure.java b/test/hotspot/jtreg/gc/z/TestCommitFailure.java index 3cee84d4f95..c7c8dc12add 100644 --- a/test/hotspot/jtreg/gc/z/TestCommitFailure.java +++ b/test/hotspot/jtreg/gc/z/TestCommitFailure.java @@ -106,7 +106,6 @@ public class TestCommitFailure { ProcessTools.executeTestJava(arguments) .outputTo(System.out) .errorTo(System.out) - .shouldContain("Forced to lower max Java heap size") .shouldHaveExitValue(0); } } From 48f70d7ad85dde49cc8134d4ac0312978a5cc9f7 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 1 Sep 2025 07:50:35 +0000 Subject: [PATCH 069/295] 8361370: runtime/Thread/TestThreadDumpMonitorContention.java fails due to time out on Windows Reviewed-by: dholmes, amenkov --- .../runtime/Thread/TestThreadDumpMonitorContention.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java index c232f257142..a8f8660272d 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java +++ b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java @@ -50,6 +50,11 @@ public class TestThreadDumpMonitorContention { // getJDKTool() which can fall back to "compile.jdk". final static String JSTACK = JDKToolFinder.getTestJDKTool("jstack"); final static String PID = Long.toString(ProcessHandle.current().pid()); + // jstack streaming output should be disabled because if the attach operation is executed at a safepoint, + // the attach streaming output is enabled, and the tool output is lengthy, then we can get both buffers (the attach + // channel and the tool redirection buffer) full and the test hangs. + // Instead the attach operation output is buffered and is sent after the operation is completed. + final static String DISABLE_STREAMING_OUTPUT = "-J-Djdk.attach.allowStreamingOutput=false"; // looking for header lines with these patterns: // "ContendingThread-1" #19 prio=5 os_prio=64 tid=0x000000000079c000 nid=0x23 runnable [0xffff80ffb8b87000] @@ -379,7 +384,7 @@ public class TestThreadDumpMonitorContention { // we don't mix data between the two stack traces that do // match HEADER_PREFIX_PATTERN. // - Process process = new ProcessBuilder(JSTACK, PID) + Process process = new ProcessBuilder(JSTACK, DISABLE_STREAMING_OUTPUT, PID) .redirectErrorStream(true).start(); BufferedReader reader = new BufferedReader(new InputStreamReader( From 3ca44c8dea035588070644e5c1f8f25559f66e53 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Sep 2025 08:03:34 +0000 Subject: [PATCH 070/295] 8364352: Some tests fail when using a limited number of pregenerated .jsa CDS archives Reviewed-by: dholmes, stuefe --- test/hotspot/jtreg/TEST.ROOT | 1 + ...mpressedCPUSpecificClassSpaceReservation.java | 1 + .../runtime/cds/TestDefaultArchiveLoading.java | 16 ++++++++++++---- .../DynamicLoaderConstraintsTest.java | 3 ++- test/jtreg-ext/requires/VMProps.java | 11 +++++++++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 1857978ebc0..2d0d972744c 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -80,6 +80,7 @@ requires.properties= \ vm.rtm.compiler \ vm.cds \ vm.cds.default.archive.available \ + vm.cds.nocoops.archive.available \ vm.cds.custom.loaders \ vm.cds.supports.aot.class.linking \ vm.cds.supports.aot.code.caching \ diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java index 622573fa709..35e4b9ef233 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java @@ -28,6 +28,7 @@ * @requires vm.bits == 64 & !vm.graal.enabled & vm.debug == true * @requires vm.flagless * @requires vm.cds + * @requires vm.cds.default.archive.available * @requires (os.family != "windows") & (os.family != "aix") * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java index 4dd3b63c84a..4bca1ed4581 100644 --- a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java +++ b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java @@ -94,8 +94,8 @@ public class TestDefaultArchiveLoading { "server", archiveName(archiveSuffix)); } - private static boolean isCOHArchiveAvailable(char coops, char coh, - String archiveSuffix) throws Exception { + private static boolean isArchiveAvailable(char coops, char coh, + String archiveSuffix) throws Exception { Path archive= archivePath(archiveSuffix); return Files.exists(archive); } @@ -113,12 +113,16 @@ public class TestDefaultArchiveLoading { case "nocoops_nocoh": coh = coops = '-'; archiveSuffix = "_nocoops"; + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { + throw new SkippedException("Skipping test due to " + + archivePath(archiveSuffix).toString() + " not available"); + } break; case "nocoops_coh": coops = '-'; coh = '+'; archiveSuffix = "_nocoops_coh"; - if (!isCOHArchiveAvailable(coops, coh, archiveSuffix)) { + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { throw new SkippedException("Skipping test due to " + archivePath(archiveSuffix).toString() + " not available"); } @@ -127,11 +131,15 @@ public class TestDefaultArchiveLoading { coops = '+'; coh = '-'; archiveSuffix = ""; + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { + throw new SkippedException("Skipping test due to " + + archivePath(archiveSuffix).toString() + " not available"); + } break; case "coops_coh": coh = coops = '+'; archiveSuffix = "_coh"; - if (!isCOHArchiveAvailable(coops, coh, archiveSuffix)) { + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { throw new SkippedException("Skipping test due to " + archivePath(archiveSuffix).toString() + " not available"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java index 91293531611..1d83fb9efa6 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ /** * @test id=custom-cl-zgc * @requires vm.cds.custom.loaders + * @requires vm.cds.nocoops.archive.available * @requires vm.gc.Z * @summary Test dumptime_table entries are removed with zgc eager class unloading * @bug 8274935 diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 74ea525b415..96c84115fe3 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -121,6 +121,7 @@ public class VMProps implements Callable> { // vm.cds is true if the VM is compiled with cds support. map.put("vm.cds", this::vmCDS); map.put("vm.cds.default.archive.available", this::vmCDSDefaultArchiveAvailable); + map.put("vm.cds.nocoops.archive.available", this::vmCDSNocoopsArchiveAvailable); map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders); map.put("vm.cds.supports.aot.class.linking", this::vmCDSSupportsAOTClassLinking); map.put("vm.cds.supports.aot.code.caching", this::vmCDSSupportsAOTCodeCaching); @@ -440,6 +441,16 @@ public class VMProps implements Callable> { return "" + ("true".equals(vmCDS()) && Files.exists(archive)); } + /** + * Check for CDS no compressed oops archive existence. + * + * @return true if CDS archive classes_nocoops.jsa exists in the JDK to be tested. + */ + protected String vmCDSNocoopsArchiveAvailable() { + Path archive = Paths.get(System.getProperty("java.home"), "lib", "server", "classes_nocoops.jsa"); + return "" + ("true".equals(vmCDS()) && Files.exists(archive)); + } + /** * Check for CDS support for custom loaders. * From fe4c7a0429a2cf9ef47701d68d0852ce44e1a9ab Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Mon, 1 Sep 2025 08:07:08 +0000 Subject: [PATCH 071/295] 8364135: JPEGImageReader.getImageTypes() should throw exception for negative image index Reviewed-by: aivanov, prr, psadhukhan --- .../imageio/plugins/jpeg/JPEGImageReader.java | 14 ++- .../jpeg/JpegNegativeImageIndexTest.java | 85 +++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 77c15c7c7fc..1d6bf2dbf8a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -391,6 +391,12 @@ public class JPEGImageReader extends ImageReader { tablesOnlyChecked = true; } + private void verifyImageIndex(int imageIndex) { + if (imageIndex < minIndex) { + throw new IndexOutOfBoundsException("imageIndex < " + minIndex); + } + } + @Override public int getNumImages(boolean allowSearch) throws IOException { setThreadLock(); @@ -497,9 +503,7 @@ public class JPEGImageReader extends ImageReader { if (iis == null) { throw new IllegalStateException("Input not set"); } - if (imageIndex < minIndex) { - throw new IndexOutOfBoundsException(); - } + verifyImageIndex(imageIndex); if (!tablesOnlyChecked) { checkTablesOnly(); } @@ -842,6 +846,7 @@ public class JPEGImageReader extends ImageReader { public int getWidth(int imageIndex) throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); if (currentImage != imageIndex) { cbLock.check(); readHeader(imageIndex, true); @@ -856,6 +861,7 @@ public class JPEGImageReader extends ImageReader { public int getHeight(int imageIndex) throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); if (currentImage != imageIndex) { cbLock.check(); readHeader(imageIndex, true); @@ -886,6 +892,7 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); if (currentImage != imageIndex) { cbLock.check(); @@ -904,6 +911,7 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); return getImageTypesOnThread(imageIndex); } finally { clearThreadLock(); diff --git a/test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java b/test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java new file mode 100644 index 00000000000..87843f16853 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8364135 + * @summary Test verifies that jpeg image reader throws + * IndexOutOfBoundsException when "-1" image index is used. + * @run main JpegNegativeImageIndexTest + */ + +import java.io.IOException; +import java.util.Iterator; +import java.util.concurrent.Callable; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; + +public class JpegNegativeImageIndexTest { + + private static boolean failed; + + private static void checkException(boolean exceptionReceived, + String testName) { + if (!exceptionReceived) { + System.out.println("Didn't receive IndexOutOfBoundsException for " + + testName); + failed = true; + } + } + + private static void testMethod(String methodName, + Callable method) { + boolean exceptionReceived = false; + System.out.println("Testing " + methodName); + try { + method.call(); + } catch (Exception e) { + if (e instanceof IndexOutOfBoundsException) { + exceptionReceived = true; + } + } + checkException(exceptionReceived, methodName); + } + + public static void main(String[] args) throws IOException { + Iterator readers = + ImageIO.getImageReadersByFormatName("jpeg"); + if (!readers.hasNext()) { + throw new RuntimeException("No jpeg image readers found"); + } + + ImageReader ir = readers.next(); + + testMethod("getImageTypes()", () -> ir.getImageTypes(-1)); + testMethod("getWidth()", () -> ir.getWidth(-1)); + testMethod("getHeight()", () -> ir.getHeight(-1)); + testMethod("getRawImageType()", () -> ir.getRawImageType(-1)); + + if (failed) { + throw new RuntimeException("JpegImageReader didn't throw required" + + " IndexOutOfBoundsException for -1 image index"); + } + } +} From 56713817c0fd060f7106a538b0e795081f4f9d4b Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Sep 2025 08:47:19 +0000 Subject: [PATCH 072/295] 8366361: C2 SuperWord: rename VTransformNode::set_req -> init_req, analogue to Node::init_req Reviewed-by: kvn, chagedorn --- .../share/opto/superwordVTransformBuilder.cpp | 46 +++++++++---------- .../share/opto/superwordVTransformBuilder.hpp | 4 +- src/hotspot/share/opto/vtransform.hpp | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index 404eb02372e..d178fd4394c 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -68,29 +68,29 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every memory dependency only once per vtn. if (p0->is_Load()) { - set_req_with_scalar(p0, vtn, MemNode::Address); + init_req_with_scalar(p0, vtn, MemNode::Address); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (p0->is_Store()) { - set_req_with_scalar(p0, vtn, MemNode::Address); - set_req_with_vector(pack, vtn, MemNode::ValueIn); + init_req_with_scalar(p0, vtn, MemNode::Address); + init_req_with_vector(pack, vtn, MemNode::ValueIn); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (vtn->isa_ReductionVector() != nullptr) { - set_req_with_scalar(p0, vtn, 1); // scalar init - set_req_with_vector(pack, vtn, 2); // vector + init_req_with_scalar(p0, vtn, 1); // scalar init + init_req_with_vector(pack, vtn, 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, 1); - set_req_with_scalar(p0, vtn, 2); // constant rotation + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rotation } else if (VectorNode::is_roundopD(p0)) { - set_req_with_vector(pack, vtn, 1); - set_req_with_scalar(p0, vtn, 2); // constant rounding mode + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rounding mode } else if (p0->is_CMove()) { // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. set_all_req_with_vectors(pack, vtn); @@ -113,18 +113,18 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. if (n->is_Load()) { - set_req_with_scalar(n, vtn, MemNode::Address); + init_req_with_scalar(n, vtn, MemNode::Address); add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_Store()) { - set_req_with_scalar(n, vtn, MemNode::Address); - set_req_with_scalar(n, vtn, MemNode::ValueIn); + init_req_with_scalar(n, vtn, MemNode::Address); + init_req_with_scalar(n, vtn, MemNode::ValueIn); add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } 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, 0); + init_req_with_scalar(n, vtn, 0); continue; } else { set_all_req_with_scalars(n, vtn); @@ -177,9 +177,9 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co return vtn; } -void SuperWordVTransformBuilder::set_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { +void SuperWordVTransformBuilder::init_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); - vtn->set_req(index, req); + vtn->init_req(index, req); } // Either get the existing vtnode vector input (when input is a pack), or else make a @@ -217,7 +217,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i // 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); + populate_index->init_req(1, iv_vtn); return populate_index; } @@ -230,7 +230,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i 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); + shift_count->init_req(1, same_input_vtn); return shift_count; } else { // Replicate the scalar same_input to every vector element. @@ -245,11 +245,11 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i // 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); + conv->init_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); + replicate->init_req(1, same_input_vtn); return replicate; } } @@ -274,9 +274,9 @@ VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(N return vtn; } -void SuperWordVTransformBuilder::set_req_with_vector(const Node_List* pack, VTransformNode* vtn, int j) { +void SuperWordVTransformBuilder::init_req_with_vector(const Node_List* pack, VTransformNode* vtn, int j) { VTransformNode* req = get_or_make_vtnode_vector_input_at_index(pack, j); - vtn->set_req(j, req); + vtn->init_req(j, req); } void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn) { @@ -284,7 +284,7 @@ void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNod for (uint j = 0; j < n->req(); j++) { Node* def = n->in(j); if (def == nullptr) { continue; } - set_req_with_scalar(n, vtn, j); + init_req_with_scalar(n, vtn, j); } } @@ -295,7 +295,7 @@ void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, for (uint j = 1; j < vtn->req(); j++) { Node* def = p0->in(j); if (def == nullptr) { continue; } - set_req_with_vector(pack, vtn, j); + init_req_with_vector(pack, vtn, j); } } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index f2198113d31..fd85b87f825 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -77,8 +77,8 @@ private: 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, const int index); - void set_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); + void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); + void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); void set_all_req_with_scalars(Node* n, VTransformNode* vtn); void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index fb76a3b89d6..74905bc6915 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -341,7 +341,7 @@ public: vtransform.graph().add_vtnode(this); } - void set_req(uint i, VTransformNode* n) { + void init_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); From dacd9af9a02464d2d6144e29d851216641e836c9 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Mon, 1 Sep 2025 08:50:08 +0000 Subject: [PATCH 073/295] 8329829: HttpClient: Add a BodyPublishers.ofFileChannel method Reviewed-by: dfuchs, jpai, michaelm --- .../classes/java/net/http/HttpRequest.java | 44 +- .../internal/net/http/RequestPublishers.java | 80 +- .../jdk/internal/net/http/common/Utils.java | 22 + .../httpclient/FileChannelPublisherTest.java | 708 ++++++++++++++++++ 4 files changed, 849 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/net/httpclient/FileChannelPublisherTest.java diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java index 7ba6ed25b41..84a521336b6 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 +26,13 @@ package java.net.http; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.OpenOption; import java.nio.file.Path; import java.time.Duration; import java.util.Iterator; @@ -720,6 +720,44 @@ public abstract class HttpRequest { return RequestPublishers.FilePublisher.create(path); } + /** + * {@return a request body publisher whose body is the {@code length} + * content bytes read from the provided file {@code channel} starting + * from the specified {@code offset}} + *

        + * This method and the returned {@code BodyPublisher} do not modify the + * {@code channel}'s position, and do not close the {@code channel}. The + * caller is expected to close the {@code channel} when no longer needed. + * + * @apiNote + * This method can be used to either publish just a region of a file as + * the request body or to publish different regions of a file + * concurrently. A typical usage would be to publish different regions + * of a file by creating a single instance of {@link FileChannel} and + * then send multiple concurrent {@code HttpRequest}s, each of which + * uses a new {@code ofFileChannel BodyPublisher} created from the same + * channel with a different, typically non-overlapping, range of bytes + * specified by offset and length. + * + * @param channel a file channel + * @param offset the offset of the first byte + * @param length the number of bytes to read from the file channel + * + * @throws IndexOutOfBoundsException if the specified byte range is + * found to be {@linkplain Objects#checkFromIndexSize(long, long, long) + * out of bounds} compared with the size of the file referred by the + * channel + * + * @throws IOException if the {@linkplain FileChannel#size() channel's + * size} cannot be determined or the {@code channel} is closed + * + * @since 26 + */ + public static BodyPublisher ofFileChannel(FileChannel channel, long offset, long length) throws IOException { + Objects.requireNonNull(channel, "channel"); + return new RequestPublishers.FileChannelPublisher(channel, offset, length); + } + /** * A request body publisher that takes data from an {@code Iterable} * of byte arrays. An {@link Iterable} is provided which supplies diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java index dd5443c5035..88cabe15419 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java @@ -32,6 +32,7 @@ import java.io.UncheckedIOException; import java.lang.reflect.UndeclaredThrowableException; import java.net.http.HttpRequest.BodyPublisher; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.NoSuchFileException; @@ -418,6 +419,81 @@ public final class RequestPublishers { } } + public static final class FileChannelPublisher implements BodyPublisher { + + private final FileChannel channel; + + private final long position; + + private final long limit; + + public FileChannelPublisher(FileChannel channel, long offset, long length) throws IOException { + this.channel = Objects.requireNonNull(channel, "channel"); + long fileSize = channel.size(); + Objects.checkFromIndexSize(offset, length, fileSize); + this.position = offset; + this.limit = offset + length; + } + + @Override + public long contentLength() { + return limit - position; + } + + @Override + public void subscribe(Flow.Subscriber subscriber) { + Iterable iterable = () -> new FileChannelIterator(channel, position, limit); + new PullPublisher<>(iterable).subscribe(subscriber); + } + + } + + private static final class FileChannelIterator implements Iterator { + + private final FileChannel channel; + + private final long limit; + + private long position; + + private boolean terminated; + + private FileChannelIterator(FileChannel channel, long position, long limit) { + this.channel = channel; + this.position = position; + this.limit = limit; + } + + @Override + public boolean hasNext() { + return position < limit && !terminated; + } + + @Override + public ByteBuffer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + long remaining = limit - position; + ByteBuffer buffer = Utils.getBufferWithAtMost(remaining); + try { + int readLength = channel.read(buffer, position); + // Short-circuit if `read()` has failed, e.g., due to file content being changed in the meantime + if (readLength < 0) { + // Throw to signal that the request needs to be cancelled + throw new IOException("Unexpected EOF (position=%s)".formatted(position)); + } else { + position += readLength; + } + } catch (IOException ioe) { + terminated = true; + throw new UncheckedIOException(ioe); + } + return buffer.flip(); + } + + } + public static final class PublisherAdapter implements BodyPublisher { private final Publisher publisher; @@ -430,12 +506,12 @@ public final class RequestPublishers { } @Override - public final long contentLength() { + public long contentLength() { return contentLength; } @Override - public final void subscribe(Flow.Subscriber subscriber) { + public void subscribe(Flow.Subscriber subscriber) { publisher.subscribe(subscriber); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index b10c7cd5957..bcedff8844e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -392,10 +392,32 @@ public final class Utils { public static IllegalArgumentException newIAE(String message, Object... args) { return new IllegalArgumentException(format(message, args)); } + + /** + * {@return a new {@link ByteBuffer} instance of {@link #BUFSIZE} capacity} + */ public static ByteBuffer getBuffer() { return ByteBuffer.allocate(BUFSIZE); } + /** + * {@return a new {@link ByteBuffer} instance whose capacity is set to the + * smaller of the specified {@code maxCapacity} and the default + * ({@value BUFSIZE})} + * + * @param maxCapacity a buffer capacity, in bytes + * @throws IllegalArgumentException if {@code maxCapacity < 0} + */ + public static ByteBuffer getBufferWithAtMost(long maxCapacity) { + if (maxCapacity < 0) { + throw new IllegalArgumentException( + // Match the message produced by `ByteBuffer::createCapacityException` + "capacity < 0: (%s < 0)".formatted(maxCapacity)); + } + int effectiveCapacity = (int) Math.min(maxCapacity, BUFSIZE); + return ByteBuffer.allocate(effectiveCapacity); + } + public static Throwable getCompletionCause(Throwable x) { Throwable cause = x; while ((cause instanceof CompletionException) diff --git a/test/jdk/java/net/httpclient/FileChannelPublisherTest.java b/test/jdk/java/net/httpclient/FileChannelPublisherTest.java new file mode 100644 index 00000000000..5b064efa078 --- /dev/null +++ b/test/jdk/java/net/httpclient/FileChannelPublisherTest.java @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 Verifies `HttpRequest.BodyPublishers::ofFileChannel` + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * @run junit FileChannelPublisherTest + */ + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpResponse.BodyHandlers.discarding; +import static java.net.http.HttpResponse.BodyHandlers.ofInputStream; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FileChannelPublisherTest { + + private static final String CLASS_NAME = FileChannelPublisherTest.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static final int DEFAULT_BUFFER_SIZE = Utils.getBuffer().capacity(); + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + private static final HttpClient CLIENT = HttpClient.newBuilder().sslContext(SSL_CONTEXT).proxy(NO_PROXY).build(); + + private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(); + + private static final ServerRequestPair + HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false), + HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true), + HTTP2 = ServerRequestPair.of(Version.HTTP_2, false), + HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true); + + private static SSLContext createSslContext() { + try { + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private record ServerRequestPair( + String serverName, + HttpTestServer server, + BlockingQueue serverReadRequestBodyBytes, + HttpRequest.Builder requestBuilder, + boolean secure) { + + private static CountDownLatch SERVER_REQUEST_RECEIVED_SIGNAL = null; + + private static CountDownLatch SERVER_READ_PERMISSION = null; + + private static ServerRequestPair of(Version version, boolean secure) { + + // Create the server + SSLContext sslContext = secure ? SSL_CONTEXT : null; + HttpTestServer server = createServer(version, sslContext); + String serverName = secure ? version.toString().replaceFirst("_", "S_") : version.toString(); + + // Add the handler + String handlerPath = "/%s/".formatted(CLASS_NAME); + BlockingQueue serverReadRequestBodyBytes = + addRequestBodyConsumingServerHandler(serverName, server, handlerPath); + + // Create the request builder + String requestUriScheme = secure ? "https" : "http"; + // `x` suffix in the URI is not a typo, but ensures that *only* the parent handler path is matched + URI requestUri = URI.create("%s://%s%sx".formatted(requestUriScheme, server.serverAuthority(), handlerPath)); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(requestUri).version(version); + + // Create the pair + ServerRequestPair pair = new ServerRequestPair(serverName, server, serverReadRequestBodyBytes, requestBuilder, secure); + pair.server.start(); + LOGGER.log("Server[%s] is started at `%s`", pair, server.serverAuthority()); + + return pair; + + } + + private static HttpTestServer createServer(Version version, SSLContext sslContext) { + try { + // The default HTTP/1.1 test server processes requests sequentially. + // This causes a deadlock for concurrent tests such as `testSlicedUpload()`. + // Hence, explicitly providing a multithreaded executor for HTTP/1.1. + ExecutorService executor = Version.HTTP_1_1.equals(version) ? EXECUTOR : null; + return HttpTestServer.create(version, sslContext, executor); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + private static BlockingQueue addRequestBodyConsumingServerHandler( + String serverName, HttpTestServer server, String handlerPath) { + BlockingQueue readRequestBodyBytes = new LinkedBlockingQueue<>(); + HttpTestHandler handler = exchange -> { + // `HttpTestExchange::toString` changes on failure, pin it + String exchangeName = exchange.toString(); + try (exchange) { + + // Discard `HEAD` requests used for initial connection admission + if ("HEAD".equals(exchange.getRequestMethod())) { + exchange.sendResponseHeaders(200, -1L); + return; + } + + signalServerRequestReceived(serverName, exchangeName); + awaitServerReadPermission(serverName, exchangeName); + + LOGGER.log("Server[%s] is reading the request body (exchange=%s)", serverName, exchangeName); + byte[] requestBodyBytes = exchange.getRequestBody().readAllBytes(); + LOGGER.log("Server[%s] has read %s bytes (exchange=%s)", serverName, requestBodyBytes.length, exchangeName); + readRequestBodyBytes.add(requestBodyBytes); + + LOGGER.log("Server[%s] is writing the response (exchange=%s)", serverName, exchangeName); + exchange.sendResponseHeaders(200, requestBodyBytes.length); + exchange.getResponseBody().write(requestBodyBytes); + + } catch (Throwable exception) { + LOGGER.log( + "Server[%s] failed to process the request (exchange=%s)".formatted(serverName, exception), + exception); + readRequestBodyBytes.add(new byte[0]); + } finally { + LOGGER.log("Server[%s] completed processing the request (exchange=%s)", serverName, exchangeName); + } + }; + server.addHandler(handler, handlerPath); + return readRequestBodyBytes; + } + + private static void signalServerRequestReceived(String serverName, String exchangeName) { + if (SERVER_REQUEST_RECEIVED_SIGNAL != null) { + LOGGER.log("Server[%s] is signaling that the request is received (exchange=%s)", serverName, exchangeName); + SERVER_REQUEST_RECEIVED_SIGNAL.countDown(); + } + } + + private static void awaitServerReadPermission(String serverName, String exchangeName) { + if (SERVER_READ_PERMISSION != null) { + LOGGER.log("Server[%s] is waiting for the read permission (exchange=%s)", serverName, exchangeName); + try { + SERVER_READ_PERMISSION.await(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); // Restore the `interrupted` flag + throw new RuntimeException(ie); + } + } + } + + @Override + public String toString() { + return serverName; + } + + } + + @AfterAll + static void shutDown() { + LOGGER.log("Closing the client"); + CLIENT.close(); + LOGGER.log("Closing servers"); + closeServers(); + LOGGER.log("Closing the executor"); + EXECUTOR.shutdownNow(); + } + + private static void closeServers() { + Exception[] exceptionRef = {null}; + Stream + .of(HTTP1, HTTPS1, HTTP2, HTTPS2) + .map(pair -> (Runnable) pair.server::stop) + .forEach(terminator -> { + try { + terminator.run(); + } catch (Exception exception) { + if (exceptionRef[0] == null) { + exceptionRef[0] = exception; + } else { + exceptionRef[0].addSuppressed(exception); + } + } + }); + if (exceptionRef[0] != null) { + throw new RuntimeException("failed closing one or more server resources", exceptionRef[0]); + } + } + + /** + * Resets {@link ServerRequestPair#serverReadRequestBodyBytes()} to avoid leftover state from a test leaking to the next. + */ + @BeforeEach + void resetServerHandlerResults() { + Stream + .of(HTTP1, HTTPS1, HTTP2, HTTPS2) + .forEach(pair -> pair.serverReadRequestBodyBytes.clear()); + } + + static ServerRequestPair[] serverRequestPairs() { + return new ServerRequestPair[]{ + HTTP1, + HTTPS1, + HTTP2, + HTTPS2 + }; + } + + @Test + void testNullFileChannel() { + assertThrows(NullPointerException.class, () -> BodyPublishers.ofFileChannel(null, 0, 1)); + } + + @ParameterizedTest + @CsvSource({ + "6,-1,1", // offset < 0 + "6,7,1", // offset > fileSize + "6,0,-1", // length < 0 + "6,0,7", // length > fileSize + "6,2,5" // (offset + length) > fileSize + }) + void testIllegalOffsetOrLength( + int fileLength, + int fileChannelOffset, + int fileChannelLength, + @TempDir Path tempDir) throws Exception { + withFileChannel(tempDir.resolve("data.txt"), fileLength, (_, fileChannel) -> + assertThrows( + IndexOutOfBoundsException.class, + () -> BodyPublishers.ofFileChannel(fileChannel, fileChannelOffset, fileChannelLength))); + } + + /** + * Stresses corner cases in {@linkplain + * BodyPublishers#ofFileChannel(FileChannel, long, long) the file channel + * publisher}, which uses a {@linkplain #DEFAULT_BUFFER_SIZE fixed size} + * buffer to read files, by providing sub-ranges and files that are + * smaller than the buffer size. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testContentLessThanBufferSize(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + + // Use a file of length smaller than the default buffer size + int fileLength = 6; + assertTrue(fileLength < DEFAULT_BUFFER_SIZE); + + // Publish the `[0, fileLength)` sub-range + testSuccessfulContentDelivery( + "Complete content", + pair, tempDir, fileLength, 0, fileLength); + + // Publish the `[1, fileLength)` sub-range to stress the inclusion of EOF + { + int fileChannelOffset = 1; + int fileChannelLength = fileLength - 1; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertEquals( + fileLength - fileChannelOffset, fileChannelLength, + "must be until EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content until the EOF " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength - 1)` sub-range to stress the exclusion of EOF + { + int fileChannelOffset = 1; + int fileChannelLength = fileLength - 2; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertTrue( + fileLength - fileChannelOffset > fileChannelLength, + "must end before EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content *before* the EOF " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + } + + /** + * Stresses corner cases in {@linkplain + * BodyPublishers#ofFileChannel(FileChannel, long, long) the file channel + * publisher}, which uses a {@linkplain #DEFAULT_BUFFER_SIZE fixed size} + * buffer to read files, by providing sub-ranges and files that are + * bigger than the buffer size. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testContentMoreThanBufferSize(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + + // Use a file of length that is + // 1. greater than the default buffer size + // 2. *not* a multitude of the buffer size + int fileLength = 1 + 3 * DEFAULT_BUFFER_SIZE; + + // Publish the `[0, fileLength)` sub-range + testSuccessfulContentDelivery( + "Complete content", + pair, tempDir, fileLength, 0, fileLength); + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is included + // - the total length is a multitude of the buffer size + { + int fileChannelOffset = 1; + int fileChannelLength = 3 * DEFAULT_BUFFER_SIZE; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertEquals( + fileLength - fileChannelOffset, fileChannelLength, + "must be until EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content until the EOF. Occupies exactly 3 buffers. " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is included + // - the total length is *not* a multitude of the buffer size + { + int fileChannelOffset = 2; + int fileChannelLength = 3 * DEFAULT_BUFFER_SIZE - 1; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertEquals( + fileLength - fileChannelOffset, fileChannelLength, + "must be until EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content until the EOF. Occupies 3 buffers, the last is custom sized. " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is *not* included + // - the total length is a multitude of the buffer size + { + int fileChannelOffset = 2; + int fileChannelLength = 2 * DEFAULT_BUFFER_SIZE; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertTrue( + fileLength - fileChannelOffset > fileChannelLength, + "must end before EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content *before* the EOF. Occupies exactly 2 buffers. " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is *not* included + // - the total length is *not* a multitude of the buffer size + { + int fileChannelOffset = 2; + int fileChannelLength = 3 * DEFAULT_BUFFER_SIZE - 2; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertTrue( + fileLength - fileChannelOffset > fileChannelLength, + "must end before EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content *before* the EOF. Occupies 3 buffers, the last is custom sized. "+ debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + } + + private static String debuggingContext(int fileLength, int fileChannelOffset, int fileChannelLength) { + Map context = new LinkedHashMap<>(); // Using `LHM` to preserve the insertion order + context.put("DEFAULT_BUFFER_SIZE", DEFAULT_BUFFER_SIZE); + context.put("fileLength", fileLength); + context.put("fileChannelOffset", fileChannelOffset); + context.put("fileChannelLength", fileChannelLength); + boolean customSizedBuffer = fileChannelLength % DEFAULT_BUFFER_SIZE == 0; + context.put("customSizedBuffer", customSizedBuffer); + return context.toString(); + } + + private void testSuccessfulContentDelivery( + String caseDescription, + ServerRequestPair pair, + Path tempDir, + int fileLength, + int fileChannelOffset, + int fileChannelLength) throws Exception { + + // Case names come handy even when no debug logging is enabled. + // Hence, intentionally avoiding `Logger`. + System.err.printf("Case: %s%n", caseDescription); + + // Create the file to upload + String fileName = "data-%d-%d-%d.txt".formatted(fileLength, fileChannelOffset, fileChannelLength); + Path filePath = tempDir.resolve(fileName); + withFileChannel(filePath, fileLength, (fileBytes, fileChannel) -> { + + // Upload the file + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, fileChannelOffset, fileChannelLength)) + .build(); + CLIENT.send(request, discarding()); + + // Verify the received request body + byte[] expectedRequestBodyBytes = new byte[fileChannelLength]; + System.arraycopy(fileBytes, fileChannelOffset, expectedRequestBodyBytes, 0, fileChannelLength); + byte[] actualRequestBodyBytes = pair.serverReadRequestBodyBytes.take(); + assertArrayEquals(expectedRequestBodyBytes, actualRequestBodyBytes); + + }); + + } + + /** + * Big enough file length to observe the effects of publisher state corruption while uploading. + *

        + * Certain tests follow below steps: + *

        + *
          + *
        1. Issue the request
        2. + *
        3. Wait for the server's signal that the request (not the body!) is received
        4. + *
        5. Corrupt the publisher's state; modify the file, close the file channel, etc.
        6. + *
        7. Signal the server to proceed with reading
        8. + *
        + *

        + * With small files, even before we permit the server to read (step 4), file gets already uploaded. + * This voids the effect of state corruption (step 3). + * To circumvent this, use this big enough file size. + *

        + * + * @see #testChannelCloseDuringPublisherRead(ServerRequestPair, Path) + * @see #testFileModificationDuringPublisherRead(ServerRequestPair, Path) + */ + private static final int BIG_FILE_LENGTH = 8 * 1024 * 1024; // 8 MiB + + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testChannelCloseDuringPublisherRead(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + establishInitialConnection(pair); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = new CountDownLatch(1); + ServerRequestPair.SERVER_READ_PERMISSION = new CountDownLatch(1); + try { + + int fileLength = BIG_FILE_LENGTH; + AtomicReference>> responseFutureRef = new AtomicReference<>(); + withFileChannel(tempDir.resolve("data.txt"), fileLength, ((_, fileChannel) -> { + + // Issue the request + LOGGER.log("Issuing the request"); + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, 0, fileLength)) + .build(); + responseFutureRef.set(CLIENT.sendAsync(request, discarding())); + + // Wait for server to receive the request + LOGGER.log("Waiting for the request to be received"); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL.await(); + + })); + + LOGGER.log("File channel is closed"); + + // Let the server proceed + LOGGER.log("Permitting the server to proceed"); + ServerRequestPair.SERVER_READ_PERMISSION.countDown(); + + // Verifying the client failure + LOGGER.log("Verifying the client failure"); + Exception requestFailure0 = assertThrows(ExecutionException.class, () -> responseFutureRef.get().get()); + Exception requestFailure1 = assertInstanceOf(UncheckedIOException.class, requestFailure0.getCause()); + assertInstanceOf(ClosedChannelException.class, requestFailure1.getCause()); + + verifyServerIncompleteRead(pair, fileLength); + + } finally { + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = null; + ServerRequestPair.SERVER_READ_PERMISSION = null; + } + } + + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testFileModificationDuringPublisherRead(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + establishInitialConnection(pair); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = new CountDownLatch(1); + ServerRequestPair.SERVER_READ_PERMISSION = new CountDownLatch(1); + try { + + int fileLength = BIG_FILE_LENGTH; + Path filePath = tempDir.resolve("data.txt"); + withFileChannel(filePath, fileLength, ((_, fileChannel) -> { + + // Issue the request + LOGGER.log("Issuing the request"); + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, 0, fileLength)) + .build(); + Future> responseFuture = CLIENT.sendAsync(request, discarding()); + + // Wait for server to receive the request + LOGGER.log("Waiting for the request to be received"); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL.await(); + + // Modify the file + LOGGER.log("Modifying the file"); + Files.write(filePath, generateFileBytes(1)); + + // Let the server proceed + LOGGER.log("Permitting the server to proceed"); + ServerRequestPair.SERVER_READ_PERMISSION.countDown(); + + // Verifying the client failure + LOGGER.log("Verifying the client failure"); + Exception requestFailure0 = assertThrows(ExecutionException.class, responseFuture::get); + Exception requestFailure1 = assertInstanceOf(UncheckedIOException.class, requestFailure0.getCause()); + Exception requestFailure2 = assertInstanceOf(IOException.class, requestFailure1.getCause()); + String requestFailure2Message = requestFailure2.getMessage(); + assertTrue( + requestFailure2Message.contains("Unexpected EOF"), + "unexpected message: " + requestFailure2Message); + + verifyServerIncompleteRead(pair, fileLength); + + })); + + } finally { + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = null; + ServerRequestPair.SERVER_READ_PERMISSION = null; + } + } + + private static void verifyServerIncompleteRead(ServerRequestPair pair, int fileLength) throws InterruptedException { + LOGGER.log("Verifying the server's incomplete read"); + byte[] readRequestBodyBytes = pair.serverReadRequestBodyBytes.take(); + assertTrue( + readRequestBodyBytes.length < fileLength, + "was expecting `readRequestBodyBytes < fileLength` (%s < %s)".formatted( + readRequestBodyBytes.length, fileLength)); + } + + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSlicedUpload(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + + // Populate the file + int sliceCount = 4; + int sliceLength = 14_281; // Intentionally using a prime number to increase the chances of hitting corner cases + int fileLength = sliceCount * sliceLength; + byte[] fileBytes = generateFileBytes(fileLength); + Path filePath = tempDir.resolve("data.txt"); + Files.write(filePath, fileBytes, StandardOpenOption.CREATE); + + List responseBodyStreams = new ArrayList<>(sliceCount); + try (FileChannel fileChannel = FileChannel.open(filePath)) { + + // Upload the complete file in mutually exclusive slices + List>> responseFutures = new ArrayList<>(sliceCount); + for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { + LOGGER.log("Issuing request %d/%d", (sliceIndex + 1), sliceCount); + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, sliceIndex * sliceLength, sliceLength)) + .build(); + responseFutures.add(CLIENT.sendAsync( + request, + // Intentionally using an `InputStream` response + // handler to defer consuming the response body + // until after the file channel is closed: + ofInputStream())); + } + + // Collect response body `InputStream`s from all requests + for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { + LOGGER.log("Collecting response body `InputStream` for request %d/%d", (sliceIndex + 1), sliceCount); + HttpResponse response = responseFutures.get(sliceIndex).get(); + assertEquals(200, response.statusCode()); + responseBodyStreams.add(response.body()); + } + + } + + LOGGER.log("File channel is closed"); + + // Verify response bodies + for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { + LOGGER.log("Consuming response body %d/%d", (sliceIndex + 1), sliceCount); + byte[] expectedResponseBodyBytes = new byte[sliceLength]; + System.arraycopy(fileBytes, sliceIndex * sliceLength, expectedResponseBodyBytes, 0, sliceLength); + try (InputStream responseBodyStream = responseBodyStreams.get(sliceIndex)) { + byte[] responseBodyBytes = responseBodyStream.readAllBytes(); + assertArrayEquals(expectedResponseBodyBytes, responseBodyBytes); + } + } + + } + + /** + * Performs the initial {@code HEAD} request to the specified server. This + * effectively admits a connection to the client's pool, where all protocol + * upgrades, handshakes, etc. are already performed. + *

        + * HTTP/2 test server consumes the complete request payload in the very + * first upgrade frame. That is, if a client sends 100 MiB of data, all + * of it will be consumed first before the configured handler is + * invoked. Though certain tests expect the data to be consumed + * piecemeal. To accommodate this, we ensure client has an upgraded + * connection in the pool. + *

        + */ + private static void establishInitialConnection(ServerRequestPair pair) { + LOGGER.log("Server[%s] is getting queried for the initial connection pool admission", pair); + try { + CLIENT.send(pair.requestBuilder.HEAD().build(), discarding()); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + } + + private static void withFileChannel(Path filePath, int fileLength, FileChannelConsumer fileChannelConsumer) throws Exception { + byte[] fileBytes = generateFileBytes(fileLength); + Files.write(filePath, fileBytes, StandardOpenOption.CREATE); + try (FileChannel fileChannel = FileChannel.open(filePath)) { + fileChannelConsumer.consume(fileBytes, fileChannel); + } + } + + @FunctionalInterface + private interface FileChannelConsumer { + + void consume(byte[] fileBytes, FileChannel fileChannel) throws Exception; + + } + + private static byte[] generateFileBytes(int length) { + byte[] bytes = new byte[length]; + for (int i = 0; i < length; i++) { + bytes[i] = (byte) i; + } + return bytes; + } + +} From fc77e7600f217cc91c24d4e512c685e176a66e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 1 Sep 2025 08:55:23 +0000 Subject: [PATCH 074/295] 8365791: IGV: Update build dependencies Reviewed-by: chagedorn, ayang --- src/utils/IdealGraphVisualizer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/IdealGraphVisualizer/pom.xml b/src/utils/IdealGraphVisualizer/pom.xml index 7f9bd67af42..8fdb182ed90 100644 --- a/src/utils/IdealGraphVisualizer/pom.xml +++ b/src/utils/IdealGraphVisualizer/pom.xml @@ -116,7 +116,7 @@ 3.3.0 3.4.1 4.13.2 - 1.17 + 1.19 1.3.34 1.6.2 idealgraphvisualizer From 7f0cd6488ba969d5cffe8ebe9b95e4ad70982188 Mon Sep 17 00:00:00 2001 From: Bhavana Kilambi Date: Mon, 1 Sep 2025 09:18:29 +0000 Subject: [PATCH 075/295] 8361582: AArch64: Some ConH values cannot be replicated with SVE Reviewed-by: shade, epeter, aph --- src/hotspot/cpu/aarch64/aarch64.ad | 35 +++-- src/hotspot/cpu/aarch64/aarch64_vector.ad | 32 +++-- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 32 +++-- src/hotspot/cpu/aarch64/assembler_aarch64.cpp | 5 + src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 1 + .../c2/aarch64/TestFloat16Replicate.java | 136 ++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 10 ++ 7 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 9697ac31350..33466453b76 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -4412,10 +4412,9 @@ operand immI8() %} // 8 bit signed value (simm8), or #simm8 LSL 8. -operand immI8_shift8() +operand immIDupV() %{ - predicate((n->get_int() <= 127 && n->get_int() >= -128) || - (n->get_int() <= 32512 && n->get_int() >= -32768 && (n->get_int() & 0xff) == 0)); + predicate(Assembler::operand_valid_for_sve_dup_immediate((int64_t)n->get_int())); match(ConI); op_cost(0); @@ -4424,10 +4423,9 @@ operand immI8_shift8() %} // 8 bit signed value (simm8), or #simm8 LSL 8. -operand immL8_shift8() +operand immLDupV() %{ - predicate((n->get_long() <= 127 && n->get_long() >= -128) || - (n->get_long() <= 32512 && n->get_long() >= -32768 && (n->get_long() & 0xff) == 0)); + predicate(Assembler::operand_valid_for_sve_dup_immediate(n->get_long())); match(ConL); op_cost(0); @@ -4435,6 +4433,17 @@ operand immL8_shift8() interface(CONST_INTER); %} +// 8 bit signed value (simm8), or #simm8 LSL 8. +operand immHDupV() +%{ + predicate(Assembler::operand_valid_for_sve_dup_immediate((int64_t)n->geth())); + match(ConH); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 8 bit integer valid for vector add sub immediate operand immBAddSubV() %{ @@ -7077,18 +7086,16 @@ instruct loadConD(vRegD dst, immD con) %{ %} // Load Half Float Constant -// The "ldr" instruction loads a 32-bit word from the constant pool into a -// 32-bit register but only the bottom half will be populated and the top -// 16 bits are zero. instruct loadConH(vRegF dst, immH con) %{ match(Set dst con); - format %{ - "ldrs $dst, [$constantaddress]\t# load from constant table: half float=$con\n\t" - %} + format %{ "mov rscratch1, $con\n\t" + "fmov $dst, rscratch1" + %} ins_encode %{ - __ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con)); + __ movw(rscratch1, (uint32_t)$con$$constant); + __ fmovs($dst$$FloatRegister, rscratch1); %} - ins_pipe(fp_load_constant_s); + ins_pipe(pipe_class_default); %} // Store Instructions diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 58300992c2a..67c4dad27a7 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -4875,7 +4875,7 @@ instruct replicateB_imm8_gt128b(vReg dst, immI8 con) %{ ins_pipe(pipe_slow); %} -instruct replicateI_imm8_gt128b(vReg dst, immI8_shift8 con) %{ +instruct replicateI_imm8_gt128b(vReg dst, immIDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16 && (Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); @@ -4898,7 +4898,7 @@ instruct replicateL_imm_128b(vReg dst, immL con) %{ ins_pipe(pipe_slow); %} -instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ +instruct replicateL_imm8_gt128b(vReg dst, immLDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16); match(Set dst (Replicate con)); format %{ "replicateL_imm8_gt128b $dst, $con\t# vector > 128 bits" %} @@ -4909,19 +4909,27 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ ins_pipe(pipe_slow); %} -// Replicate a 16-bit half precision float value -instruct replicateHF_imm(vReg dst, immH con) %{ +// Replicate an immediate 16-bit half precision float value +instruct replicateHF_imm_le128b(vReg dst, immH con) %{ + predicate(Matcher::vector_length_in_bytes(n) <= 16); match(Set dst (Replicate con)); - format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %} + format %{ "replicateHF_imm_le128b $dst, $con\t# vector <= 128 bits" %} ins_encode %{ - uint length_in_bytes = Matcher::vector_length_in_bytes(this); int imm = (int)($con$$constant) & 0xffff; - if (VM_Version::use_neon_for_vector(length_in_bytes)) { - __ mov($dst$$FloatRegister, get_arrangement(this), imm); - } else { // length_in_bytes must be > 16 and SVE should be enabled - assert(UseSVE > 0, "must be sve"); - __ sve_dup($dst$$FloatRegister, __ H, imm); - } + __ mov($dst$$FloatRegister, get_arrangement(this), imm); + %} + ins_pipe(pipe_slow); +%} + +// Replicate a 16-bit half precision float which is within the limits +// for the operand - immHDupV +instruct replicateHF_imm8_gt128b(vReg dst, immHDupV con) %{ + predicate(Matcher::vector_length_in_bytes(n) > 16); + match(Set dst (Replicate con)); + format %{ "replicateHF_imm8_gt128b $dst, $con\t# vector > 128 bits" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_dup($dst$$FloatRegister, __ H, (int)($con$$constant)); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 4d91e04dc21..28f91204ec3 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -3107,7 +3107,7 @@ instruct replicateB_imm8_gt128b(vReg dst, immI8 con) %{ ins_pipe(pipe_slow); %} -instruct replicateI_imm8_gt128b(vReg dst, immI8_shift8 con) %{ +instruct replicateI_imm8_gt128b(vReg dst, immIDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16 && (Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); @@ -3130,7 +3130,7 @@ instruct replicateL_imm_128b(vReg dst, immL con) %{ ins_pipe(pipe_slow); %} -instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ +instruct replicateL_imm8_gt128b(vReg dst, immLDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16); match(Set dst (Replicate con)); format %{ "replicateL_imm8_gt128b $dst, $con\t# vector > 128 bits" %} @@ -3141,19 +3141,27 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ ins_pipe(pipe_slow); %} -// Replicate a 16-bit half precision float value -instruct replicateHF_imm(vReg dst, immH con) %{ +// Replicate an immediate 16-bit half precision float value +instruct replicateHF_imm_le128b(vReg dst, immH con) %{ + predicate(Matcher::vector_length_in_bytes(n) <= 16); match(Set dst (Replicate con)); - format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %} + format %{ "replicateHF_imm_le128b $dst, $con\t# vector <= 128 bits" %} ins_encode %{ - uint length_in_bytes = Matcher::vector_length_in_bytes(this); int imm = (int)($con$$constant) & 0xffff; - if (VM_Version::use_neon_for_vector(length_in_bytes)) { - __ mov($dst$$FloatRegister, get_arrangement(this), imm); - } else { // length_in_bytes must be > 16 and SVE should be enabled - assert(UseSVE > 0, "must be sve"); - __ sve_dup($dst$$FloatRegister, __ H, imm); - } + __ mov($dst$$FloatRegister, get_arrangement(this), imm); + %} + ins_pipe(pipe_slow); +%} + +// Replicate a 16-bit half precision float which is within the limits +// for the operand - immHDupV +instruct replicateHF_imm8_gt128b(vReg dst, immHDupV con) %{ + predicate(Matcher::vector_length_in_bytes(n) > 16); + match(Set dst (Replicate con)); + format %{ "replicateHF_imm8_gt128b $dst, $con\t# vector > 128 bits" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_dup($dst$$FloatRegister, __ H, (int)($con$$constant)); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp index 5e5d6c16b45..fe1792ed1c6 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp @@ -434,6 +434,11 @@ int Assembler::operand_valid_for_movi_immediate(uint64_t imm64, SIMD_Arrangement return -1; } +bool Assembler::operand_valid_for_sve_dup_immediate(int64_t imm) { + return ((imm >= -128 && imm <= 127) || + (((imm & 0xff) == 0) && imm >= -32768 && imm <= 32512)); +} + bool Assembler::operand_valid_for_sve_logical_immediate(unsigned elembits, uint64_t imm) { return encode_sve_logical_immediate(elembits, imm) != 0xffffffff; } diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 11d302e9026..4b0a0e77915 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -4324,6 +4324,7 @@ public: static bool operand_valid_for_sve_add_sub_immediate(int64_t imm); static bool operand_valid_for_float_immediate(double imm); static int operand_valid_for_movi_immediate(uint64_t imm64, SIMD_Arrangement T); + static bool operand_valid_for_sve_dup_immediate(int64_t imm); void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java new file mode 100644 index 00000000000..ab7808a0401 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java @@ -0,0 +1,136 @@ +/* Copyright (c) 2025, Arm 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. + * + * 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 8361582 +* @summary Ensure the correct backend replicate node is being generated for +* half precision float constants on >16B SVE machines +* @modules jdk.incubator.vector +* @library /test/lib / +* @run main/othervm compiler.c2.aarch64.TestFloat16Replicate +*/ + +package compiler.c2.aarch64; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import java.util.Arrays; +import java.util.Random; +import jdk.incubator.vector.Float16; +import jdk.test.lib.*; +import jdk.test.lib.Utils; + +import static java.lang.Float.*; +import static jdk.incubator.vector.Float16.*; + +public class TestFloat16Replicate { + private static short[] input; + private static short[] output; + private static short[] expected; + private static Random rnd; + + // Choose FP16_IMM8 which is within the range of [-128 << 8, 127 << 8] and a multiple of 256 + private static final Float16 FP16_IMM8; + + // Choose a value in the range [-128 << 8, 127 << 8] and a non multiple of 256 for FP16_NON_IMM8 + private static final Float16 FP16_NON_IMM8; + + private static final int LEN = 1024; + + public static void main(String args[]) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:-TieredCompilation"); + } + + static { + rnd = Utils.getRandomInstance(); + int k = rnd.nextInt(-128, 128); + int b = rnd.nextInt(1, 256); + short bits_imm8 = (short) (k << 8); + short bits_non_imm8 = (short) ((k << 8) + b); + + FP16_IMM8 = Float16.shortBitsToFloat16(bits_imm8); + FP16_NON_IMM8 = Float16.shortBitsToFloat16(bits_non_imm8); + + input = new short[LEN]; + output = new short[LEN]; + expected = new short[LEN]; + + for (int i = 0; i < LEN; i++) { + input[i] = (short) i; + } + } + + // For vectorizable loops containing FP16 operations with an FP16 constant as one of the inputs, the IR + // node `(dst (Replicate con))` is generated to broadcast the constant into all lanes of an SVE register. + // On SVE-capable hardware with vector length > 16B, if the FP16 immediate is a signed value within the + // range [-128, 127] or a signed multiple of 256 in the range [-32768, 32512] for element widths of + // 16 bits or higher then the backend should generate the "replicateHF_imm_gt128b" machnode. + @Test + @Warmup(5000) + @IR(counts = {IRNode.REPLICATE_HF_IMM8, ">0"}, + phase = CompilePhase.FINAL_CODE, + applyIf = {"MaxVectorSize", ">16"}, + applyIfCPUFeature = {"sve", "true"}) + public void TestFloat16AddInRange() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(Float16.add(shortBitsToFloat16(input[i]), FP16_IMM8)); + } + } + + @Check(test="TestFloat16AddInRange") + public void checkResultFloat16AddInRange() { + for (int i = 0; i < LEN; ++i) { + expected[i] = floatToFloat16(float16ToFloat(input[i]) + FP16_IMM8.floatValue()); + } + Verify.checkEQWithRawBits(output, expected); + } + + // For vectorizable loops containing FP16 operations with an FP16 constant as one of the inputs, the IR + // node `(dst (Replicate con))` is generated to broadcast the constant into all lanes of an SVE register. + // On SVE-capable hardware with vector length > 16B, if the FP16 constant falls outside the immediate + // range accepted by the SVE "dup" instruction, the backend must: + // 1. Generate the "loadConH" machnode to load the FP16 constant from the constant pool. + // 2. Emit the "replicateHF" machnode to broadcast this loaded constant into an SVE register. + // In this case, the backend should not generate the "replicateHF_imm8_gt128b" machnode. + @Test + @Warmup(5000) + @IR(counts = {IRNode.REPLICATE_HF, ">0"}, + failOn = {IRNode.REPLICATE_HF_IMM8}, + phase = CompilePhase.FINAL_CODE, + applyIf = {"MaxVectorSize", ">16"}, + applyIfCPUFeature = {"sve", "true"}) + public void TestFloat16AddOutOfRange() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(add(shortBitsToFloat16(input[i]), FP16_NON_IMM8)); + } + } + + @Check(test="TestFloat16AddOutOfRange") + public void checkResultFloat16AddOutOfRange() { + for (int i = 0; i < LEN; ++i) { + expected[i] = floatToFloat16(float16ToFloat(input[i]) + FP16_NON_IMM8.floatValue()); + } + Verify.checkEQWithRawBits(output, expected); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 7fb1eeb800c..16c6d99a64f 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2896,6 +2896,16 @@ public class IRNode { vectorNode(SELECT_FROM_TWO_VECTOR_VL, "SelectFromTwoVector", TYPE_LONG); } + public static final String REPLICATE_HF = PREFIX + "REPLICATE_HF" + POSTFIX; + static { + machOnlyNameRegex(REPLICATE_HF, "replicateHF"); + } + + public static final String REPLICATE_HF_IMM8 = PREFIX + "REPLICATE_HF_IMM8" + POSTFIX; + static { + machOnlyNameRegex(REPLICATE_HF_IMM8, "replicateHF_imm8_gt128b"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ From 98af18921aa3c274ef7ece03005337b58df3da96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 1 Sep 2025 09:24:52 +0000 Subject: [PATCH 076/295] 8366456: Allow AllocFailStrategy for RBTree Reviewed-by: cnorrbin, aboldtch --- src/hotspot/share/utilities/rbTree.hpp | 26 +++++++---- test/hotspot/gtest/utilities/test_rbtree.cpp | 46 ++++++++++++-------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 405fa3e9ae9..cc52cec3fe0 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -61,7 +61,6 @@ // used for extra validation can optionally be provided. This should return: // - true if a < b // - false otherwise -// ALLOCATOR must check for oom and exit, as RBTree does not handle the allocation failing. // K needs to be of a type that is trivially destructible. // The tree will call a value's destructor when its node is removed. // Nodes are address stable and will not change during its lifetime. @@ -468,13 +467,17 @@ public: RBNode* allocate_node(const K& key) { void* node_place = _allocator.allocate(sizeof(RBNode)); - assert(node_place != nullptr, "rb-tree allocator must exit on failure"); + if (node_place == nullptr) { + return nullptr; + } return new (node_place) RBNode(key); } RBNode* allocate_node(const K& key, const V& val) { void* node_place = _allocator.allocate(sizeof(RBNode)); - assert(node_place != nullptr, "rb-tree allocator must exit on failure"); + if (node_place == nullptr) { + return nullptr; + } return new (node_place) RBNode(key, val); } @@ -485,16 +488,21 @@ public: // Inserts a node with the given key/value into the tree, // if the key already exist, the value is updated instead. - void upsert(const K& key, const V& val, const RBNode* hint_node = nullptr) { + // Returns false if and only if allocation of a new node failed. + bool upsert(const K& key, const V& val, const RBNode* hint_node = nullptr) { Cursor node_cursor = cursor(key, hint_node); RBNode* node = node_cursor.node(); if (node != nullptr) { node->set_val(val); - return; + return true; } node = allocate_node(key, val); + if (node == nullptr) { + return false; + } insert_at_cursor(node, node_cursor); + return true; } // Finds the value of the node associated with the given key. @@ -545,12 +553,12 @@ public: } }; -template +template class RBTreeCHeapAllocator { public: void* allocate(size_t sz) { void* allocation = os::malloc(sz, mem_tag); - if (allocation == nullptr) { + if (allocation == nullptr && strategy == AllocFailStrategy::EXIT_OOM) { vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, "red-black tree failed allocation"); } @@ -560,8 +568,8 @@ public: void free(void* ptr) { os::free(ptr); } }; -template -using RBTreeCHeap = RBTree>; +template +using RBTreeCHeap = RBTree>; template using IntrusiveRBTree = AbstractRBTree; diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index e1be83bfd58..d8394de017e 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -986,23 +986,23 @@ struct IntCmp { }; TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { - typedef RBTree > TreeType; - TreeType tree; - const int i1 = 82924; - const char* const s1 = "[82924] = 1"; - const int i2 = -13591; - const char* const s2 = "[-13591] = 2"; - const int i3 = 0; - const char* const s3 = "[0] = 3"; - tree.upsert(i1, 1U); - tree.upsert(i2, 2U); - tree.upsert(i3, 3U); - stringStream ss; - tree.print_on(&ss); - const char* const N = nullptr; - ASSERT_NE(strstr(ss.base(), s1), N); - ASSERT_NE(strstr(ss.base(), s2), N); - ASSERT_NE(strstr(ss.base(), s3), N); + using TreeType = RBTreeCHeap; + TreeType tree; + const int i1 = 82924; + const char* const s1 = "[82924] = 1"; + const int i2 = -13591; + const char* const s2 = "[-13591] = 2"; + const int i3 = 0; + const char* const s3 = "[0] = 3"; + tree.upsert(i1, 1U); + tree.upsert(i2, 2U); + tree.upsert(i3, 3U); + stringStream ss; + tree.print_on(&ss); + const char* const N = nullptr; + ASSERT_NE(strstr(ss.base(), s1), N); + ASSERT_NE(strstr(ss.base(), s2), N); + ASSERT_NE(strstr(ss.base(), s3), N); } TEST_VM_F(RBTreeTest, IntrusiveTest) { @@ -1079,3 +1079,15 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { } } +struct OomAllocator { + void* allocate(size_t sz) { + return nullptr; + } + void free(void* ptr) {} +}; +TEST_VM_F(RBTreeTest, AllocatorMayReturnNull) { + RBTree rbtree; + bool success = rbtree.upsert(5, 5); + EXPECT_EQ(false, success); + // The test didn't exit the VM, so it was succesful. +} From 5110d54d938b7afbdf9cfbc4501674ef7bc1d518 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 1 Sep 2025 13:08:53 +0000 Subject: [PATCH 077/295] 8365922: Parallel: Group uses of GCTimeRatio to a single location Reviewed-by: tschatzl, phh --- .../gc/parallel/parallelScavengeHeap.cpp | 3 +- .../gc/parallel/psAdaptiveSizePolicy.cpp | 28 +++++++++++++------ .../gc/parallel/psAdaptiveSizePolicy.hpp | 3 +- .../share/gc/shared/adaptiveSizePolicy.cpp | 11 +------- .../share/gc/shared/adaptiveSizePolicy.hpp | 7 +---- 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 07ae097c5b8..45c364ab35a 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -103,8 +103,7 @@ jint ParallelScavengeHeap::initialize() { double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; _size_policy = new PSAdaptiveSizePolicy(SpaceAlignment, - max_gc_pause_sec, - GCTimeRatio); + max_gc_pause_sec); assert((old_gen()->virtual_space()->high_boundary() == young_gen()->virtual_space()->low_boundary()), diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index 5d99095c1ed..1e4bd6c2868 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -36,10 +36,8 @@ #include PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t space_alignment, - double gc_pause_goal_sec, - uint gc_cost_ratio) : - AdaptiveSizePolicy(gc_pause_goal_sec, - gc_cost_ratio), + double gc_pause_goal_sec) : + AdaptiveSizePolicy(gc_pause_goal_sec), _avg_promoted(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, PromotedPadding)), _space_alignment(space_alignment), _young_gen_size_increment_supplement(YoungGenerationSizeSupplement) {} @@ -73,14 +71,28 @@ void PSAdaptiveSizePolicy::print_stats(bool is_survivor_overflowing) { is_survivor_overflowing ? "true" : "false"); } +// The throughput goal is implemented as +// _throughput_goal = 1 - (1 / (1 + gc_cost_ratio)) +// gc_cost_ratio is the ratio +// application cost / gc cost +// For example a gc_cost_ratio of 4 translates into a +// throughput goal of .80 +static double calculate_throughput_goal(double gc_cost_ratio) { + return 1.0 - (1.0 / (1.0 + gc_cost_ratio)); +} + size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflowing, size_t cur_eden) { // Guard against divide-by-zero; 0.001ms double gc_distance = MAX2(_gc_distance_seconds_seq.last(), 0.000001); double min_gc_distance = MinGCDistanceSecond; - if (mutator_time_percent() < _throughput_goal) { + // Get a local copy and use it inside gc-pause in case the global var gets updated externally. + const uint local_GCTimeRatio = Atomic::load(&GCTimeRatio); + const double throughput_goal = calculate_throughput_goal(local_GCTimeRatio); + + if (mutator_time_percent() < throughput_goal) { size_t new_eden; - const double expected_gc_distance = _trimmed_minor_gc_time_seconds.last() * GCTimeRatio; + const double expected_gc_distance = _trimmed_minor_gc_time_seconds.last() * local_GCTimeRatio; if (gc_distance >= expected_gc_distance) { // The lastest sample already satisfies throughput goal; keep the current size new_eden = cur_eden; @@ -90,7 +102,7 @@ size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflow (double)increase_eden(cur_eden)); } log_debug(gc, ergo)("Adaptive: throughput (actual vs goal): %.3f vs %.3f ; eden delta: + %zu K", - mutator_time_percent(), _throughput_goal, (new_eden - cur_eden)/K); + mutator_time_percent(), throughput_goal, (new_eden - cur_eden)/K); return new_eden; } @@ -118,7 +130,7 @@ size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflow // promoted_bytes_estimate() / (gc_distance + gc_time_lower_estimate) < 1M/s // ==> promoted_bytes_estimate() / M - gc_time_lower_estimate < gc_distance - const double gc_distance_target = MAX3(minor_gc_time_conservative_estimate() * GCTimeRatio, + const double gc_distance_target = MAX3(minor_gc_time_conservative_estimate() * local_GCTimeRatio, promoted_bytes_estimate() / M - gc_time_lower_estimate, min_gc_distance); double predicted_gc_distance = gc_distance * (1 - delta_factor) - _gc_distance_seconds_seq.dsd(); diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp index 68c736d0716..2b4bd2b6807 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp @@ -61,8 +61,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { // NEEDS_CLEANUP this is a singleton object PSAdaptiveSizePolicy(size_t space_alignment, - double gc_pause_goal_sec, - uint gc_time_ratio); + double gc_pause_goal_sec); // Methods indicating events of interest to the adaptive size policy, // called by GC algorithms. It is the responsibility of users of this diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp index 9a699921caa..b048c7dd79a 100644 --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp @@ -31,16 +31,7 @@ elapsedTimer AdaptiveSizePolicy::_minor_timer; elapsedTimer AdaptiveSizePolicy::_major_timer; -// The throughput goal is implemented as -// _throughput_goal = 1 - ( 1 / (1 + gc_cost_ratio)) -// gc_cost_ratio is the ratio -// application cost / gc cost -// For example a gc_cost_ratio of 4 translates into a -// throughput goal of .80 - -AdaptiveSizePolicy::AdaptiveSizePolicy(double gc_pause_goal_sec, - uint gc_cost_ratio) : - _throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))), +AdaptiveSizePolicy::AdaptiveSizePolicy(double gc_pause_goal_sec) : _gc_distance_timer(), _gc_distance_seconds_seq(seq_default_alpha_value), _trimmed_minor_gc_time_seconds(NumOfGCSample, seq_default_alpha_value), diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp index a3848079a76..89d419c28fa 100644 --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp @@ -47,10 +47,6 @@ class AdaptiveSizePolicy : public CHeapObj { static constexpr double MinGCDistanceSecond = 0.100; static_assert(MinGCDistanceSecond >= 0.001, "inv"); - // Goal for the fraction of the total time during which application - // threads run - const double _throughput_goal; - // pause and interval times for collections static elapsedTimer _minor_timer; @@ -170,8 +166,7 @@ class AdaptiveSizePolicy : public CHeapObj { size_t eden_increment(size_t cur_eden, uint percent_change); public: - AdaptiveSizePolicy(double gc_pause_goal_sec, - uint gc_cost_ratio); + AdaptiveSizePolicy(double gc_pause_goal_sec); void record_gc_pause_end_instant() { _gc_distance_timer.reset(); From 99223eea03e2ed714f7a5408c356fdf06efc9200 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Sep 2025 13:48:25 +0000 Subject: [PATCH 078/295] 8366427: C2 SuperWord: refactor VTransform scalar nodes Reviewed-by: mhaessig, chagedorn, kvn --- .../share/opto/superwordVTransformBuilder.cpp | 28 +++-- .../share/opto/superwordVTransformBuilder.hpp | 2 +- src/hotspot/share/opto/vtransform.cpp | 53 +++++++- src/hotspot/share/opto/vtransform.hpp | 117 +++++++++++++----- 4 files changed, 157 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index d178fd4394c..b31f2eda9c0 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -53,7 +53,19 @@ 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); + + VTransformNode* vtn = nullptr; + if (n->is_Load() || n->is_Store()) { + MemNode* mem = n->as_Mem(); + const VPointer& mem_p = _vloop_analyzer.vpointers().vpointer(mem); + vtn = new (_vtransform.arena()) VTransformMemopScalarNode(_vtransform, mem, mem_p); + } else if (n->is_Phi()) { + vtn = new (_vtransform.arena()) VTransformLoopPhiNode(_vtransform, n->as_Phi()); + } else if (n->is_CFG()) { + vtn = new (_vtransform.arena()) VTransformCFGNode(_vtransform, n); + } else { + vtn = new (_vtransform.arena()) VTransformDataScalarNode(_vtransform, n); + } map_node_to_vtnode(n, vtn); } } @@ -108,8 +120,8 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_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; } + VTransformNode* vtn = get_vtnode(n); + if (vtn->isa_Vector() != nullptr) { continue; } vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. if (n->is_Load()) { @@ -178,7 +190,7 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co } void SuperWordVTransformBuilder::init_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { - VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); + VTransformNode* req = get_vtnode_or_wrap_as_outer(n->in(index)); vtn->init_req(index, req); } @@ -210,7 +222,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i 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()); + VTransformNode* iv_vtn = get_vtnode_or_wrap_as_outer(_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 @@ -222,7 +234,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i } if (same_input != nullptr) { - VTransformNode* same_input_vtn = get_vtnode_or_wrap_as_input_scalar(same_input); + VTransformNode* same_input_vtn = get_vtnode_or_wrap_as_outer(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 @@ -264,12 +276,12 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i ShouldNotReachHere(); } -VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(Node* n) { +VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_outer(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); + vtn = new (_vtransform.arena()) VTransformOuterNode(_vtransform, n); map_node_to_vtnode(n, vtn); return vtn; } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index fd85b87f825..ea93bb60ffb 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -76,7 +76,7 @@ private: 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); + VTransformNode* get_vtnode_or_wrap_as_outer(Node* n); void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); void set_all_req_with_scalars(Node* n, VTransformNode* vtn); diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index f8efe333941..2882cc2c1a3 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -282,8 +282,8 @@ void VTransform::apply_speculative_aliasing_runtime_checks() { if (visited.test(use->_idx)) { // The use node was already visited, i.e. is higher up in the schedule. // The "out" edge thus points backward, i.e. it is violated. - const VPointer& vp1 = vtn->vpointer(_vloop_analyzer); - const VPointer& vp2 = use->vpointer(_vloop_analyzer); + const VPointer& vp1 = vtn->vpointer(); + const VPointer& vp2 = use->vpointer(); #ifdef ASSERT if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { tty->print_cr("\nViolated Weak Edge:"); @@ -630,7 +630,7 @@ bool VTransformGraph::has_store_to_load_forwarding_failure(const VLoopAnalyzer& for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); if (vtn->is_load_or_store_in_loop()) { - const VPointer& p = vtn->vpointer(vloop_analyzer); + const VPointer& p = vtn->vpointer(); if (p.is_valid()) { VTransformVectorNode* vector = vtn->isa_Vector(); bool is_load = vtn->is_load_in_loop(); @@ -708,7 +708,27 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { return n; } -VTransformApplyResult VTransformScalarNode::apply(VTransformApplyState& apply_state) const { +VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { // This was just wrapped. Now we simply unwap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } @@ -861,7 +881,7 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl // 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. - const VPointer& load_p = vpointer(apply_state.vloop_analyzer()); + const VPointer& load_p = vpointer(); while (mem->is_StoreVector()) { VPointer store_p(mem->as_Mem(), apply_state.vloop()); if (store_p.never_overlaps_with(load_p)) { @@ -983,7 +1003,24 @@ void VTransformNode::print_node_idx(const VTransformNode* vtn) { } } -void VTransformScalarNode::print_spec() const { +void VTransformMemopScalarNode::print_spec() const { + tty->print("node[%d %s] ", _node->_idx, _node->Name()); + _vpointer.print_on(tty, false); +} + +void VTransformDataScalarNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformLoopPhiNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformCFGNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformOuterNode::print_spec() const { tty->print("node[%d %s]", _node->_idx, _node->Name()); } @@ -1011,5 +1048,9 @@ void VTransformVectorNode::print_spec() const { tty->print("%d %s", n->_idx, n->Name()); } tty->print("]"); + if (is_load_or_store_in_loop()) { + tty->print(" "); + vpointer().print_on(tty, false); + } } #endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 74905bc6915..17dd81634ed 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -60,8 +60,11 @@ typedef int VTransformNodeIDX; class VTransformNode; -class VTransformScalarNode; -class VTransformInputScalarNode; +class VTransformMemopScalarNode; +class VTransformDataScalarNode; +class VTransformLoopPhiNode; +class VTransformCFGNode; +class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; class VTransformBoolVectorNode; @@ -422,8 +425,8 @@ public: return false; } - virtual VTransformScalarNode* isa_Scalar() { return nullptr; } - virtual VTransformInputScalarNode* isa_InputScalar() { return nullptr; } + virtual VTransformMemopScalarNode* isa_MemopScalar() { return nullptr; } + virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } @@ -434,7 +437,7 @@ public: virtual bool is_load_in_loop() const { return false; } virtual bool is_load_or_store_in_loop() const { return false; } - virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const { ShouldNotReachHere(); } + virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const = 0; @@ -448,34 +451,92 @@ public: NOT_PRODUCT(static void print_node_idx(const VTransformNode* vtn);) }; -// Identity transform for scalar nodes. -class VTransformScalarNode : public VTransformNode { +// Identity transform for scalar loads and stores. +class VTransformMemopScalarNode : public VTransformNode { +private: + MemNode* _node; + const VPointer _vpointer; +public: + VTransformMemopScalarNode(VTransform& vtransform, MemNode* n, const VPointer& vpointer) : + VTransformNode(vtransform, n->req()), _node(n), _vpointer(vpointer) + { + assert(node()->is_Load() || node()->is_Store(), "must be memop"); + } + + MemNode* node() const { return _node; } + virtual VTransformMemopScalarNode* isa_MemopScalar() override { return this; } + + virtual bool is_load_in_loop() const override { return _node->is_Load(); } + virtual bool is_load_or_store_in_loop() const override { return true; } + + virtual const VPointer& vpointer() const override { return _vpointer; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "MemopScalar"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Identity transform for scalar data nodes. +class VTransformDataScalarNode : 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 bool is_load_in_loop() const override { return _node->is_Load(); } - virtual bool is_load_or_store_in_loop() const override { return _node->is_Load() || _node->is_Store(); } - virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const override { return vloop_analyzer.vpointers().vpointer(node()->as_Mem()); } + VTransformDataScalarNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) + { + assert(!_node->is_Mem() && !_node->is_Phi() && !_node->is_CFG(), "must be data node: %s", _node->Name()); + } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; - NOT_PRODUCT(virtual const char* name() const override { return "Scalar"; };) + NOT_PRODUCT(virtual const char* name() const override { return "DataScalar"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Identity transform for loop head phi nodes. +class VTransformLoopPhiNode : public VTransformNode { +private: + PhiNode* _node; +public: + VTransformLoopPhiNode(VTransform& vtransform, PhiNode* n) : + VTransformNode(vtransform, n->req()), _node(n) + { + assert(_node->in(0)->is_Loop(), "phi ctrl must be Loop: %s", _node->in(0)->Name()); + } + + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "LoopPhi"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Identity transform for CFG nodes. +class VTransformCFGNode : public VTransformNode { +private: + Node* _node; +public: + VTransformCFGNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) + { + assert(_node->is_CFG(), "must be CFG node: %s", _node->Name()); + } + + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "CFG"; };) 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 { +class VTransformOuterNode : public VTransformNode { +private: + Node* _node; public: - VTransformInputScalarNode(VTransform& vtransform, Node* n) : - VTransformScalarNode(vtransform, n) {} - virtual VTransformInputScalarNode* isa_InputScalar() override { return this; } - virtual bool is_load_in_loop() const override { return false; } - virtual bool is_load_or_store_in_loop() const override { return false; } - NOT_PRODUCT(virtual const char* name() const override { return "InputScalar"; };) + VTransformOuterNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) {} + + virtual VTransformOuterNode* isa_Outer() override { return this; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "Outer"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; // Transform produces a ReplicateNode, replicating the input to all vector lanes. @@ -598,7 +659,7 @@ public: virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } - virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const override { return _vpointer; } + virtual const VPointer& vpointer() const override { return _vpointer; } }; class VTransformLoadVectorNode : public VTransformMemVectorNode { @@ -632,12 +693,12 @@ void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { 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; } + // We must ignore nodes outside the loop. + if (vtn->isa_Outer() != nullptr) { continue; } - VTransformScalarNode* scalar = vtn->isa_Scalar(); - if (scalar != nullptr && scalar->node()->is_Mem()) { - callback(scalar->node()->as_Mem()); + VTransformMemopScalarNode* scalar = vtn->isa_MemopScalar(); + if (scalar != nullptr) { + callback(scalar->node()); } VTransformVectorNode* vector = vtn->isa_Vector(); From b06459d3a83c13c0fbc7a0a7698435f17265982e Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Mon, 1 Sep 2025 14:21:33 +0000 Subject: [PATCH 079/295] 8364227: MBeanServer registerMBean throws NPE Reviewed-by: alanb --- .../DefaultMBeanServerInterceptor.java | 11 +- .../MBeanServer/ExceptionTestNulls.java | 196 ++++++++++++++++++ 2 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java diff --git a/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index 43606144cd0..161ac1b01fe 100644 --- a/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -291,8 +291,13 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - // ------------------------------ - // ------------------------------ + if (object == null) { + final RuntimeException wrapped = + new IllegalArgumentException("Object cannot be null"); + throw new RuntimeOperationsException(wrapped, + "Exception occurred trying to register the MBean"); + } + Class theClass = object.getClass(); Introspector.checkCompliance(theClass); diff --git a/test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java b/test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java new file mode 100644 index 00000000000..e8d534936a0 --- /dev/null +++ b/test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8364227 + * @summary Test various null parameters and verify Exceptions thrown + * @modules java.management.rmi + * @run main ExceptionTestNulls + */ + +import java.lang.management.ManagementFactory; +import javax.management.AttributeNotFoundException; +import javax.management.ObjectName; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MalformedObjectNameException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationListener; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; + +public class ExceptionTestNulls { + + public interface MyMBean { + } + + public class My implements MyMBean { + } + + private int count; + + public static void main(String args[]) throws Exception { + ExceptionTestNulls test = new ExceptionTestNulls(); + test.run(); + } + + public ExceptionTestNulls() { + count = 0; // Simple index for printing tests, for readability. + } + + public void run() { + + try { + ObjectName name = new ObjectName("a:b=c"); + ObjectName namePattern = new ObjectName("*:type=Foo"); + My myMy = new My(); + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + + try { + // createMBean with null className + mbs.createMBean((String) null, name, name, new Object[0], new String[0]); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // createMBean with ObjectName as a pattern + mbs.createMBean("myMy", namePattern, name, new Object[0], new String[0]); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // registerMBean with null Object + mbs.registerMBean(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // registerMBean with no name available + mbs.registerMBean(myMy, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // unregisterMBean with null ObjectName + mbs.unregisterMBean(null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.isRegistered(null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttribute(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttribute(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttributes(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttributes(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttribute(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttribute(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttributes(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttributes(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.addNotificationListener(null, (NotificationListener) null, null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.registerMBean(myMy, name); + mbs.addNotificationListener(null, name, null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + } catch (MBeanException | MalformedObjectNameException | InstanceAlreadyExistsException + | NotCompliantMBeanException | InstanceNotFoundException | ReflectionException + | AttributeNotFoundException | InvalidAttributeValueException e) { + // Should not reach here. Known Exceptions thrown by methods above. + // These would be a failure, as would other exceptions not caught (e.g. NullPointerException). + throw new RuntimeException(e); + } + } + + public void checkROEContainsIAE(RuntimeOperationsException e) { + System.out.println(++count); + System.out.println("Checking: " + e); + if (e.getCause() instanceof IllegalArgumentException) { + System.out.println("Got expected cause: " + e.getCause()); + System.out.println(); + } else { + throw new RuntimeException("Not the expected cause: " + e); + } + } +} From f58d612b6111658f01fa6b927bb2b2032c685620 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 2 Sep 2025 04:01:32 +0000 Subject: [PATCH 080/295] 8366483: ShowRegistersOnAssertTest uses wrong register pattern string for Windows on AArch64 Reviewed-by: dholmes, shade --- .../runtime/ErrorHandling/ShowRegistersOnAssertTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java index 3b038ebd8a0..b0138625450 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java @@ -76,7 +76,11 @@ public class ShowRegistersOnAssertTest { } else if (Platform.isX86()) { pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("EAX=.*")}; } else if (Platform.isAArch64()) { - pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("R0=.*")}; + if (Platform.isLinux()) { + pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("R0=.*")}; + } else if (Platform.isWindows()) { + pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("X0 =.*")}; + } } else if (Platform.isS390x()) { pattern = new Pattern[] { Pattern.compile("General Purpose Registers:"), Pattern.compile("^-{26}$"), From 8f11d83a0126f8179d72e714595588b631e6451d Mon Sep 17 00:00:00 2001 From: Philippe Marschall Date: Tue, 2 Sep 2025 05:49:06 +0000 Subject: [PATCH 081/295] 8362893: Improve performance for MemorySegment::getString Reviewed-by: pminborg, mcimadamore --- .../jdk/internal/foreign/StringSupport.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index 6dc104ff323..2f842810aa7 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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.internal.util.ArraysSupport; import jdk.internal.vm.annotation.ForceInline; import java.lang.foreign.MemorySegment; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import static java.lang.foreign.ValueLayout.*; @@ -71,7 +72,12 @@ public final class StringSupport { final int len = strlenByte(segment, offset, segment.byteSize()); final byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); - return new String(bytes, charset); + try { + return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + } catch (CharacterCodingException _) { + // use replacement characters for malformed input + return new String(bytes, charset); + } } @ForceInline @@ -85,7 +91,12 @@ public final class StringSupport { int len = strlenShort(segment, offset, segment.byteSize()); byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); - return new String(bytes, charset); + try { + return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + } catch (CharacterCodingException _) { + // use replacement characters for malformed input + return new String(bytes, charset); + } } @ForceInline @@ -99,7 +110,12 @@ public final class StringSupport { int len = strlenInt(segment, offset, segment.byteSize()); byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); - return new String(bytes, charset); + try { + return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + } catch (CharacterCodingException _) { + // use replacement characters for malformed input + return new String(bytes, charset); + } } @ForceInline From efb81dafaf6da334674e52dbb509208d7d872440 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 2 Sep 2025 06:50:15 +0000 Subject: [PATCH 082/295] 8366031: Mark com/sun/nio/sctp/SctpChannel/CloseDescriptors.java as intermittent Reviewed-by: jpai --- test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java index 0b3ce6ae039..c68abd7a36c 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java @@ -24,6 +24,7 @@ /* * @test * @bug 8238274 + * @key intermittent * @summary Potential leak file descriptor for SCTP * @requires (os.family == "linux") * @library /test/lib From 55e7af0560335ef69af072cee60956cf8e6d00a1 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 2 Sep 2025 07:27:12 +0000 Subject: [PATCH 083/295] 8260555: Change the default TIMEOUT_FACTOR from 4 to 1 Reviewed-by: alanb, sspitsyn, lmesnik, ihse --- doc/testing.html | 11 ++- doc/testing.md | 10 +-- make/RunTests.gmk | 3 +- .../arguments/TestCompileTaskTimeout.java | 2 +- .../arraycopy/stress/TestStressArrayCopy.java | 2 +- .../compiler/c1/TestConcurrentPatching.java | 4 +- .../compiler/c1/TestPinnedIntrinsics.java | 4 +- .../jtreg/compiler/c2/TestMergeStores.java | 6 +- .../c2/TestScalarReplacementMaxLiveNodes.java | 6 +- .../compiler/c2/TestStressRecompilation.java | 4 +- .../TestOverloadCompileQueues.java | 6 +- .../TestAntiDependenciesHighMemUsage2.java | 2 +- .../aes/TestCipherBlockChainingEncrypt.java | 4 +- .../TestLoadBypassesClassCast.java | 2 +- .../floatingpoint/TestFloatSyncJNIArgs.java | 2 +- .../intrinsics/TestLongUnsignedDivMod.java | 4 +- .../ContinuousCallSiteTargetChange.java | 4 +- ...fineMethodUsedByMultipleMethodHandles.java | 2 +- .../vm/ci/runtime/test/RedefineClassTest.java | 4 +- .../runtime/test/TestResolvedJavaMethod.java | 4 +- .../loopopts/TestMaxLoopOptsCountReached.java | 4 +- ...rtialPeelAtUnsignedTestsNegativeLimit.java | 10 +-- .../loopopts/superword/ProdRed_Double.java | 4 +- .../loopopts/superword/ProdRed_Float.java | 4 +- .../loopopts/superword/ProdRed_Int.java | 2 +- .../superword/SumRedAbsNeg_Double.java | 4 +- .../superword/SumRedAbsNeg_Float.java | 2 +- .../loopopts/superword/SumRedSqrt_Double.java | 2 +- .../loopopts/superword/SumRed_Double.java | 2 +- .../loopopts/superword/SumRed_Float.java | 2 +- .../loopopts/superword/SumRed_Int.java | 2 +- .../superword/TestDependencyOffsets.java | 68 +++++++++---------- .../superword/TestEquivalentInvariants.java | 2 +- .../superword/TestMovingLoadBeforeStore.java | 13 ++-- .../loopstripmining/CheckLoopStripMining.java | 2 +- .../profiling/TestProfileCounterOverflow.java | 4 +- .../spectrapredefineclass/Launcher.java | 10 +-- .../Launcher.java | 10 +-- .../tiered/Level2RecompilationTest.java | 5 +- .../compiler/uncommontrap/TestDeoptOOM.java | 6 +- .../vectorapi/TestRawOopAtSafepoint.java | 5 +- .../TestFloat16VectorOperations.java | 2 +- .../vectorization/TestVectorZeroCount.java | 2 +- .../g1/TestGreyReclaimedHumongousObjects.java | 4 +- .../TestHumongousClassLoader.java | 10 +-- .../TestHumongousNonArrayAllocation.java | 12 ++-- .../jtreg/gc/g1/ihop/TestIHOPErgo.java | 4 +- .../gc/stress/TestMultiThreadStressRSet.java | 4 +- .../stress/TestReclaimStringsLeaksMemory.java | 10 +-- .../gc/stress/TestStressG1Humongous.java | 10 +-- .../gc/stress/TestStressRSetCoarsening.java | 14 ++-- .../stress/systemgc/TestSystemGCWithG1.java | 4 +- .../systemgc/TestSystemGCWithParallel.java | 4 +- .../systemgc/TestSystemGCWithSerial.java | 4 +- .../systemgc/TestSystemGCWithShenandoah.java | 8 +-- test/hotspot/jtreg/gc/z/TestUncommit.java | 2 +- test/hotspot/jtreg/gtest/GTestWrapper.java | 2 +- .../jtreg/runtime/8176717/TestInheritFD.java | 9 +-- .../CreateMirror/ArraysNewInstanceBug.java | 4 +- .../ErrorHandling/CreateCoredumpOnCrash.java | 4 +- .../InvocationTests/invocationC1Tests.java | 6 +- .../InvocationTests/invokeinterfaceTests.java | 6 +- .../jtreg/runtime/LoadClass/TestResize.java | 4 +- .../runtime/NMT/VirtualAllocCommitMerge.java | 4 +- .../InvokeInterfaceICCE.java | 2 +- .../InvokeInterfaceSuccessTest.java | 2 +- .../InvokeVirtualICCE.java | 2 +- .../InvokeVirtualSuccessTest.java | 2 +- .../TestThreadDumpMonitorContention.java | 4 +- .../jtreg/runtime/cds/DeterministicDump.java | 2 +- .../cds/appcds/LotsOfSyntheticClasses.java | 2 +- .../jtreg/runtime/cds/appcds/TestCommon.java | 32 ++++----- .../aotCode/AOTCodeCompressedOopsTest.java | 4 +- .../appcds/aotProfile/AOTProfileFlags.java | 2 +- .../sharedStrings/SharedStringsStress.java | 2 +- .../ArrayIndexOutOfBoundsExceptionTest.java | 6 +- .../runtime/logging/RedefineClasses.java | 4 +- .../reflect/ReflectOutOfMemoryError.java | 4 +- .../UnmountedVThreadNativeMethodAtTop.java | 2 +- .../MyPackage/HeapMonitorThreadTest.java | 4 +- .../jvmti/SetTag/TagMapTest.java | 8 +-- .../SuspendResume2/SuspendResume2.java | 6 +- .../serviceability/sa/ClhsdbDumpheap.java | 4 +- .../jtreg/serviceability/sa/ClhsdbFindPC.java | 10 +-- .../sa/ClhsdbJstackXcompStress.java | 4 +- .../sa/ClhsdbThreadContext.java | 4 +- .../sa/TestJhsdbJstackLineNumbers.java | 4 +- .../sa/TestObjectAlignment.java | 4 +- .../sa/sadebugd/SADebugDTest.java | 6 +- .../ir_framework/tests/TestNotCompilable.java | 2 +- .../TestDescription.java | 4 +- .../TestDescription.java | 4 +- .../LargeObjects/large001/large001.java | 4 +- .../large002/TestDescription.java | 4 +- .../large003/TestDescription.java | 4 +- .../large004/TestDescription.java | 4 +- .../large005/TestDescription.java | 4 +- .../SoftReference/soft004/soft004.java | 4 +- .../WeakReference/weak004/weak004.java | 4 +- .../CircularListLow/TestDescription.java | 4 +- .../AdaptiveBlocking001.java | 4 +- .../TestDescription.java | 5 +- .../ShrinkGrowMultiJVM.java | 4 +- .../stressHierarchy001/TestDescription.java | 4 +- .../stressHierarchy002/TestDescription.java | 4 +- .../stressHierarchy003/TestDescription.java | 4 +- .../stressHierarchy004/TestDescription.java | 4 +- .../stressHierarchy005/TestDescription.java | 4 +- .../stressHierarchy006/TestDescription.java | 4 +- .../stressHierarchy007/TestDescription.java | 4 +- .../stressHierarchy008/TestDescription.java | 4 +- .../stressHierarchy009/TestDescription.java | 4 +- .../stressHierarchy010/TestDescription.java | 4 +- .../stressHierarchy011/TestDescription.java | 4 +- .../stressHierarchy012/TestDescription.java | 4 +- .../stressHierarchy013/TestDescription.java | 4 +- .../stressHierarchy014/TestDescription.java | 4 +- .../stressHierarchy015/TestDescription.java | 4 +- .../referringObjects001.java | 4 +- .../_itself_/stepEvent004/stepEvent004.java | 2 +- .../thread/thread001/TestDescription.java | 5 +- .../serial/mixed002/TestDescription.java | 5 +- .../holdevents002/TestDescription.java | 5 +- .../rawmnwait001/TestDescription.java | 5 +- .../SP03/sp03t001/TestDescription.java | 5 +- .../SP03/sp03t002/TestDescription.java | 5 +- .../SP04/sp04t001/TestDescription.java | 5 +- .../SP04/sp04t002/TestDescription.java | 5 +- .../SP07/sp07t001/TestDescription.java | 5 +- .../isSuspended/issuspended002.java | 4 +- .../thread/strace001/TestDescription.java | 5 +- .../thread/strace002/TestDescription.java | 5 +- .../thread/strace003/TestDescription.java | 5 +- .../nsk/stress/strace/strace006.java | 4 +- .../nsk/stress/thread/thread001.java | 4 +- .../nsk/stress/thread/thread002.java | 4 +- .../nsk/stress/thread/thread005.java | 4 +- .../nsk/stress/thread/thread006.java | 4 +- .../nsk/stress/thread/thread007.java | 4 +- .../nsk/stress/thread/thread008.java | 4 +- .../vm/stress/btree/btree001/btree001.java | 9 ++- .../vm/stress/btree/btree002/btree002.java | 9 ++- .../vm/stress/btree/btree003/btree003.java | 9 ++- .../vm/stress/btree/btree004/btree004.java | 9 ++- .../vm/stress/btree/btree005/btree005.java | 9 ++- .../vm/stress/btree/btree006/btree006.java | 9 ++- .../vm/stress/btree/btree007/btree007.java | 9 ++- .../vm/stress/btree/btree008/btree008.java | 9 ++- .../vm/stress/btree/btree009/btree009.java | 9 ++- .../vm/stress/btree/btree010/btree010.java | 9 ++- .../vm/stress/btree/btree011/btree011.java | 9 ++- .../vm/stress/btree/btree012/btree012.java | 9 ++- .../TestDescription.java | 3 +- .../meth/stress/compiler/i2c_c2i/Test.java | 2 +- .../meth/stress/compiler/sequences/Test.java | 4 +- .../provider/KeyFactory/TestProviderLeak.java | 8 +-- test/jdk/com/sun/jdi/InterruptHangTest.java | 7 +- .../com/sun/jdi/MethodEntryExitEvents.java | 8 +-- .../jdk/com/sun/jdi/ThreadMemoryLeakTest.java | 4 +- .../sun/jndi/ldap/LdapPoolTimeoutTest.java | 3 +- .../com/sun/nio/sctp/SctpChannel/Connect.java | 3 +- .../SctpServerChannel/NonBlockingAccept.java | 3 +- .../java/awt/font/NumericShaper/MTTest.java | 4 +- .../XMLDecoder/8028054/TestMethodFinder.java | 4 +- test/jdk/java/foreign/StdLibTest.java | 4 +- test/jdk/java/foreign/TestAccessModes.java | 10 +-- .../java/foreign/TestBufferStackStress2.java | 2 +- .../jdk/java/foreign/TestConcurrentClose.java | 4 +- test/jdk/java/foreign/TestDeadlock.java | 2 +- test/jdk/java/foreign/TestMismatch.java | 4 +- .../java/foreign/TestStringEncodingJumbo.java | 4 +- .../java/foreign/TestStubAllocFailure.java | 4 +- test/jdk/java/foreign/TestUpcallStack.java | 2 +- .../loaderLookup/TestLoaderLookup.java | 2 +- .../UnreferencedFISClosesFd.java | 4 +- .../UnreferencedFOSClosesFd.java | 4 +- .../UnreferencedRAFClosesFd.java | 4 +- .../FieldSetAccessibleTest.java | 4 +- test/jdk/java/lang/Math/IntegralPowTest.java | 2 +- .../ProcessBuilder/FDLeakTest/FDLeakTest.java | 6 +- .../lang/ProcessBuilder/UnblockSignals.java | 10 +-- .../lang/StackWalker/LocalsAndOperands.java | 8 +-- .../CompactString/MaxSizeUTF16String.java | 8 +-- .../StringBuilder/CompactStringBuilder.java | 6 +- .../virtual/CancelTimerWithContention.java | 4 +- .../lang/Thread/virtual/MiscMonitorTests.java | 12 ++-- .../lang/Thread/virtual/MonitorEnterExit.java | 10 +-- .../Thread/virtual/MonitorWaitNotify.java | 10 +-- .../jdk/java/lang/Thread/virtual/Parking.java | 8 +-- .../virtual/RetryMonitorEnterWhenPinned.java | 2 +- .../java/lang/Thread/virtual/Starvation.java | 2 +- .../Thread/virtual/SynchronizedNative.java | 8 +-- .../Thread/virtual/ThreadPollOnYield.java | 4 +- .../stress/GetStackTraceALotWhenBlocking.java | 6 +- .../GetStackTraceALotWithTimedWait.java | 7 +- .../lang/Thread/virtual/stress/ParkALot.java | 6 +- .../lang/Thread/virtual/stress/PinALot.java | 4 +- .../lang/Thread/virtual/stress/Skynet.java | 4 +- .../stress/Skynet100kWithMonitors.java | 4 +- .../lang/Thread/virtual/stress/SleepALot.java | 6 +- .../java/lang/annotation/LoaderLeakTest.java | 4 +- .../invoke/TestLambdaFormCustomization.java | 6 +- .../lang/reflect/IllegalArgumentsTest.java | 4 +- .../math/BigInteger/LargeValueExceptions.java | 4 +- .../UnreferencedDatagramSockets.java | 6 +- .../MulticastSocket/SetLoopbackModeIPv4.java | 4 +- .../UnreferencedMulticastSockets.java | 6 +- .../net/ServerSocket/UnreferencedSockets.java | 6 +- test/jdk/java/net/Socket/CloseAvailable.java | 6 +- .../net/httpclient/AsFileDownloadTest.java | 4 +- .../httpclient/BufferingSubscriberTest.java | 4 +- .../net/httpclient/CancelledResponse.java | 6 +- .../net/httpclient/HttpSlowServerTest.java | 4 +- .../jdk/java/net/httpclient/ManyRequests.java | 8 +-- .../httpclient/ResponseBodyBeforeError.java | 4 +- .../net/httpclient/ResponsePublisher.java | 4 +- .../net/httpclient/SpecialHeadersTest.java | 6 +- .../java/net/httpclient/SplitResponse.java | 4 +- .../net/httpclient/SplitResponseAsync.java | 4 +- .../httpclient/SplitResponseKeepAlive.java | 4 +- .../SplitResponseKeepAliveAsync.java | 4 +- .../java/net/httpclient/SplitResponseSSL.java | 4 +- .../net/httpclient/SplitResponseSSLAsync.java | 4 +- .../httpclient/SplitResponseSSLKeepAlive.java | 4 +- .../SplitResponseSSLKeepAliveAsync.java | 4 +- .../httpclient/whitebox/FlowTestDriver.java | 4 +- .../StressLoopback.java | 4 +- .../nio/channels/Channels/TransferTo.java | 4 +- .../Channels/TransferTo_2GB_transferFrom.java | 4 +- .../Channels/TransferTo_2GB_transferTo.java | 4 +- .../nio/channels/FileChannel/CleanerTest.java | 4 +- .../SocketChannel/CloseDuringConnect.java | 4 +- .../nio/channels/SocketChannel/OpenLeak.java | 4 +- .../nio/channels/unixdomain/IOExchanges.java | 4 +- .../channels/vthread/BlockingChannelOps.java | 8 +-- .../transport/dgcDeadLock/DGCDeadLock.java | 7 +- .../jdk/java/security/SignedObject/Chain.java | 4 +- .../Format/DateFormat/DateFormatTest.java | 2 +- .../java/util/HashMap/WhiteBoxResizeTest.java | 4 +- .../CurrencyNameProviderTest.java | 4 +- .../LocaleNameProviderTest.java | 2 +- .../BasicCancelTest.java | 4 +- .../java/util/logging/FileHandlerPath.java | 4 +- .../HandlersOnComplexResetUpdate.java | 11 ++- .../HandlersOnComplexUpdate.java | 11 ++- .../java/util/stream/TEST.properties | 1 + .../tests/java/util/stream/TEST.properties | 1 + test/jdk/java/util/zip/DeInflate.java | 5 +- .../zip/ZipFile/TestZipFileEncodings.java | 4 +- .../ssl/ciphersuites/DisabledAlgorithms.java | 6 +- .../JFileChooser/6868611/bug6868611.java | 4 +- .../ConcurrentModification.java | 4 +- .../parser/Parser/8078268/bug8078268.java | 6 +- .../xml/crypto/dsig/GenerationTests.java | 2 +- test/jdk/jdk/incubator/vector/AddTest.java | 3 +- .../TestDockerMemoryMetricsSubgroup.java | 2 +- .../docker/TestGetFreeSwapSpaceSize.java | 4 +- .../platform/docker/TestLimitsUpdating.java | 4 +- .../platform/docker/TestPidsLimit.java | 4 +- .../internal/vm/Continuation/BasicExt.java | 6 +- .../jdk/internal/vm/Continuation/Fuzz.java | 13 ++-- .../consumer/recordingstream/TestClose.java | 2 +- .../metadata/annotations/TestStackFilter.java | 4 +- .../oldobject/TestEmergencyDumpAtOOM.java | 2 +- .../oldobject/TestObjectDescription.java | 2 +- .../TestCPUTimeSampleMultipleRecordings.java | 2 +- test/jdk/jdk/jfr/jvm/TestModularImage.java | 2 +- .../MonitoredVm/MonitorVmStartTerminate.java | 1 + .../sun/nio/ch/TestMaxCachedBufferSize.java | 12 ++-- .../sun/nio/cs/TestEncoderReplaceUTF16.java | 4 +- test/jdk/sun/security/ec/ed/EdDSATest.java | 4 +- .../security/krb5/config/IncludeRandom.java | 2 +- .../sun/security/krb5/name/Constructors.java | 4 +- .../jdk/sun/security/pkcs11/KDF/TestHKDF.java | 2 +- .../KeyPairGenerator/TestDefaultSize.java | 4 +- .../pkcs11/KeyStore/ImportKeyToP12.java | 2 +- .../pkcs11/Mac/TestLargeSecretKeys.java | 2 +- .../pkcs12/KeytoolOpensslInteropTest.java | 4 +- .../sun/security/provider/acvp/Launcher.java | 4 +- .../ssl/SSLSocketImpl/SSLSocketCloseHang.java | 7 +- .../ssl/X509KeyManager/CertChecking.java | 8 +-- .../tools/jarsigner/ConciseJarsigner.java | 2 +- .../InsufficientSectionDelimiter.java | 4 +- .../tools/jarsigner/RestrictedAlgo.java | 6 +- .../SectionNameContinuedVsLineBreak.java | 4 +- .../tools/jarsigner/TimestampCheck.java | 2 +- .../security/tools/keytool/GenerateAll.java | 4 +- .../sun/security/tools/keytool/ReadJar.java | 4 +- .../keytool/fakecacerts/TrustedCert.java | 4 +- test/jdk/sun/tools/jcmd/TestJcmdSanity.java | 4 +- .../util/resources/TimeZone/Bug8139107.java | 5 +- test/jdk/tools/jlink/JLink100Modules.java | 4 +- test/jdk/tools/jlink/JLink20000Packages.java | 4 +- test/jdk/tools/jlink/JLinkTest.java | 4 +- .../plugins/IncludeLocalesPluginTest.java | 2 +- .../runtimeImage/JavaSEReproducibleTest.java | 2 +- .../tools/jpackage/macosx/DmgContentTest.java | 2 +- .../macosx/MacFileAssociationsTest.java | 2 +- .../tools/jpackage/share/AddLauncherTest.java | 4 +- .../jpackage/share/AppLauncherSubstTest.java | 2 +- .../tools/jpackage/share/AppVersionTest.java | 2 +- test/jdk/tools/jpackage/share/BasicTest.java | 2 +- test/jdk/tools/jpackage/share/IconTest.java | 2 +- .../tools/jpackage/share/InOutPathTest.java | 2 +- .../tools/jpackage/share/InstallDirTest.java | 4 +- .../tools/jpackage/share/JavaOptionsTest.java | 2 +- .../tools/jpackage/share/MainClassTest.java | 2 +- .../jpackage/share/MultiNameTwoPhaseTest.java | 2 +- .../jpackage/share/PostImageScriptTest.java | 2 +- .../jpackage/windows/WinNoRestartTest.java | 4 +- test/jdk/tools/launcher/InstanceMainTest.java | 4 +- .../testLinkOption/TestRedirectLinks.java | 2 +- test/langtools/jdk/jshell/ClassesTest.java | 4 +- .../jdk/jshell/CompletionSuggestionTest.java | 2 +- .../jdk/jshell/HangingRemoteAgent.java | 6 +- .../JdiHangingLaunchExecutionControlTest.java | 4 +- .../JdiHangingListenExecutionControlTest.java | 2 +- .../jdk/jshell/ToolLocalSimpleTest.java | 4 +- test/langtools/jdk/jshell/ToolSimpleTest.java | 4 +- test/langtools/jdk/jshell/UITesting.java | 13 +--- test/langtools/jdk/jshell/VariablesTest.java | 4 +- .../tools/javac/Paths/MineField.java | 4 +- .../tools/javac/Paths/WildcardMineField.java | 4 +- .../tools/javac/diags/CheckExamples.java | 4 +- .../tools/javac/diags/RunExamples.java | 4 +- .../javac/failover/CheckAttributedTree.java | 4 +- .../MultiReleaseJar/MultiReleaseJarTest.java | 4 +- .../GenericConstructorAndDiamondTest.java | 3 +- .../NegativeCyclicDependencyTest.java | 4 +- .../tools/javac/lambda/LambdaParserTest.java | 4 +- .../bridge/template_tests/TEST.properties | 2 + .../IntersectionTargetTypeTest.java | 3 +- .../CreateSymbolsReproducibleTest.java | 2 +- .../javac/tree/JavacTreeScannerTest.java | 4 +- .../javac/tree/SourceDocTreeScannerTest.java | 4 +- .../javac/tree/SourceTreeScannerTest.java | 4 +- .../tools/javac/types/TestComparisons.java | 3 +- .../tools/javac/util/IteratorsTest.java | 4 +- .../tools/javac/varargs/warning/Warn5.java | 4 +- test/langtools/tools/lib/toolbox/ToolBox.java | 12 +--- test/lib/jdk/test/lib/cds/CDSTestUtils.java | 5 +- test/lib/jdk/test/lib/util/ForceGC.java | 9 +-- 342 files changed, 810 insertions(+), 850 deletions(-) create mode 100644 test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties create mode 100644 test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties diff --git a/doc/testing.html b/doc/testing.html index fa774aa312f..89a9b1b23b7 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -398,7 +398,8 @@ TEST_OPTS keywords.

        JOBS

        Currently only applies to JTReg.

        TIMEOUT_FACTOR

        -

        Currently only applies to JTReg.

        +

        Currently only applies to JTReg +-timeoutFactor.

        JAVA_OPTIONS

        Applies to JTReg, GTest and Micro.

        VM_OPTIONS

        @@ -444,8 +445,12 @@ otherwise it defaults to JOBS, except for Hotspot, where the default is number of CPU cores/2, but never more than memory size in GB/2.

        TIMEOUT_FACTOR

        -

        The timeout factor (-timeoutFactor).

        -

        Defaults to 4.

        +

        The TIMEOUT_FACTOR is forwarded to JTReg framework +itself (-timeoutFactor). Also, some test cases that +programmatically wait a certain amount of time will apply this factor. +If we run in forced compilation mode (-Xcomp), the build +system will automatically adjust this factor to compensate for less +performance. Defaults to 1.

        FAILURE_HANDLER_TIMEOUT

        Sets the argument -timeoutHandlerTimeout for JTReg. The default value is 0. This is only valid if the failure handler is diff --git a/doc/testing.md b/doc/testing.md index 4cfc36c85f9..324f9645c27 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -324,7 +324,7 @@ Currently only applies to JTReg. #### TIMEOUT_FACTOR -Currently only applies to JTReg. +Currently only applies to [JTReg -timeoutFactor](#timeout_factor-1). #### JAVA_OPTIONS @@ -383,9 +383,11 @@ never more than *memory size in GB/2*. #### TIMEOUT_FACTOR -The timeout factor (`-timeoutFactor`). - -Defaults to 4. +The `TIMEOUT_FACTOR` is forwarded to JTReg framework itself +(`-timeoutFactor`). Also, some test cases that programmatically wait a +certain amount of time will apply this factor. If we run in forced +compilation mode (`-Xcomp`), the build system will automatically +adjust this factor to compensate for less performance. Defaults to 1. #### FAILURE_HANDLER_TIMEOUT diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 46f9a2e4047..10f0a2f87ed 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -946,7 +946,8 @@ define SetupRunJtregTestBody JTREG_ALL_OPTIONS := $$(JTREG_JAVA_OPTIONS) $$(JTREG_VM_OPTIONS) JTREG_AUTO_PROBLEM_LISTS := - JTREG_AUTO_TIMEOUT_FACTOR := 4 + # Please reach consensus before changing this. It was not easy changing it to a `1`. + JTREG_AUTO_TIMEOUT_FACTOR := 1 ifneq ($$(findstring -Xcomp, $$(JTREG_ALL_OPTIONS)), ) JTREG_AUTO_PROBLEM_LISTS += ProblemList-Xcomp.txt diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java index 4204f7be92e..cb52e5a24a0 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -29,7 +29,7 @@ package compiler.arguments; * @requires vm.debug & vm.flagless & os.name == "Linux" * @summary Check functionality of CompileTaskTimeout * @library /test/lib - * @run driver compiler.arguments.TestCompileTaskTimeout + * @run driver/timeout=480 compiler.arguments.TestCompileTaskTimeout */ import jdk.test.lib.process.ProcessTools; diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java index 55dfb0460a2..8c410c77e5f 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java @@ -51,7 +51,7 @@ import jdk.test.whitebox.cpuinfo.CPUInfo; * jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=7200 + * @run main/othervm/timeout=28800 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * compiler.arraycopy.stress.TestStressArrayCopy */ diff --git a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java index 6a7179d0ce4..dfd719f3a3b 100644 --- a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java +++ b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 java.util.ArrayList; * @test * @bug 8340313 * @summary Test that concurrent patching of oop immediates is thread-safe in C1. - * @run main/othervm/timeout=480 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching + * @run main/othervm/timeout=1920 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching */ class MyClass { } diff --git a/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java b/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java index a1f42a43240..0c47f752eab 100644 --- a/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java +++ b/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8184271 * @summary Test correct scheduling of System.nanoTime C1 intrinsic. - * @run main/othervm -XX:TieredStopAtLevel=1 -Xbatch + * @run main/othervm/timeout=480 -XX:TieredStopAtLevel=1 -Xbatch * -XX:CompileCommand=dontinline,compiler.c1.TestPinnedIntrinsics::checkNanoTime * compiler.c1.TestPinnedIntrinsics */ diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index 22920eda828..84329c4a9c8 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -37,7 +37,7 @@ import java.util.Random; * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run main compiler.c2.TestMergeStores aligned + * @run main/timeout=480 compiler.c2.TestMergeStores aligned */ /* @@ -46,7 +46,7 @@ import java.util.Random; * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run main compiler.c2.TestMergeStores unaligned + * @run main/timeout=480 compiler.c2.TestMergeStores unaligned */ /* @@ -55,7 +55,7 @@ import java.util.Random; * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run main compiler.c2.TestMergeStores StressIGVN + * @run main/timeout=480 compiler.c2.TestMergeStores StressIGVN */ public class TestMergeStores { diff --git a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java index 60086dba327..f133e91a1ee 100644 --- a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java +++ b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib / * @requires vm.debug & vm.compiler2.enabled * @compile -XDstringConcat=inline TestScalarReplacementMaxLiveNodes.java - * @run main/othervm compiler.c2.TestScalarReplacementMaxLiveNodes - * @run main/othervm -Xbatch -XX:-OptimizeStringConcat -XX:-TieredCompilation + * @run main/othervm/timeout=480 compiler.c2.TestScalarReplacementMaxLiveNodes + * @run main/othervm/timeout=480 -Xbatch -XX:-OptimizeStringConcat -XX:-TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+ReduceAllocationMerges * -XX:CompileCommand=dontinline,compiler.c2.TestScalarReplacementMaxLiveNodes::test * -XX:CompileCommand=compileonly,*TestScalarReplacementMaxLiveNodes*::*test* diff --git a/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java b/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java index 923323beb75..3572b6137f0 100644 --- a/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java +++ b/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8245801 * @requires vm.debug * @summary Test running with StressRecompilation enabled. - * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressRecompilation + * @run main/othervm/timeout=480 -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressRecompilation * compiler.c2.TestStressRecompilation */ diff --git a/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java b/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java index 04906954090..db5f31d8c77 100644 --- a/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java +++ b/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +26,9 @@ * @bug 8163511 8230402 * @summary Test overloading the C1 and C2 compile queues with tasks. * @requires !vm.graal.enabled - * @run main/othervm/timeout=300 -XX:-TieredCompilation -XX:CompileThreshold=2 -XX:CICompilerCount=1 + * @run main/othervm/timeout=1200 -XX:-TieredCompilation -XX:CompileThreshold=2 -XX:CICompilerCount=1 * compiler.classUnloading.methodUnloading.TestOverloadCompileQueues - * @run main/othervm/timeout=300 -XX:TieredCompileTaskTimeout=1000 -XX:CompileThresholdScaling=0.001 -XX:CICompilerCount=2 + * @run main/othervm/timeout=1200 -XX:TieredCompileTaskTimeout=1000 -XX:CompileThresholdScaling=0.001 -XX:CICompilerCount=2 * compiler.classUnloading.methodUnloading.TestOverloadCompileQueues */ diff --git a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java index d5f220f4628..cfe884c269f 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java +++ b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java @@ -25,7 +25,7 @@ * @test * @bug 8333258 * @summary C2: high memory usage in PhaseCFG::raise_above_anti_dependences() - * @run main/othervm -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 -XX:-ClipInlining + * @run main/othervm/timeout=480 -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 -XX:-ClipInlining * -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement TestAntiDependenciesHighMemUsage2 */ diff --git a/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java b/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java index 46d09b42425..b80a4ecdf5c 100644 --- a/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java +++ b/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -Xbatch + * @run main/othervm/timeout=480 -Xbatch * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * compiler.codegen.aes.TestCipherBlockChainingEncrypt */ diff --git a/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java b/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java index f5608c3a51a..127206f9b0e 100644 --- a/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java +++ b/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java @@ -26,7 +26,7 @@ * @summary C2: Load can bypass subtype check that enforces it's from the right object type * @requires vm.gc.Parallel * @requires vm.compiler2.enabled - * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileOnly=TestLoadBypassesClassCast::test + * @run main/othervm/timeout=480 -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileOnly=TestLoadBypassesClassCast::test * -XX:CompileThreshold=20000 -XX:LoopMaxUnroll=1 -XX:-LoopUnswitching -XX:+UseParallelGC TestLoadBypassesClassCast * */ diff --git a/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java b/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java index d9699062952..cd596c337b7 100644 --- a/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java +++ b/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java @@ -27,7 +27,7 @@ * @summary Regression test for passing float args to a synchronized jni function. * * - * @run main/othervm/native compiler.floatingpoint.TestFloatSyncJNIArgs + * @run main/othervm/native/timeout=480 compiler.floatingpoint.TestFloatSyncJNIArgs */ package compiler.floatingpoint; diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java b/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java index 88fd46c4325..ce9444823da 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test intrinsic for divideUnsigned() and remainderUnsigned() methods for Long * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="riscv64" | os.arch=="aarch64" * @library /test/lib / -* @run driver compiler.intrinsics.TestLongUnsignedDivMod +* @run driver/timeout=480 compiler.intrinsics.TestLongUnsignedDivMod */ package compiler.intrinsics; diff --git a/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java b/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java index 2b501064b76..5964341e816 100644 --- a/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java +++ b/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver/timeout=180 compiler.jsr292.ContinuousCallSiteTargetChange + * @run driver/timeout=720 compiler.jsr292.ContinuousCallSiteTargetChange */ package compiler.jsr292; diff --git a/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java b/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java index 93f21164bf5..769863880f2 100644 --- a/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java +++ b/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java @@ -32,7 +32,7 @@ * jdk.attach * @requires vm.jvmti * - * @run main/othervm -Djdk.attach.allowAttachSelf compiler.jsr292.RedefineMethodUsedByMultipleMethodHandles + * @run main/othervm/timeout=480 -Djdk.attach.allowAttachSelf compiler.jsr292.RedefineMethodUsedByMultipleMethodHandles */ package compiler.jsr292; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java index 6aeaf4eec7e..a6f58fd1375 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.attach * java.base/jdk.internal.misc - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -Djdk.attach.allowAttachSelf jdk.vm.ci.runtime.test.RedefineClassTest + * @run junit/othervm/timeout=480 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -Djdk.attach.allowAttachSelf jdk.vm.ci.runtime.test.RedefineClassTest */ package jdk.vm.ci.runtime.test; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 6151ae68ce7..58612aa0da1 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.base/jdk.internal.misc * java.base/jdk.internal.vm * java.base/sun.reflect.annotation - * @run junit/othervm/timeout=240 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod + * @run junit/othervm/timeout=960 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod */ package jdk.vm.ci.runtime.test; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java index d8a56e1b51b..a529c69dae8 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8284944 * @requires vm.compiler2.enabled * @summary triggers the loop optimization phase `LoopOptsCount` many times - * @run main/othervm -Xcomp -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test TestMaxLoopOptsCountReached + * @run main/othervm/timeout=480 -Xcomp -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test TestMaxLoopOptsCountReached */ import java.lang.System.Logger.Level; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java index 7809f79ce9d..34f0411f4ed 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 id=Xbatch * @bug 8332920 * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". - * @run main/othervm -Xbatch -XX:-TieredCompilation + * @run main/othervm/timeout=480 -Xbatch -XX:-TieredCompilation * -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test* * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit */ @@ -34,7 +34,7 @@ * @test id=Xcomp-run-inline * @bug 8332920 * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". - * @run main/othervm -Xcomp -XX:-TieredCompilation + * @run main/othervm/timeout=480 -Xcomp -XX:-TieredCompilation * -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::run*,*TestPartialPeel*::test* * -XX:CompileCommand=inline,*TestPartialPeelAtUnsignedTestsNegativeLimit::test* * -XX:CompileCommand=dontinline,*TestPartialPeelAtUnsignedTestsNegativeLimit::check @@ -45,7 +45,7 @@ * @test id=Xcomp-compile-test * @bug 8332920 * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". - * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test* + * @run main/othervm/timeout=480 -Xcomp -XX:-TieredCompilation -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test* * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit */ @@ -55,7 +55,7 @@ * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". * Only run this test with C2 since it is time-consuming and only tests a C2 issue. - * @run main compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit + * @run main/timeout=480 compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit */ package compiler.loopopts; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java index 41284c0d61e..4eebe6a80fe 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test * @library /test/lib / - * @run driver compiler.loopopts.superword.ProdRed_Double + * @run driver/timeout=480 compiler.loopopts.superword.ProdRed_Double */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java index 603530f7fb2..116a69f6bbf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test * @library /test/lib / - * @run driver compiler.loopopts.superword.ProdRed_Float + * @run driver/timeout=480 compiler.loopopts.superword.ProdRed_Float */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java index 9ca670117cf..433a4b6f3a3 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test * @library /test/lib / - * @run driver compiler.loopopts.superword.ProdRed_Int + * @run driver/timeout=480 compiler.loopopts.superword.ProdRed_Int */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java index 0122f1c34cd..2dd720ad1f0 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8138583 * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : double abs & neg test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRedAbsNeg_Double + * @run driver/timeout=480 compiler.loopopts.superword.SumRedAbsNeg_Double */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java index 6e2d304c149..3ada72c402b 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java @@ -26,7 +26,7 @@ * @bug 8138583 * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : float abs & neg test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRedAbsNeg_Float + * @run driver/timeout=480 compiler.loopopts.superword.SumRedAbsNeg_Float */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java index 2965af2a63b..ab99fd4adef 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java @@ -26,7 +26,7 @@ * @bug 8135028 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double sqrt test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRedSqrt_Double + * @run driver/timeout=480 compiler.loopopts.superword.SumRedSqrt_Double */ diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java index 0b81ae59bf0..89a396f43af 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRed_Double + * @run driver/timeout=480 compiler.loopopts.superword.SumRed_Double */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java index f667f2d05c1..db3ccf1a0b2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : float test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRed_Float + * @run driver/timeout=480 compiler.loopopts.superword.SumRed_Float */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java index 098dc2a7d1e..8c7e69247c5 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : int test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRed_Int + * @run driver/timeout=480 compiler.loopopts.superword.SumRed_Int */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index d760c87ad19..e2aca036474 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -27,7 +27,7 @@ * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vanilla-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vanilla-A */ /* @@ -36,7 +36,7 @@ * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vanilla-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vanilla-U */ /* @@ -48,7 +48,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v016-A */ /* @@ -60,7 +60,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v016-U */ /* @@ -72,7 +72,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v008-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v008-A */ /* @@ -84,7 +84,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v008-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v008-U */ /* @@ -96,7 +96,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v004-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v004-A */ /* @@ -108,7 +108,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v004-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v004-U */ /* @@ -120,7 +120,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v032-A */ /* @@ -132,7 +132,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v032-U */ /* @@ -144,7 +144,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v016-A */ /* @@ -156,7 +156,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v016-U */ /* @@ -168,7 +168,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v032-A */ /* @@ -180,7 +180,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v032-U */ /* @@ -192,7 +192,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v016-A */ /* @@ -204,7 +204,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v016-U */ /* @@ -216,7 +216,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v064-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v064-A */ /* @@ -228,7 +228,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v064-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v064-U */ /* @@ -240,7 +240,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v032-A */ /* @@ -252,7 +252,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v032-U */ /* @@ -264,7 +264,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-A */ /* @@ -276,7 +276,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-U */ /* @@ -288,7 +288,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-A */ /* @@ -300,7 +300,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-U */ /* @@ -311,7 +311,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v064-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v064-A */ /* @@ -322,7 +322,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v064-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v064-U */ /* @@ -333,7 +333,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v032-A */ /* @@ -344,7 +344,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v032-U */ /* @@ -355,7 +355,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v016-A */ /* @@ -366,7 +366,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v016-U */ /* @@ -377,7 +377,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v008-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v008-A */ /* @@ -388,7 +388,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v008-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v008-U */ /* @@ -399,7 +399,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v004-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v004-A */ /* @@ -410,7 +410,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v004-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v004-U */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java index 7cec26d6532..91d1ee9666a 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java @@ -39,7 +39,7 @@ import java.lang.foreign.*; * i.e. where the invariants have the same summands, but in a different order. * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run driver/timeout=1200 compiler.loopopts.superword.TestEquivalentInvariants + * @run driver/timeout=4800 compiler.loopopts.superword.TestEquivalentInvariants */ public class TestEquivalentInvariants { diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java index 72ca2cee341..18fb0019fa5 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java @@ -29,12 +29,13 @@ * @key randomness * @modules java.base/jdk.internal.misc * @library /test/lib - * @run main/othervm -XX:CompileCommand=compileonly,compiler.loopopts.superword.TestMovingLoadBeforeStore::test* - * --add-modules java.base --add-exports java.base/jdk.internal.misc=ALL-UNNAMED - * -Xbatch - * -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM - * -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=100 - * compiler.loopopts.superword.TestMovingLoadBeforeStore + * @run main/othervm/timeout=480 + * -XX:CompileCommand=compileonly,compiler.loopopts.superword.TestMovingLoadBeforeStore::test* + * --add-modules java.base --add-exports java.base/jdk.internal.misc=ALL-UNNAMED + * -Xbatch + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM + * -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=100 + * compiler.loopopts.superword.TestMovingLoadBeforeStore */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java index 9e8ac6b013a..cdbf5affd01 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java @@ -28,7 +28,7 @@ * @requires vm.compiler2.enabled * * @library /test/lib - * @run driver compiler.loopstripmining.CheckLoopStripMining + * @run driver/timeout=480 compiler.loopstripmining.CheckLoopStripMining */ package compiler.loopstripmining; diff --git a/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java b/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java index b4c4d2d4a4a..bcd48698d13 100644 --- a/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java +++ b/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Loongson Technology Co. Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,7 +27,7 @@ * @bug 8224162 * @summary Profile counter for a call site may overflow. * @requires vm.compMode != "Xcomp" - * @run main/othervm -Xbatch -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:MaxTrivialSize=0 -XX:C1MaxTrivialSize=0 compiler.profiling.TestProfileCounterOverflow + * @run main/othervm/timeout=480 -Xbatch -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:MaxTrivialSize=0 -XX:C1MaxTrivialSize=0 compiler.profiling.TestProfileCounterOverflow */ package compiler.profiling; diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java index bdf4b3fb852..297c0312069 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 +32,10 @@ * @build compiler.profiling.spectrapredefineclass.Agent * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass.Agent * @run driver compiler.profiling.spectrapredefineclass.Launcher - * @run main/othervm -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 - * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 - * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf - * compiler.profiling.spectrapredefineclass.Agent + * @run main/othervm/timeout=480 -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 + * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 + * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf + * compiler.profiling.spectrapredefineclass.Agent */ package compiler.profiling.spectrapredefineclass; diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java index 6fdbca00523..e7f5736889c 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,10 @@ * compiler.profiling.spectrapredefineclass_classloaders.B * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass_classloaders.Agent * @run driver compiler.profiling.spectrapredefineclass_classloaders.Launcher - * @run main/othervm -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 - * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 - * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf - * compiler.profiling.spectrapredefineclass_classloaders.Agent + * @run main/othervm/timeout=480 -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 + * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 + * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf + * compiler.profiling.spectrapredefineclass_classloaders.Agent */ package compiler.profiling.spectrapredefineclass_classloaders; diff --git a/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java index 9cdba8c7bea..5bf031b7c4a 100644 --- a/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java +++ b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+TieredCompilation + * @run main/othervm/timeout=960 -Xbootclasspath/a:. -XX:+TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCaseHelper::* * -XX:CompileCommand=print,compiler.whitebox.SimpleTestCaseHelper::* @@ -101,4 +101,3 @@ public class Level2RecompilationTest extends CompLevelsTest { super.checkLevel(expected, actual); } } - diff --git a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java index 3dc9df2d73e..1f5fc3d36bd 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary failed reallocations of scalar replaced objects during deoptimization causes crash * * @requires !vm.graal.enabled - * @run main/othervm -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack + * @run main/othervm/timeout=480 -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::main * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::m9_1 * compiler.uncommontrap.TestDeoptOOM @@ -38,7 +38,7 @@ * @bug 8273456 * @summary Test that ttyLock is ranked above StackWatermark_lock * @requires !vm.graal.enabled & vm.gc.Z - * @run main/othervm -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack + * @run main/othervm/timeout=480 -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::main * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::m9_1 * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java b/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java index 7af6296d16b..c9c574771c5 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import jdk.test.lib.Asserts; * @summary Verify that CheckCastPPs with raw oop inputs are not floating below a safepoint. * @library /test/lib * @modules jdk.incubator.vector - * @run main/othervm -XX:-TieredCompilation -Xbatch + * @run main/othervm/timeout=480 + * -XX:-TieredCompilation -Xbatch * -XX:CompileCommand=compileonly,compiler.vectorapi.TestRawOopAtSafepoint::test* * -XX:CompileCommand=dontinline,compiler.vectorapi.TestRawOopAtSafepoint::safepoint * compiler.vectorapi.TestRawOopAtSafepoint diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java index 9c342574632..f3c27c4d278 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java @@ -29,7 +29,7 @@ * @modules jdk.incubator.vector * @library /test/lib / * @compile TestFloat16VectorOperations.java -* @run driver compiler.vectorization.TestFloat16VectorOperations +* @run driver/timeout=480 compiler.vectorization.TestFloat16VectorOperations */ package compiler.vectorization; diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java index f4c8845b857..c30a28c46f9 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java @@ -26,7 +26,7 @@ * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary Ensure that vectorization of numberOfLeadingZeros and numberOfTrailingZeros outputs correct values * @library /test/lib / - * @run main/othervm compiler.vectorization.TestVectorZeroCount + * @run main/othervm/timeout=480 compiler.vectorization.TestVectorZeroCount */ package compiler.vectorization; diff --git a/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java b/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java index 0ee8cfdbaa4..1dee119401b 100644 --- a/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java +++ b/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ package gc.g1; * @requires vm.gc.G1 * @summary Test handling of marked but unscanned reclaimed humongous objects. * @modules jdk.management - * @run main/othervm -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m + * @run main/othervm/timeout=480 -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m * gc.g1.TestGreyReclaimedHumongousObjects 1048576 90 */ diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java index 813b002a8ea..5ade1fbee93 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +48,20 @@ import java.nio.file.Paths; * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=240 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=960 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * gc.g1.humongousObjects.ClassLoaderGenerator 1 * - * @run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_Full_GC.log * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousClassLoader FULL_GC * - * @run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_Full_GC_Mem_Pressure.log * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousClassLoader FULL_GC_MEMORY_PRESSURE * - *@run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + *@run main/othervm/timeout=480 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_CMC.log * -XX:G1HeapRegionSize=1M -XX:MaxTenuringThreshold=1 * gc.g1.humongousObjects.TestHumongousClassLoader CMC diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java index c9bc1e0f14e..692e5017157 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,23 +44,23 @@ import java.nio.file.Paths; * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation LARGEST_NON_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation SMALLEST_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation ONE_REGION_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation TWO_REGION_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation MORE_THAN_TWO_REGION_HUMONGOUS * diff --git a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java index b0adb1d489f..83080175a15 100644 --- a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java +++ b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * @modules java.management - * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo + * @run driver/timeout=1920 gc.g1.ihop.TestIHOPErgo */ package gc.g1.ihop; diff --git a/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java b/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java index 0c742b7b4ef..a323ebd945a 100644 --- a/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java +++ b/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.Utils; * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc * -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 60 16 * - * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * @run main/othervm/timeout=1200 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 600 32 */ diff --git a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java index 645583ec450..80ab9e21667 100644 --- a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java +++ b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +31,10 @@ package gc.stress; * @requires !vm.debug * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver gc.stress.TestReclaimStringsLeaksMemory - * @run driver gc.stress.TestReclaimStringsLeaksMemory -XX:+UseSerialGC - * @run driver gc.stress.TestReclaimStringsLeaksMemory -XX:+UseParallelGC - * @run driver gc.stress.TestReclaimStringsLeaksMemory -XX:+UseG1GC + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseSerialGC + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseParallelGC + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseG1GC */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java index 9f3c4286c0f..f92a562aa31 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=180 gc.stress.TestStressG1Humongous 4 3 1.1 120 + * @run driver/timeout=240 gc.stress.TestStressG1Humongous 4 3 1.1 120 */ /* @@ -40,7 +40,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=180 gc.stress.TestStressG1Humongous 16 5 2.1 120 + * @run driver/timeout=240 gc.stress.TestStressG1Humongous 16 5 2.1 120 */ /* @@ -49,7 +49,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=180 gc.stress.TestStressG1Humongous 32 4 0.6 120 + * @run driver/timeout=240 gc.stress.TestStressG1Humongous 32 4 0.6 120 */ /* @@ -58,7 +58,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=900 gc.stress.TestStressG1Humongous 1 7 0.6 600 + * @run driver/timeout=1200 gc.stress.TestStressG1Humongous 1 7 0.6 600 */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java b/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java index f7b6c77fdf3..7f91714d709 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java +++ b/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 1 0 300 @@ -53,7 +53,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=8m gc.stress.TestStressRSetCoarsening 1 10 300 @@ -68,7 +68,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=32m gc.stress.TestStressRSetCoarsening 42 10 300 @@ -83,7 +83,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 2 0 300 @@ -98,7 +98,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=1800 + * @run main/othervm/timeout=7200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx1G -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 500 0 1800 @@ -113,7 +113,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=1800 + * @run main/othervm/timeout=7200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx1G -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 10 10 1800 diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java index 64a090025ac..a3bb0944dd5 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ package gc.stress.systemgc; * @library / * @requires vm.gc.G1 * @summary Stress the G1 GC full GC by allocating objects of different lifetimes concurrently with System.gc(). - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseG1GC gc.stress.systemgc.TestSystemGCWithG1 270 + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UseG1GC gc.stress.systemgc.TestSystemGCWithG1 270 */ public class TestSystemGCWithG1 { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java index 07a510c7a4e..2b4bca5cf4b 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ package gc.stress.systemgc; * @library / * @requires vm.gc.Parallel * @summary Stress the Parallel GC full GC by allocating objects of different lifetimes concurrently with System.gc(). - * @run main/othervm/timeout=300 -Xlog:gc=info -Xmx512m -XX:+UseParallelGC gc.stress.systemgc.TestSystemGCWithParallel 270 + * @run main/othervm/timeout=540 -Xlog:gc=info -Xmx512m -XX:+UseParallelGC gc.stress.systemgc.TestSystemGCWithParallel 270 */ public class TestSystemGCWithParallel { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java index 1db15b76e18..8571aee84c0 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ package gc.stress.systemgc; * @library / * @requires vm.gc.Serial * @summary Stress the Serial GC full GC by allocating objects of different lifetimes concurrently with System.gc(). - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseSerialGC gc.stress.systemgc.TestSystemGCWithSerial 270 + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UseSerialGC gc.stress.systemgc.TestSystemGCWithSerial 270 */ public class TestSystemGCWithSerial { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java index 13129552873..ea475d42e0c 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java @@ -32,12 +32,12 @@ package gc.stress.systemgc; * @requires vm.gc.Shenandoah * @summary Stress the Shenandoah GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC * -XX:+ShenandoahVerify * gc.stress.systemgc.TestSystemGCWithShenandoah 270 * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC * gc.stress.systemgc.TestSystemGCWithShenandoah 270 */ @@ -49,12 +49,12 @@ package gc.stress.systemgc; * @requires vm.gc.Shenandoah * @summary Stress the Shenandoah GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * gc.stress.systemgc.TestSystemGCWithShenandoah 270 * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * gc.stress.systemgc.TestSystemGCWithShenandoah 270 */ diff --git a/test/hotspot/jtreg/gc/z/TestUncommit.java b/test/hotspot/jtreg/gc/z/TestUncommit.java index afb736501dd..0e674358be5 100644 --- a/test/hotspot/jtreg/gc/z/TestUncommit.java +++ b/test/hotspot/jtreg/gc/z/TestUncommit.java @@ -27,7 +27,7 @@ package gc.z; * @test TestUncommit * @requires vm.gc.Z * @summary Test ZGC uncommit unused memory - * @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=5 gc.z.TestUncommit + * @run main/othervm/timeout=480 -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=5 gc.z.TestUncommit */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gtest/GTestWrapper.java b/test/hotspot/jtreg/gtest/GTestWrapper.java index 1bd9734e48c..2ee174b11be 100644 --- a/test/hotspot/jtreg/gtest/GTestWrapper.java +++ b/test/hotspot/jtreg/gtest/GTestWrapper.java @@ -27,7 +27,7 @@ * @modules java.base/jdk.internal.misc * java.xml * @requires vm.flagless - * @run main/native GTestWrapper + * @run main/native/timeout=480 GTestWrapper */ import jdk.test.lib.Platform; diff --git a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java index f2a17acdd64..8130ff65792 100644 --- a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java +++ b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +56,7 @@ import java.util.stream.Stream; * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run driver TestInheritFD + * @run driver/timeout=480 TestInheritFD */ /** @@ -78,6 +78,8 @@ import java.util.stream.Stream; * the third VM. */ +import jdk.test.lib.Utils; + public class TestInheritFD { public static final String LEAKS_FD = "VM RESULT => LEAKS FD"; @@ -90,8 +92,7 @@ public class TestInheritFD { public static final String THIRD_VM_PID_PREFIX = "Third VM pid="; public static final String THIRD_VM_WAITING_PREFIX = "Third VM waiting for second VM pid="; - public static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - public static long subProcessTimeout = (long)(15L * timeoutFactor); + public static long subProcessTimeout = (long)(15L * Utils.TIMEOUT_FACTOR); // Extract a pid from the specified String at the specified start offset. private static long extractPidFromStringOffset(String str, int start) { diff --git a/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java b/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java index cb45f00d666..743e0372ab1 100644 --- a/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java +++ b/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8182397 * @summary race in setting array_klass field for component mirror with mirror update for klass * @modules java.base/jdk.internal.misc - * @run main/othervm -Xcomp ArraysNewInstanceBug + * @run main/othervm/timeout=480 -Xcomp ArraysNewInstanceBug */ // This test crashes in compiled code with race, because the compiler generates code that assumes this ordering. diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java index 2fb42e230a5..12755cba243 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run driver CreateCoredumpOnCrash + * @run driver/timeout=480 CreateCoredumpOnCrash * @requires vm.flagless * @requires !vm.asan */ diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java b/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java index 0e4f01bb55f..a21c6b2b233 100644 --- a/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java +++ b/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java @@ -32,7 +32,7 @@ * @modules java.base/jdk.internal.misc * @compile invokespecial/Checker.java invokespecial/ClassGenerator.java invokespecial/Generator.java * - * @run driver/timeout=1800 invocationC1Tests special + * @run driver/timeout=7200 invocationC1Tests special */ /* @@ -45,7 +45,7 @@ * @modules java.base/jdk.internal.misc * @compile invokevirtual/Checker.java invokevirtual/ClassGenerator.java invokevirtual/Generator.java * - * @run driver/timeout=1800 invocationC1Tests virtual + * @run driver/timeout=7200 invocationC1Tests virtual */ /* @@ -58,7 +58,7 @@ * @modules java.base/jdk.internal.misc * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java invokeinterface/Generator.java * - * @run driver/timeout=1800 invocationC1Tests interface + * @run driver/timeout=7200 invocationC1Tests interface */ import jdk.test.lib.process.ProcessTools; diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java index 1cf175030be..fdbffb3afcf 100644 --- a/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java +++ b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java @@ -33,7 +33,7 @@ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java * invokeinterface/Generator.java * - * @run driver/timeout=1800 invokeinterfaceTests current-int + * @run driver/timeout=5400 invokeinterfaceTests current-int */ /* @@ -47,7 +47,7 @@ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java * invokeinterface/Generator.java * - * @run driver/timeout=1800 invokeinterfaceTests current-comp + * @run driver/timeout=5400 invokeinterfaceTests current-comp */ /* @@ -61,7 +61,7 @@ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java * invokeinterface/Generator.java * - * @run driver/timeout=1800 invokeinterfaceTests old-int + * @run driver/timeout=5400 invokeinterfaceTests old-int */ import jdk.test.lib.process.ProcessTools; diff --git a/test/hotspot/jtreg/runtime/LoadClass/TestResize.java b/test/hotspot/jtreg/runtime/LoadClass/TestResize.java index 9177ede52da..bb4ebe358e4 100644 --- a/test/hotspot/jtreg/runtime/LoadClass/TestResize.java +++ b/test/hotspot/jtreg/runtime/LoadClass/TestResize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules java.base/jdk.internal.misc * java.management * @compile TriggerResize.java - * @run driver TestResize + * @run driver/timeout=480 TestResize */ import jdk.test.lib.Platform; diff --git a/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java b/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java index 4d691eb920a..fd4444ccd88 100644 --- a/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java +++ b/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.management * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -Xint -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitMerge + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -Xint -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitMerge * */ diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java index 9212b2d0032..f00ed1636e2 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceICCE + * @run main/othervm/timeout=2000 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceICCE */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java index 4eb3c06e637..f27c03308e9 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=300 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceSuccessTest + * @run main/othervm/timeout=1200 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceSuccessTest */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java index c041bca153d..1a0e67aeeab 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=1200 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualICCE + * @run main/othervm/timeout=4800 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualICCE */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java index a20e934d651..821b11169ab 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=400 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualSuccessTest + * @run main/othervm/timeout=1600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualSuccessTest */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java index a8f8660272d..6dc6d04a737 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java +++ b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * * @library /test/lib * @modules java.base/jdk.internal.misc - * @run main/othervm TestThreadDumpMonitorContention + * @run main/othervm/timeout=480 TestThreadDumpMonitorContention */ import java.io.BufferedReader; diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 202262a8117..d26ca8cc7cf 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -29,7 +29,7 @@ * @library /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 + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI DeterministicDump */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java index 3c3db7d0397..bb3d33218a2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java @@ -37,7 +37,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @summary Try to archive lots and lots of classes. * @requires vm.cds * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @run driver/timeout=500 LotsOfSyntheticClasses + * @run driver/timeout=8000 LotsOfSyntheticClasses */ public class LotsOfSyntheticClasses { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java index 5d1e3831d86..16e691c9a13 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java @@ -22,30 +22,22 @@ * */ -import jdk.test.lib.Utils; -import jdk.test.lib.BuildHelper; -import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.Platform; -import jdk.test.lib.cds.CDSOptions; -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.cds.CDSTestUtils.Result; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; +import cdsutils.DynamicDumpHelper; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.nio.file.DirectoryStream; -import java.nio.file.Files; import java.nio.file.FileSystem; import java.nio.file.FileSystems; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.Enumeration; import java.util.regex.Matcher; @@ -53,8 +45,17 @@ import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; +import jdk.test.lib.BuildHelper; +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.Utils; +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.cds.CDSTestUtils.Result; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; import jtreg.SkippedException; -import cdsutils.DynamicDumpHelper; /** @@ -76,9 +77,6 @@ public class TestCommon extends CDSTestUtils { private static final SimpleDateFormat timeStampFormat = new SimpleDateFormat("HH'h'mm'm'ss's'SSS"); - private static final String timeoutFactor = - System.getProperty("test.timeout.factor", "1.0"); - private static String currentArchiveName; // Call this method to start new archive with new unique name @@ -420,7 +418,7 @@ public class TestCommon extends CDSTestUtils { cmd.add("-Xshare:" + opts.xShareMode); cmd.add("-showversion"); cmd.add("-XX:SharedArchiveFile=" + getCurrentArchiveName()); - cmd.add("-Dtest.timeout.factor=" + timeoutFactor); + cmd.add("-Dtest.timeout.factor=" + Utils.TIMEOUT_FACTOR); if (opts.appJar != null) { cmd.add("-cp"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index 4587eeae5e5..e1d132dd984 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -32,12 +32,12 @@ * subtests with this flag. * @library /test/lib /test/setup_aot * @build AOTCodeCompressedOopsTest JavacBenchApp - * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * @run driver/timeout=480 jdk.test.lib.helpers.ClassFileInstaller -jar app.jar * JavacBenchApp * JavacBenchApp$ClassFile * JavacBenchApp$FileManager * JavacBenchApp$SourceFile - * @run driver AOTCodeCompressedOopsTest + * @run driver/timeout=480 AOTCodeCompressedOopsTest */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java index fe9c7e7bbb7..4dc4512e01c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java @@ -36,7 +36,7 @@ * JavacBenchApp$FileManager * JavacBenchApp$SourceFile * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello - * @run driver AOTProfileFlags + * @run driver/timeout=480 AOTProfileFlags */ import jdk.test.lib.cds.CDSTestUtils; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java index 5871305139e..1114870d1d3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java @@ -28,7 +28,7 @@ * @requires vm.cds.write.archived.java.heap * @library /test/hotspot/jtreg/runtime/cds/appcds /test/lib * @build HelloString - * @run driver/timeout=650 SharedStringsStress + * @run driver/timeout=2600 SharedStringsStress */ import java.io.File; import java.io.FileOutputStream; diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java index 434864ff3bf..cf316a8bfd6 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,8 +34,8 @@ * @test * @requires !vm.graal.enabled * @comment These test C1 and C2 so make no sense when Graal is enabled. - * @run testng/othervm -Xcomp -XX:-TieredCompilation ArrayIndexOutOfBoundsExceptionTest - * @run testng/othervm -Xcomp -XX:TieredStopAtLevel=1 ArrayIndexOutOfBoundsExceptionTest + * @run testng/othervm/timeout=480 -Xcomp -XX:-TieredCompilation ArrayIndexOutOfBoundsExceptionTest + * @run testng/othervm/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 ArrayIndexOutOfBoundsExceptionTest */ import java.io.ByteArrayInputStream; diff --git a/test/hotspot/jtreg/runtime/logging/RedefineClasses.java b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java index 8b75802cd3b..a013ebdea54 100644 --- a/test/hotspot/jtreg/runtime/logging/RedefineClasses.java +++ b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.instrument * @requires vm.jvmti * @run main RedefineClassHelper - * @run main/othervm -Xmx256m -XX:MaxMetaspaceSize=64m -javaagent:redefineagent.jar -Xlog:all=trace:file=all.log RedefineClasses + * @run main/othervm/timeout=480 -Xmx256m -XX:MaxMetaspaceSize=64m -javaagent:redefineagent.jar -Xlog:all=trace:file=all.log RedefineClasses */ // package access top-level class to avoid problem with RedefineClassHelper diff --git a/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java b/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java index 09646d07358..69cfade4521 100644 --- a/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8297977 * @summary Test that throwing OOM from reflected method gets InvocationTargetException - * @run main/othervm -Xmx128m ReflectOutOfMemoryError + * @run main/othervm/timeout=480 -Xmx128m ReflectOutOfMemoryError */ import java.lang.reflect.*; diff --git a/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java b/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java index 7980b5ae28d..04086c49a4d 100644 --- a/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java +++ b/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java @@ -29,7 +29,7 @@ * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run junit/othervm/native -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI --enable-native-access=ALL-UNNAMED UnmountedVThreadNativeMethodAtTop + * @run junit/othervm/native/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI --enable-native-access=ALL-UNNAMED UnmountedVThreadNativeMethodAtTop */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java index 38fd16808cd..17565899a64 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,7 +30,7 @@ package MyPackage; * @summary Verifies the JVMTI Heap Monitor Thread information sanity. * @requires vm.jvmti * @compile HeapMonitorThreadTest.java - * @run main/othervm/native -Xmx512m -agentlib:HeapMonitorTest MyPackage.HeapMonitorThreadTest + * @run main/othervm/native/timeout=480 -Xmx512m -agentlib:HeapMonitorTest MyPackage.HeapMonitorThreadTest */ import java.util.List; diff --git a/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java b/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java index d75f56714a4..136381e2111 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +26,9 @@ * @bug 8306843 * @summary Test that 10M tags doesn't time out. * @requires vm.jvmti - * @run main/othervm/native -agentlib:TagMapTest - * -Xlog:jvmti+table - * TagMapTest + * @run main/othervm/native/timeout=480 -agentlib:TagMapTest + * -Xlog:jvmti+table + * TagMapTest */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java index b773cf3fa0a..80dd42c480a 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java @@ -28,7 +28,7 @@ * @library /test/lib * @compile SuspendResume2.java * @run driver jdk.test.lib.FileInstaller . . - * @run main/othervm/native + * @run main/othervm/native/timeout=700 * -Djdk.virtualThreadScheduler.maxPoolSize=1 * -agentlib:SuspendResume2 * SuspendResume2 @@ -40,7 +40,7 @@ * @library /test/lib * @compile SuspendResume2.java * @run driver jdk.test.lib.FileInstaller . . - * @run main/othervm/native + * @run main/othervm/native/timeout=700 * -Djdk.virtualThreadScheduler.maxPoolSize=1 * -agentlib:SuspendResume2 * -XX:-VerifyContinuations @@ -53,7 +53,7 @@ * @library /test/lib * @compile SuspendResume2.java * @run driver jdk.test.lib.FileInstaller . . - * @run main/othervm/native + * @run main/othervm/native/timeout=700 * -agentlib:SuspendResume2 * -XX:+UnlockExperimentalVMOptions * -XX:-VMContinuations diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java index fef7c827eb7..ee9872867ac 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jtreg.SkippedException; * timeouts. As there is no known direct benefit from running the test * with -Xcomp, we disable such testing. * @library /test/lib - * @run main/othervm/timeout=240 ClhsdbDumpheap + * @run main/othervm/timeout=960 ClhsdbDumpheap */ public class ClhsdbDumpheap { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java index c75a38490d5..7ced4c9515b 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jtreg.SkippedException; * @requires vm.compiler1.enabled * @requires vm.opt.DeoptimizeALot != true * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC true false + * @run main/othervm/timeout=1920 ClhsdbFindPC true false */ /** @@ -53,7 +53,7 @@ import jtreg.SkippedException; * @requires vm.compiler1.enabled * @requires vm.opt.DeoptimizeALot != true * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC true true + * @run main/othervm/timeout=1920 ClhsdbFindPC true true */ /** @@ -64,7 +64,7 @@ import jtreg.SkippedException; * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @requires vm.compiler1.enabled * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC false false + * @run main/othervm/timeout=1920 ClhsdbFindPC false false */ /** @@ -74,7 +74,7 @@ import jtreg.SkippedException; * @requires vm.hasSA * @requires vm.compiler1.enabled * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC false true + * @run main/othervm/timeout=1920 ClhsdbFindPC false true */ public class ClhsdbFindPC { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java index 7e06cb3af95..bb35e6c5aff 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -39,7 +39,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @requires vm.opt.DeoptimizeALot != true * @library /test/lib - * @run driver/timeout=300 ClhsdbJstackXcompStress + * @run driver/timeout=1200 ClhsdbJstackXcompStress */ public class ClhsdbJstackXcompStress { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java index 988227f3961..5c3092a139d 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jtreg.SkippedException; * @requires vm.hasSA * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @library /test/lib - * @run main/othervm ClhsdbThreadContext + * @run main/othervm/timeout=480 ClhsdbThreadContext */ public class ClhsdbThreadContext { diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java index 87e664ef308..15b9aa9ccae 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.SA.SATestUtils; * @requires os.family=="windows" | os.family == "linux" | os.family == "mac" * @requires vm.flagless * @library /test/lib - * @run driver TestJhsdbJstackLineNumbers + * @run driver/timeout=480 TestJhsdbJstackLineNumbers */ /* diff --git a/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java b/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java index 28d6f74c689..62fe2f5d7aa 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java +++ b/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.Utils; * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @modules jdk.hotspot.agent/sun.jvm.hotspot * jdk.hotspot.agent/sun.jvm.hotspot.runtime - * @run driver TestObjectAlignment + * @run driver/timeout=480 TestObjectAlignment */ public class TestObjectAlignment { diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java index ebdd69e7d40..69f4c9eb454 100644 --- a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules java.base/jdk.internal.misc * @library /test/lib * - * @run driver SADebugDTest + * @run driver/timeout=480 SADebugDTest */ import java.util.concurrent.TimeUnit; @@ -125,7 +125,7 @@ public class SADebugDTest { // The startProcess will block until the 'golden' string appears in either process' stdout or stderr // In case of timeout startProcess kills the debugd process - Process debugd = startProcess("debugd", pb, null, l -> checkOutput(l, useRmiPort, rmiPort), 20, TimeUnit.SECONDS); + Process debugd = startProcess("debugd", pb, null, l -> checkOutput(l, useRmiPort, rmiPort), 80, TimeUnit.SECONDS); // If we are here, this means we have received the golden line and the test has passed // The debugd remains running, we have to kill it diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java index 8ba72f1bd86..bf8de679dfa 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java @@ -33,7 +33,7 @@ import compiler.lib.ir_framework.driver.irmatching.IRViolationException; * @requires vm.compiler2.enabled & vm.flagless & vm.debug == true * @summary Test the functionality of allowNotCompilable. * @library /test/lib / - * @run driver ir_framework.tests.TestNotCompilable + * @run driver/timeout=480 ir_framework.tests.TestNotCompilable */ public class TestNotCompilable { diff --git a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java index 51d787ec218..10bafe26ae4 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @requires vm.opt.ClassUnloadingWithConcurrentMark != false * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java index 4d681af1e28..03108809ebd 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @requires vm.opt.ClassUnloadingWithConcurrentMark != false * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java index 4d93785e5c6..8f8cfdcd541 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * -Xlog:gc* * gc.gctests.LargeObjects.large001.large001 diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java index c96b47cf1cd..c207b80c059 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java index adfa8879153..fd7e1e5e8dd 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java index 7b09a18d798..2301daba8d3 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java index d2943ff90ab..abf91f48dea 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java index ba9b6d75750..f57e0888268 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * /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 gc.gctests.SoftReference.soft004.soft004 -t 1 + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.gctests.SoftReference.soft004.soft004 -t 1 */ package gc.gctests.SoftReference.soft004; diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java index bf86f5d8045..29390ae02d5 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * /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 gc.gctests.WeakReference.weak004.weak004 -t 1 + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.gctests.WeakReference.weak004.weak004 -t 1 */ package gc.gctests.WeakReference.weak004; diff --git a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java index 2e4cfcb9992..68fe6779e99 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,5 +31,5 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm gc.vector.SimpleGC.SimpleGC -ms low -gp circularList(low) + * @run main/othervm/timeout=480 gc.vector.SimpleGC.SimpleGC -ms low -gp circularList(low) */ diff --git a/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java b/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java index e2d04c6745a..17e88aeebb0 100644 --- a/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java +++ b/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase * /test/lib * @build jit.escape.AdaptiveBlocking.AdaptiveBlocking001.AdaptiveBlocking001 - * @run driver/timeout=300 ExecDriver --java -server -Xcomp -XX:+DoEscapeAnalysis + * @run driver/timeout=1200 ExecDriver --java -server -Xcomp -XX:+DoEscapeAnalysis * jit.escape.AdaptiveBlocking.AdaptiveBlocking001.AdaptiveBlocking001 -numRounds 10 */ diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java index 577bb5f1a92..3fb8241191d 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * * @requires vm.opt.final.ClassUnloading * @library /vmTestbase /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -DrequiresCompressedClassSpace=true * -XX:MaxMetaspaceSize=100m * -XX:CompressedClassSpaceSize=10m * -Xlog:gc*:gc.log * metaspace.shrink_grow.ShrinkGrowTest.ShrinkGrowTest */ - diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java index c59f8cd9e9e..dc7881dc8f7 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @requires vm.opt.final.ClassUnloading * @library /vmTestbase /test/lib * @build metaspace.shrink_grow.ShrinkGrowMultiJVM.ShrinkGrowMultiJVM - * @run driver metaspace.shrink_grow.ShrinkGrowMultiJVM.ShrinkGrowMultiJVM + * @run driver/timeout=480 metaspace.shrink_grow.ShrinkGrowMultiJVM.ShrinkGrowMultiJVM */ package metaspace.shrink_grow.ShrinkGrowMultiJVM; diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java index 32f5c0c55e8..2b4082d215f 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java index 75faa8d14e3..e936c3fe73e 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java index 743de7b4e7d..48fa6fe5392 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java index bc6287eaf60..ada43b47c59 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java index 030f07fbaea..e66673d3316 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java index f294a4ecc6a..288ea9d2105 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java index f3238d787c2..651da5c2955 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java index a37231429c3..03b8f77cfaf 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java index dd28f1665a7..247abdfaa3d 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java index ab11ba48647..2c9acbbbf01 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java index ce304df4041..755869c92d2 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java index a37eda53cfa..71a61a92ede 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=250m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java index a10d9b2d50b..c9cf9ee88cb 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java index c0ceceb1e50..181a526e97f 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java index a0c73e6dd0c..11eba8b2b1f 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java index 7e73bace342..b5ea8c34cbd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * /test/lib * @build nsk.jdi.ObjectReference.referringObjects.referringObjects001.referringObjects001 * nsk.share.jdi.TestClass1 - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.jdi.ObjectReference.referringObjects.referringObjects001.referringObjects001 * -verbose * -arch=${os.family}-${os.simpleArch} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java index ff303d4c52d..14c0ebf74f5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java @@ -62,7 +62,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdi.StepEvent._itself_.stepEvent004.stepEvent004 - * @run driver + * @run driver/timeout=480 * nsk.jdi.StepEvent._itself_.stepEvent004.stepEvent004 * -verbose * -arch=${os.family}-${os.simpleArch} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java index b638a58976f..269aaec8226 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,7 +82,7 @@ * /test/lib * @build nsk.jdi.ThreadDeathEvent.thread.thread001 * nsk.jdi.ThreadDeathEvent.thread.thread001a - * @run driver + * @run driver/timeout=480 * nsk.jdi.ThreadDeathEvent.thread.thread001 * -verbose * -arch=${os.family}-${os.simpleArch} @@ -91,4 +91,3 @@ * -transport.address=dynamic * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java index 938673e2284..e5d77e0263b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +63,7 @@ * nsk.share.jdi.MonitorEventsDebuggee * * @build nsk.share.jdi.SerialExecutionDebugger - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.share.jdi.SerialExecutionDebugger * -verbose * -arch=${os.family}-${os.simpleArch} @@ -76,4 +76,3 @@ * -configFile ${test.src}/mixed002.tests * -testWorkDir . */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java index e41efd46bb4..32cf223dda7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.jdwp.VirtualMachine.HoldEvents.holdevents002a - * @run main/othervm/timeout=420 + * @run main/othervm/timeout=1680 * nsk.jdwp.VirtualMachine.HoldEvents.holdevents002 * -arch=${os.family}-${os.simpleArch} * -verbose @@ -62,4 +62,3 @@ * -transport.address=dynamic * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java index 7705260e802..93b59229f14 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +37,5 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native -agentlib:rawmnwait001 nsk.jvmti.RawMonitorWait.rawmnwait001 + * @run main/othervm/native/timeout=480 -agentlib:rawmnwait001 nsk.jvmti.RawMonitorWait.rawmnwait001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java index 9c5f23d0c43..cf472a079c2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +59,7 @@ * @build nsk.jvmti.scenarios.sampling.SP03.sp03t001 * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp03t001=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP03.sp03t001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java index ba4d3f332ce..7c9f0773788 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +59,7 @@ * @build nsk.jvmti.scenarios.sampling.SP03.sp03t002 * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp03t002=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP03.sp03t002 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java index 730cfa104e5..dbb8f30873f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +58,7 @@ * /test/lib * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp04t001=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP04.sp04t001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java index e03a343e381..da08316bfd2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +58,7 @@ * /test/lib * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp04t002=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP04.sp04t002 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java index 79ccb9c8e70..182cf4494ff 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +38,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp07t001=-waittime=5 * nsk.jvmti.scenarios.sampling.SP07.sp07t001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java index 411d70f6e91..e8b855b5ce6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /vmTestbase * /test/lib * /testlibrary - * @run main/othervm nsk.monitoring.ThreadInfo.isSuspended.issuspended002 + * @run main/othervm/timeout=480 nsk.monitoring.ThreadInfo.isSuspended.issuspended002 */ package nsk.monitoring.ThreadInfo.isSuspended; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java index 53b73954af5..5732f319bc9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +60,5 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native nsk.monitoring.stress.thread.strace001 -threadCount=50 -depth=200 + * @run main/othervm/native/timeout=480 nsk.monitoring.stress.thread.strace001 -threadCount=50 -depth=200 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java index b41fb5f76f8..6548e27c779 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +58,9 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.monitoring.stress.thread.strace001 * -testMode=server * -threadCount=50 * -depth=200 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java index c39f4dde2af..fc0174092e0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +58,10 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.monitoring.stress.thread.strace001 * -testMode=server * -MBeanServer=custom * -threadCount=50 * -depth=200 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java index ef27aa57bfa..accfae7e4bd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native nsk.stress.strace.strace006 + * @run main/othervm/native/timeout=480 nsk.stress.strace.strace006 */ package nsk.stress.strace; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java index 4fdab351c79..a047824ffbb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * lower than the main thread. * * @library /test/lib - * @run main/othervm nsk.stress.thread.thread001 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread001 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java index a574533581f..f4d48b9eaa7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * Try to start the given number of threads of the same * priority that the main thread. * - * @run main/othervm nsk.stress.thread.thread002 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread002 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java index 0a5e33441cb..06afa1d2154 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * DESCRIPTION * Try many threads starting simultaneously. * - * @run main/othervm nsk.stress.thread.thread005 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread005 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java index 6adda1929d2..b6e5115e153 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * Try many threads of lower priority * starting simultaneously. * - * @run main/othervm nsk.stress.thread.thread006 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread006 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java index 26388c28d0a..04b3784ce11 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * Try to start the given number of threads starting simultaneously * when notifyall() is signaled at the stopLine object. * - * @run main/othervm/timeout=300 nsk.stress.thread.thread007 500 2m 5s + * @run main/othervm/timeout=1200 nsk.stress.thread.thread007 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java index 2cbc198a693..a6a64bc9ce9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * starting simultaneously when notifyall() is signaled at the * stopLine object. * - * @run main/othervm/timeout=300 nsk.stress.thread.thread008 500 2m 5s + * @run main/othervm/timeout=1200 nsk.stress.thread.thread008 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java index db6ebf0a446..d00b965cce2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +40,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -t 1 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java index 5a4a9fae0d6..e2b161f6f47 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +39,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useSingleLoader * -t 1 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java index b915e0d716c..7fedad20e90 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +39,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -t 1 * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java index 14094d6a5a1..dc8170c80e9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 +40,12 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java index 42041c94fcf..55b20419d17 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +39,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useSingleLoader */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java index 49b55e39456..ed15893686f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +39,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java index 6c74967dd22..dd58953d323 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +42,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -t 1 * -stressHeap */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java index 9861f3c051f..a0dff733054 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +41,11 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar @@ -53,4 +53,3 @@ * -stressHeap * -t 1 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java index 273fceebb81..6f70b64178b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +41,11 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar @@ -53,4 +53,3 @@ * -stressHeap * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java index 1e9f3e8813f..27d6166776b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +42,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -stressHeap */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java index 507abcef278..0a46ed3d80c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +41,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useSingleLoader * -stressHeap */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java index 45ce9150457..cdc22cbb399 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +41,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -stressHeap * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java index 5afb841f141..e0be5f1adb5 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,4 +59,3 @@ * vm.mlvm.indy.func.jvmti.share.IndyRedefineTest * -dummyClassName=vm.mlvm.indy.func.jvmti.mergeCP_indy2manyDiff_a.INDIFY_Dummy0 */ - diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java index 146db0dfa80..72212757a8e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java @@ -50,7 +50,7 @@ * @build vm.mlvm.meth.stress.compiler.i2c_c2i.Test * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm -XX:CompileCommand=MemLimit,*.*,0 vm.mlvm.meth.stress.compiler.i2c_c2i.Test + * @run main/othervm/timeout=480 -XX:CompileCommand=MemLimit,*.*,0 vm.mlvm.meth.stress.compiler.i2c_c2i.Test */ package vm.mlvm.meth.stress.compiler.i2c_c2i; diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java index 9a34a2b7b3d..daf5aa19609 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build vm.mlvm.meth.stress.compiler.sequences.Test * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=480 * vm.mlvm.meth.stress.compiler.sequences.Test * -threadsPerCpu 1 * -threadsExtra 2 diff --git a/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java b/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java index b2122d5691b..3b817325bcf 100644 --- a/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java +++ b/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary com.sun.crypto.provider.SunJCE instance leak using KRB5 and * LoginContext * @author Brad Wetmore + * @library /test/lib * * @run main/othervm -Xmx20m TestProviderLeak * @@ -47,6 +48,7 @@ import javax.crypto.spec.*; import java.util.*; import java.util.concurrent.*; import jdk.test.lib.security.SecurityUtils; +import jdk.test.lib.Utils; public class TestProviderLeak { private static final int MB = 1024 * 1024; @@ -59,9 +61,7 @@ public class TestProviderLeak { static { int timeout = 5; try { - double timeoutFactor = Double.parseDouble( - System.getProperty("test.timeout.factor", "1.0")); - timeout = (int) (timeout * timeoutFactor); + timeout = (int) (timeout * Utils.TIMEOUT_FACTOR); } catch (Exception e) { System.out.println("Warning: " + e); } diff --git a/test/jdk/com/sun/jdi/InterruptHangTest.java b/test/jdk/com/sun/jdi/InterruptHangTest.java index 5dcb5efef31..07af07e3c02 100644 --- a/test/jdk/com/sun/jdi/InterruptHangTest.java +++ b/test/jdk/com/sun/jdi/InterruptHangTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ import com.sun.jdi.*; import com.sun.jdi.event.*; import com.sun.jdi.request.*; +import jdk.test.lib.Utils; /** * @test * @bug 6459476 * @summary Test interrupting debuggee with single stepping enable * @author jjh + * @library /test/lib * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g InterruptHangTest.java @@ -284,8 +286,7 @@ public class InterruptHangTest extends TestScaffold { timerThread = new Thread("test timer") { public void run() { int mySteps = 0; - float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - long sleepSeconds = (long)(20 * timeoutFactor); + long sleepSeconds = (long)(20 * Utils.TIMEOUT_FACTOR); println("Timer watching for steps every " + sleepSeconds + " seconds"); while (true) { try { diff --git a/test/jdk/com/sun/jdi/MethodEntryExitEvents.java b/test/jdk/com/sun/jdi/MethodEntryExitEvents.java index abdb0ff7c75..075d2044240 100644 --- a/test/jdk/com/sun/jdi/MethodEntryExitEvents.java +++ b/test/jdk/com/sun/jdi/MethodEntryExitEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g MethodEntryExitEvents.java - * @run driver MethodEntryExitEvents SUSPEND_EVENT_THREAD MethodEntryExitEventsDebugee - * @run driver MethodEntryExitEvents SUSPEND_NONE MethodEntryExitEventsDebugee - * @run driver MethodEntryExitEvents SUSPEND_ALL MethodEntryExitEventsDebugee + * @run driver/timeout=480 MethodEntryExitEvents SUSPEND_EVENT_THREAD MethodEntryExitEventsDebugee + * @run driver/timeout=480 MethodEntryExitEvents SUSPEND_NONE MethodEntryExitEventsDebugee + * @run driver/timeout=480 MethodEntryExitEvents SUSPEND_ALL MethodEntryExitEventsDebugee */ import com.sun.jdi.*; import com.sun.jdi.event.*; diff --git a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java index ef44829f1f7..59168a4de7e 100644 --- a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java +++ b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g ThreadMemoryLeakTest.java * @comment run with -Xmx7m so any leak will quickly produce OOME - * @run main/othervm -Xmx7m ThreadMemoryLeakTest + * @run main/othervm/timeout=480 -Xmx7m ThreadMemoryLeakTest */ import com.sun.jdi.*; import com.sun.jdi.event.*; diff --git a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java index 123c5120daf..294e0f5f1a8 100644 --- a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java +++ b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java @@ -27,7 +27,7 @@ * @summary Multi-threaded client timeout tests for ldap pool * @library /test/lib * lib/ - * @run testng/othervm LdapPoolTimeoutTest + * @run testng/othervm/timeout=480 LdapPoolTimeoutTest */ import org.testng.annotations.Test; @@ -144,4 +144,3 @@ public class LdapPoolTimeoutTest { } } - diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java index fccc12a9f06..b73db200ee2 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @bug 4927640 * @summary Tests the SCTP protocol implementation * @author chegar + * @run main/timeout=480 Connect */ import java.net.InetSocketAddress; diff --git a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java index 49ba4d64b5b..6d62aa6c154 100644 --- a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java +++ b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @bug 4927640 * @summary Tests the SCTP protocol implementation * @author chegar + * @run main/timeout=480 NonBlockingAccept */ import java.net.InetSocketAddress; diff --git a/test/jdk/java/awt/font/NumericShaper/MTTest.java b/test/jdk/java/awt/font/NumericShaper/MTTest.java index 08a218dfc0d..a152f552dd1 100644 --- a/test/jdk/java/awt/font/NumericShaper/MTTest.java +++ b/test/jdk/java/awt/font/NumericShaper/MTTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 6843181 6943963 * @summary Confirm that NumericShaper is thread-safe. - * @run main/timeout=300/othervm MTTest + * @run main/timeout=400/othervm MTTest */ import java.awt.font.NumericShaper; diff --git a/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java b/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java index 1f6dc09550c..dc3384a3572 100644 --- a/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java +++ b/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import java.util.List; * @author Sergey Malenkov * @modules java.desktop/com.sun.beans.finder * @compile -XDignore.symbol.file TestMethodFinder.java - * @run main TestMethodFinder + * @run main/timeout=480 TestMethodFinder */ public class TestMethodFinder { diff --git a/test/jdk/java/foreign/StdLibTest.java b/test/jdk/java/foreign/StdLibTest.java index 7bb8a29b0c0..f1e35b53a39 100644 --- a/test/jdk/java/foreign/StdLibTest.java +++ b/test/jdk/java/foreign/StdLibTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 - * @run testng/othervm --enable-native-access=ALL-UNNAMED StdLibTest + * @run testng/othervm/timeout=480 --enable-native-access=ALL-UNNAMED StdLibTest */ import java.lang.invoke.MethodHandle; diff --git a/test/jdk/java/foreign/TestAccessModes.java b/test/jdk/java/foreign/TestAccessModes.java index a721c87484d..e54d4f1ae9e 100644 --- a/test/jdk/java/foreign/TestAccessModes.java +++ b/test/jdk/java/foreign/TestAccessModes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +23,10 @@ /* * @test - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes */ import java.lang.foreign.*; diff --git a/test/jdk/java/foreign/TestBufferStackStress2.java b/test/jdk/java/foreign/TestBufferStackStress2.java index cefdbb725d1..402ce6bbe94 100644 --- a/test/jdk/java/foreign/TestBufferStackStress2.java +++ b/test/jdk/java/foreign/TestBufferStackStress2.java @@ -30,7 +30,7 @@ * @bug 8356114 8356658 * @modules java.base/jdk.internal.foreign * @build NativeTestHelper TestBufferStackStress2 - * @run junit TestBufferStackStress2 + * @run junit/timeout=480 TestBufferStackStress2 */ import jdk.internal.foreign.BufferStack; diff --git a/test/jdk/java/foreign/TestConcurrentClose.java b/test/jdk/java/foreign/TestConcurrentClose.java index 06dc7375cda..82bb2492acf 100644 --- a/test/jdk/java/foreign/TestConcurrentClose.java +++ b/test/jdk/java/foreign/TestConcurrentClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run testng/othervm + * @run testng/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/jdk/java/foreign/TestDeadlock.java b/test/jdk/java/foreign/TestDeadlock.java index 8511a01d2f5..f333727d4ce 100644 --- a/test/jdk/java/foreign/TestDeadlock.java +++ b/test/jdk/java/foreign/TestDeadlock.java @@ -23,7 +23,7 @@ /* * @test id=Arena_allocateFrom - * @run main/othervm/timeout=10 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock Arena + * @run main/othervm/timeout=60 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock Arena */ /* diff --git a/test/jdk/java/foreign/TestMismatch.java b/test/jdk/java/foreign/TestMismatch.java index f50621e3415..fa01f1553eb 100644 --- a/test/jdk/java/foreign/TestMismatch.java +++ b/test/jdk/java/foreign/TestMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8323552 - * @run testng TestMismatch + * @run testng/timeout=480 TestMismatch */ import java.lang.foreign.Arena; diff --git a/test/jdk/java/foreign/TestStringEncodingJumbo.java b/test/jdk/java/foreign/TestStringEncodingJumbo.java index 8ef86e72efc..bdae83bbd8b 100644 --- a/test/jdk/java/foreign/TestStringEncodingJumbo.java +++ b/test/jdk/java/foreign/TestStringEncodingJumbo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static org.testng.Assert.*; * @requires sun.arch.data.model == "64" * @requires vm.flavor != "zero" * - * @run testng/othervm -Xmx6G TestStringEncodingJumbo + * @run testng/othervm/timeout=480 -Xmx6G TestStringEncodingJumbo */ public class TestStringEncodingJumbo { diff --git a/test/jdk/java/foreign/TestStubAllocFailure.java b/test/jdk/java/foreign/TestStubAllocFailure.java index b3b327e788c..8cd4a61626e 100644 --- a/test/jdk/java/foreign/TestStubAllocFailure.java +++ b/test/jdk/java/foreign/TestStubAllocFailure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library ../ /test/lib * @requires jdk.foreign.linker != "FALLBACK" * @requires vm.compMode != "Xcomp" - * @run testng/othervm/native + * @run testng/othervm/native/timeout=480 * --enable-native-access=ALL-UNNAMED * TestStubAllocFailure */ diff --git a/test/jdk/java/foreign/TestUpcallStack.java b/test/jdk/java/foreign/TestUpcallStack.java index 726373b9e27..4552cbef734 100644 --- a/test/jdk/java/foreign/TestUpcallStack.java +++ b/test/jdk/java/foreign/TestUpcallStack.java @@ -27,7 +27,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run testng/othervm/native/timeout=480 -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestUpcallStack */ diff --git a/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java b/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java index cc44d194174..204f4038144 100644 --- a/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java +++ b/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java @@ -25,7 +25,7 @@ * @test * @compile lookup/Lookup.java * @compile invoker/Invoker.java - * @run main/othervm/native --enable-native-access=ALL-UNNAMED TestLoaderLookup + * @run main/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED TestLoaderLookup */ import java.lang.foreign.*; diff --git a/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java b/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java index ac5d6c6a329..e0aeb76f93f 100644 --- a/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java +++ b/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 6524062 * @summary Test to ensure that FIS.finalize() invokes the close() method as per * the specification. - * @run main/othervm UnreferencedFISClosesFd + * @run main/othervm/timeout=480 UnreferencedFISClosesFd */ import java.io.File; import java.io.FileDescriptor; diff --git a/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java b/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java index 3ff817085bd..ada39a2803a 100644 --- a/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java +++ b/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build jdk.test.lib.util.FileUtils UnreferencedFOSClosesFd * @bug 6524062 * @summary Test to ensure that the fd is closed if left unreferenced - * @run main/othervm UnreferencedFOSClosesFd + * @run main/othervm/timeout=480 UnreferencedFOSClosesFd */ import java.io.File; import java.io.FileDescriptor; diff --git a/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java b/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java index c5b73a07c7d..99212b9a837 100644 --- a/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java +++ b/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +48,7 @@ import jdk.test.lib.util.FileUtils; * @build jdk.test.lib.util.FileUtils UnreferencedRAFClosesFd * @modules java.base/java.io:open * @summary Test to ensure that an unclosed and unreferenced RandomAccessFile closes the fd - * @run main/othervm UnreferencedRAFClosesFd + * @run main/othervm/timeout=480 UnreferencedRAFClosesFd */ public class UnreferencedRAFClosesFd { diff --git a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java index 51ce41d837b..4f700df33dc 100644 --- a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java +++ b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.internal.module.Modules; * loads all classes and get their declared fields * and call setAccessible(false) followed by setAccessible(true); * @modules java.base/jdk.internal.module - * @run main/othervm --add-modules=ALL-SYSTEM FieldSetAccessibleTest + * @run main/othervm/timeout=480 --add-modules=ALL-SYSTEM FieldSetAccessibleTest * * @author danielfuchs */ diff --git a/test/jdk/java/lang/Math/IntegralPowTest.java b/test/jdk/java/lang/Math/IntegralPowTest.java index b0aadcc8d3b..ffbb499e0c8 100644 --- a/test/jdk/java/lang/Math/IntegralPowTest.java +++ b/test/jdk/java/lang/Math/IntegralPowTest.java @@ -25,7 +25,7 @@ * @test * @bug 8355992 * @summary Tests for StrictMath.*PowExact and .*unsignedMultiplyExact - * @run junit IntegralPowTest + * @run junit/timeout=480 IntegralPowTest */ import org.junit.jupiter.api.Test; diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java index 146c2be563f..02f3583f0b3 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java @@ -27,7 +27,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest */ /** @@ -35,7 +35,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest */ /** @@ -43,7 +43,7 @@ * @summary Check that we don't leak FDs * @requires os.family == "linux" * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest */ import jdk.test.lib.process.ProcessTools; diff --git a/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java b/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java index d2625518b6d..5f310ff7df4 100644 --- a/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java +++ b/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +30,8 @@ import java.io.IOException; * @requires (os.family == "linux" | os.family == "mac") * @comment Don't allow -Xcomp, it disturbs the relative timing of the sleep and kill commands * @requires (vm.compMode != "Xcomp") - * @run main/othervm -Djdk.lang.Process.launchMechanism=POSIX_SPAWN UnblockSignals - * @run main/othervm -Djdk.lang.Process.launchMechanism=POSIX_SPAWN -Xrs UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=POSIX_SPAWN UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=POSIX_SPAWN -Xrs UnblockSignals */ /* @@ -41,8 +41,8 @@ import java.io.IOException; * @requires (os.family == "linux" | os.family == "mac") * @comment Don't allow -Xcomp, it disturbs the relative timing of the sleep and kill commands * @requires (vm.compMode != "Xcomp") - * @run main/othervm -Djdk.lang.Process.launchMechanism=FORK UnblockSignals - * @run main/othervm -Djdk.lang.Process.launchMechanism=FORK -Xrs UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=FORK UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=FORK -Xrs UnblockSignals */ public class UnblockSignals { diff --git a/test/jdk/java/lang/StackWalker/LocalsAndOperands.java b/test/jdk/java/lang/StackWalker/LocalsAndOperands.java index 900cad1246a..445a4efe649 100644 --- a/test/jdk/java/lang/StackWalker/LocalsAndOperands.java +++ b/test/jdk/java/lang/StackWalker/LocalsAndOperands.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8020968 8147039 8156073 * @summary Tests for locals and operands * @modules java.base/java.lang:open - * @run testng/othervm -Xint -DtestUnused=true LocalsAndOperands - * @run testng/othervm -Xcomp LocalsAndOperands + * @run testng/othervm/timeout=480 -Xint -DtestUnused=true LocalsAndOperands + * @run testng/othervm/timeout=480 -Xcomp LocalsAndOperands */ /* @@ -35,7 +35,7 @@ * @bug 8020968 8147039 8156073 * @modules java.base/java.lang:open * @requires !vm.graal.enabled - * @run testng/othervm -Xcomp -XX:-TieredCompilation LocalsAndOperands + * @run testng/othervm/timeout=480 -Xcomp -XX:-TieredCompilation LocalsAndOperands */ import org.testng.annotations.*; diff --git a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java index 3511a870f39..076e3c53faf 100644 --- a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java +++ b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +32,9 @@ import java.nio.charset.StandardCharsets; * @summary Tests Compact String for maximum size strings * @requires os.maxMemory >= 8g & vm.bits == 64 * @requires vm.flagless - * @run junit/othervm -XX:+CompactStrings -Xmx8g MaxSizeUTF16String - * @run junit/othervm -XX:-CompactStrings -Xmx8g MaxSizeUTF16String - * @run junit/othervm -Xcomp -Xmx8g MaxSizeUTF16String + * @run junit/othervm/timeout=480 -XX:+CompactStrings -Xmx8g MaxSizeUTF16String + * @run junit/othervm/timeout=480 -XX:-CompactStrings -Xmx8g MaxSizeUTF16String + * @run junit/othervm/timeout=480 -Xcomp -Xmx8g MaxSizeUTF16String */ public class MaxSizeUTF16String { diff --git a/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java b/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java index 49eb3b28ff3..2a6e92e9402 100644 --- a/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java +++ b/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java @@ -33,9 +33,9 @@ import static org.testng.Assert.assertTrue; * @bug 8054307 8077559 8351443 * @summary Tests Compact String. This test is testing StringBuilder * behavior related to Compact String. - * @run testng/othervm -XX:+CompactStrings CompactStringBuilder - * @run testng/othervm -XX:-CompactStrings CompactStringBuilder - * @run testng/othervm -Xcomp CompactStringBuilder + * @run testng/othervm/timeout=480 -XX:+CompactStrings CompactStringBuilder + * @run testng/othervm/timeout=480 -XX:-CompactStrings CompactStringBuilder + * @run testng/othervm/timeout=480 -Xcomp CompactStringBuilder */ public class CompactStringBuilder { diff --git a/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java b/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java index 840e40453c6..9c8e37e8c6d 100644 --- a/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java +++ b/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * contention on the timer queue * @requires vm.continuations * @key randomness - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.virtualThreadScheduler.parallelism=2 * -Djdk.virtualThreadScheduler.timerQueues=1 * CancelTimerWithContention diff --git a/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java b/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java index b512aa75789..32586812614 100644 --- a/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java +++ b/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java @@ -27,7 +27,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm MiscMonitorTests + * @run junit/othervm/timeout=480 MiscMonitorTests */ /* @@ -35,7 +35,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xint MiscMonitorTests + * @run junit/othervm/timeout=480 -Xint MiscMonitorTests */ /* @@ -43,7 +43,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xcomp MiscMonitorTests + * @run junit/othervm/timeout=480 -Xcomp MiscMonitorTests */ /* @@ -51,7 +51,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xcomp -XX:TieredStopAtLevel=3 MiscMonitorTests + * @run junit/othervm/timeout=480 -Xcomp -XX:TieredStopAtLevel=3 MiscMonitorTests */ /* @@ -60,7 +60,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xcomp -XX:-TieredCompilation MiscMonitorTests + * @run junit/othervm/timeout=480 -Xcomp -XX:-TieredCompilation MiscMonitorTests */ /* @@ -68,7 +68,7 @@ * @requires vm.debug == true & vm.continuations * @library /test/lib * @modules java.base/java.lang:+open - * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=1000 MiscMonitorTests + * @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=1000 MiscMonitorTests */ import java.util.concurrent.atomic.AtomicInteger; diff --git a/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java b/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java index 3a7eecd054e..14b8ffc1949 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java @@ -26,35 +26,35 @@ * @summary Test virtual thread with monitor enter/exit * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xint * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xint --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xint --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xcomp * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xcomp --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xcomp-TieredStopAtLevel1 * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xcomp-noTieredCompilation * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorEnterExit */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java index d5df8eb97d0..47089d9d6df 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java @@ -26,35 +26,35 @@ * @summary Test virtual threads using Object.wait/notifyAll * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xint * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xint --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xint --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xcomp * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xcomp --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xcomp-TieredStopAtLevel1 * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xcomp-noTieredCompilation * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ import java.util.ArrayList; diff --git a/test/jdk/java/lang/Thread/virtual/Parking.java b/test/jdk/java/lang/Thread/virtual/Parking.java index 574707e637c..c337f36e7c2 100644 --- a/test/jdk/java/lang/Thread/virtual/Parking.java +++ b/test/jdk/java/lang/Thread/virtual/Parking.java @@ -26,28 +26,28 @@ * @summary Test virtual threads using park/unpark * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit Parking + * @run junit/timeout=480 Parking */ /* * @test id=Xint * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm -Xint Parking + * @run junit/othervm/timeout=480 -Xint Parking */ /* * @test id=Xcomp * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm -Xcomp Parking + * @run junit/othervm/timeout=480 -Xcomp Parking */ /* * @test id=Xcomp-noTieredCompilation * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm -Xcomp -XX:-TieredCompilation Parking + * @run junit/othervm/timeout=480 -Xcomp -XX:-TieredCompilation Parking */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java b/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java index 1c7177d9f38..464259ecb86 100644 --- a/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java +++ b/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java @@ -29,7 +29,7 @@ * can't continue because there are no carriers available. * @modules java.base/java.lang:+open * @library /test/lib - * @run main/othervm/native --enable-native-access=ALL-UNNAMED RetryMonitorEnterWhenPinned + * @run main/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED RetryMonitorEnterWhenPinned */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/Starvation.java b/test/jdk/java/lang/Thread/virtual/Starvation.java index 2b8da5fbca8..c55ad3c2494 100644 --- a/test/jdk/java/lang/Thread/virtual/Starvation.java +++ b/test/jdk/java/lang/Thread/virtual/Starvation.java @@ -25,7 +25,7 @@ * @requires vm.continuations * @library /test/lib * @bug 8345294 - * @run main/othervm/timeout=200/native --enable-native-access=ALL-UNNAMED Starvation 100000 + * @run main/othervm/timeout=800/native --enable-native-access=ALL-UNNAMED Starvation 100000 */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java b/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java index c894944aa25..7a3da0ac334 100644 --- a/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java +++ b/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java @@ -28,7 +28,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED SynchronizedNative */ /* @@ -36,7 +36,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xint --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 -Xint --enable-native-access=ALL-UNNAMED SynchronizedNative */ /* @@ -44,7 +44,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED SynchronizedNative */ /* @@ -52,7 +52,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED SynchronizedNative */ import java.util.concurrent.CountDownLatch; diff --git a/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java b/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java index 4e6c3c12269..56257b8847e 100644 --- a/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java +++ b/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java @@ -27,7 +27,7 @@ * @summary Test that Thread.yield loop polls for safepoints * @requires vm.continuations * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED ThreadPollOnYield + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED ThreadPollOnYield */ /* @@ -36,7 +36,7 @@ * @summary Test that Thread.yield loop polls for safepoints * @requires vm.continuations & vm.compMode != "Xcomp" * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED -Xcomp -XX:-TieredCompilation + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED -Xcomp -XX:-TieredCompilation * -XX:CompileCommand=inline,*::yield* -XX:CompileCommand=inline,*::*Yield ThreadPollOnYield */ diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java index 17b63573d85..fa4d16d9f82 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @requires vm.debug != true * @modules jdk.management * @library /test/lib - * @run main/othervm/timeout=300 GetStackTraceALotWhenBlocking 100000 + * @run main/othervm/timeout=1200 GetStackTraceALotWhenBlocking 100000 */ /* @@ -36,7 +36,7 @@ * @requires vm.debug == true & vm.continuations * @modules jdk.management * @library /test/lib - * @run main/othervm/timeout=300 GetStackTraceALotWhenBlocking 50000 + * @run main/othervm/timeout=1200 GetStackTraceALotWhenBlocking 50000 */ import java.time.Instant; diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java index ad3fbdf0565..0e8693756e5 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 @@ * @test * @summary Stress test Thread.getStackTrace on a virtual thread in timed-Object.wait * @requires vm.debug != true - * @run main GetStackTraceALotWithTimedWait 100000 + * @run main/timeout=480 GetStackTraceALotWithTimedWait 100000 */ /* * @test * @requires vm.debug == true - * @run main GetStackTraceALotWithTimedWait 50000 + * @run main/timeout=480 GetStackTraceALotWithTimedWait 50000 */ import java.time.Instant; @@ -88,4 +88,3 @@ public class GetStackTraceALotWithTimedWait { } } } - diff --git a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java index c30193bc121..29704fd8975 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +26,14 @@ * @summary Stress test parking and unparking * @requires vm.debug != true * @library /test/lib - * @run main/othervm/timeout=300 ParkALot 300000 + * @run main/othervm/timeout=1200 ParkALot 300000 */ /* * @test * @requires vm.debug == true * @library /test/lib - * @run main/othervm/timeout=300 ParkALot 100000 + * @run main/othervm/timeout=1200 ParkALot 100000 */ import java.time.Instant; diff --git a/test/jdk/java/lang/Thread/virtual/stress/PinALot.java b/test/jdk/java/lang/Thread/virtual/stress/PinALot.java index ff45ea837ae..2da43388a85 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/PinALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/PinALot.java @@ -26,14 +26,14 @@ * @summary Stress test timed park when pinned * @requires vm.debug != true * @library /test/lib - * @run main/othervm/native --enable-native-access=ALL-UNNAMED PinALot 500000 + * @run main/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED PinALot 500000 */ /* * @test * @requires vm.debug == true * @library /test/lib - * @run main/othervm/native/timeout=300 --enable-native-access=ALL-UNNAMED PinALot 200000 + * @run main/othervm/native/timeout=1200 --enable-native-access=ALL-UNNAMED PinALot 200000 */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java index 1d9a5b7104b..06f3b5ff235 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java +++ b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java @@ -26,13 +26,13 @@ * @summary Stress test virtual threads with a variation of the Skynet 1M benchmark * @requires vm.continuations * @requires !vm.debug | vm.gc != "Z" - * @run main/othervm/timeout=400 -Xmx1500m Skynet + * @run main/othervm/timeout=1600 -Xmx1500m Skynet */ /* * @test id=Z * @requires vm.debug == true & vm.continuations * @requires vm.gc.Z - * @run main/othervm/timeout=400 -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=1600 -XX:+UnlockDiagnosticVMOptions * -XX:+UseZGC * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1500m Skynet */ diff --git a/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java b/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java index 7949529af60..77eed59c88d 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java +++ b/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java @@ -27,13 +27,13 @@ * a channel implementation based on object monitors. This variant uses a reduced number of * 100k virtual threads at the final level. * @requires vm.debug != true & vm.continuations - * @run main/othervm/timeout=300 Skynet100kWithMonitors 50 + * @run main/othervm/timeout=1200 Skynet100kWithMonitors 50 */ /* * @test * @requires vm.debug == true & vm.continuations - * @run main/othervm/timeout=300 Skynet100kWithMonitors 10 + * @run main/othervm/timeout=1200 Skynet100kWithMonitors 10 */ public class Skynet100kWithMonitors { diff --git a/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java b/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java index d10897629c4..fadc5c3446b 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 @@ * @test * @summary Stress test Thread.sleep * @requires vm.debug != true & vm.continuations - * @run main SleepALot 500000 + * @run main/timeout=480 SleepALot 500000 */ /* * @test * @requires vm.debug == true & vm.continuations - * @run main/othervm/timeout=300 SleepALot 200000 + * @run main/othervm/timeout=1200 SleepALot 200000 */ import java.time.Duration; diff --git a/test/jdk/java/lang/annotation/LoaderLeakTest.java b/test/jdk/java/lang/annotation/LoaderLeakTest.java index 762a08f9990..6b31add49a4 100644 --- a/test/jdk/java/lang/annotation/LoaderLeakTest.java +++ b/test/jdk/java/lang/annotation/LoaderLeakTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary annotations cause memory leak * @library /test/lib * @build jdk.test.lib.process.* - * @run testng LoaderLeakTest + * @run testng/timeout=480 LoaderLeakTest */ import jdk.test.lib.Utils; diff --git a/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java index 60ba4af590e..7635851724e 100644 --- a/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java +++ b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,8 @@ import java.util.ArrayList; * @test * @bug 8340812 * @summary Verify that LambdaForm customization via MethodHandle::updateForm is thread safe. - * @run main TestLambdaFormCustomization - * @run main/othervm -Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD=0 TestLambdaFormCustomization + * @run main/timeout=480 TestLambdaFormCustomization + * @run main/othervm/timeout=480 -Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD=0 TestLambdaFormCustomization */ public class TestLambdaFormCustomization { diff --git a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java index bb9efe29e51..7260c04c10a 100644 --- a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java +++ b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8277964 * @summary Test IllegalArgumentException be thrown when an argument is invalid - * @run testng/othervm/timeout=180 IllegalArgumentsTest + * @run testng/othervm/timeout=720 IllegalArgumentsTest */ import java.lang.reflect.Constructor; diff --git a/test/jdk/java/math/BigInteger/LargeValueExceptions.java b/test/jdk/java/math/BigInteger/LargeValueExceptions.java index bba3a23b438..4c85281a5c0 100644 --- a/test/jdk/java/math/BigInteger/LargeValueExceptions.java +++ b/test/jdk/java/math/BigInteger/LargeValueExceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8200698 * @summary Tests that exceptions are thrown for ops which would overflow * @requires (sun.arch.data.model == "64" & os.maxMemory >= 4g) - * @run testng/othervm -Xmx4g LargeValueExceptions + * @run testng/othervm/timeout=480 -Xmx4g LargeValueExceptions */ import java.math.BigInteger; import static java.math.BigInteger.ONE; diff --git a/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java b/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java index c8a1659368a..dff8b38d3c1 100644 --- a/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java +++ b/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @modules java.management java.base/java.io:+open java.base/java.net:+open * java.base/sun.net java.base/sun.nio.ch:+open - * @run main/othervm UnreferencedDatagramSockets - * @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedDatagramSockets + * @run main/othervm/timeout=480 UnreferencedDatagramSockets + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedDatagramSockets * @summary Check that unreferenced datagram sockets are closed */ diff --git a/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java b/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java index 87d62fdd685..13383a397f9 100644 --- a/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java +++ b/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * 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,5 +42,3 @@ public class SetLoopbackModeIPv4 { SetLoopbackMode.main(args); } } - - diff --git a/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java b/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java index 6e318dd77d7..2a87207c961 100644 --- a/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java +++ b/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @modules java.management java.base/java.io:+open java.base/java.net:+open * java.base/sun.net java.base/sun.nio.ch:+open - * @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets - * @run main/othervm UnreferencedMulticastSockets + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets + * @run main/othervm/timeout=480 UnreferencedMulticastSockets * @summary Check that unreferenced multicast sockets are closed */ diff --git a/test/jdk/java/net/ServerSocket/UnreferencedSockets.java b/test/jdk/java/net/ServerSocket/UnreferencedSockets.java index baed6c156d5..61e1bbfc21d 100644 --- a/test/jdk/java/net/ServerSocket/UnreferencedSockets.java +++ b/test/jdk/java/net/ServerSocket/UnreferencedSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +25,8 @@ * @test * @library /test/lib * @modules java.management java.base/java.io:+open java.base/java.net:+open - * @run main/othervm UnreferencedSockets - * @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedSockets + * @run main/othervm/timeout=480 UnreferencedSockets + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedSockets * @summary Check that unreferenced sockets are closed */ diff --git a/test/jdk/java/net/Socket/CloseAvailable.java b/test/jdk/java/net/Socket/CloseAvailable.java index 5ff7e0c03a3..dfaf92d9219 100644 --- a/test/jdk/java/net/Socket/CloseAvailable.java +++ b/test/jdk/java/net/Socket/CloseAvailable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * 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 4091859 8189366 * @library /test/lib * @summary Test Socket.getInputStream().available() - * @run main CloseAvailable - * @run main/othervm -Djava.net.preferIPv4Stack=true CloseAvailable + * @run main/timeout=480 CloseAvailable + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true CloseAvailable */ import java.net.*; diff --git a/test/jdk/java/net/httpclient/AsFileDownloadTest.java b/test/jdk/java/net/httpclient/AsFileDownloadTest.java index 1ec26777696..31d919230a4 100644 --- a/test/jdk/java/net/httpclient/AsFileDownloadTest.java +++ b/test/jdk/java/net/httpclient/AsFileDownloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ import static org.testng.Assert.fail; * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.Platform jdk.test.lib.util.FileUtils * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run testng/othervm AsFileDownloadTest + * @run testng/othervm/timeout=480 AsFileDownloadTest */ public class AsFileDownloadTest { diff --git a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java index c35c62c062a..6d15ba5d3a8 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static org.testng.Assert.*; * @key randomness * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm -Djdk.internal.httpclient.debug=true BufferingSubscriberTest + * @run testng/othervm/timeout=480 -Djdk.internal.httpclient.debug=true BufferingSubscriberTest */ public class BufferingSubscriberTest { diff --git a/test/jdk/java/net/httpclient/CancelledResponse.java b/test/jdk/java/net/httpclient/CancelledResponse.java index f69bf066ba2..44be38317dc 100644 --- a/test/jdk/java/net/httpclient/CancelledResponse.java +++ b/test/jdk/java/net/httpclient/CancelledResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +59,8 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; * @modules java.net.http/jdk.internal.net.http.common * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer ReferenceTracker - * @run main/othervm CancelledResponse - * @run main/othervm CancelledResponse SSL + * @run main/othervm/timeout=480 CancelledResponse + * @run main/othervm/timeout=480 CancelledResponse SSL */ /** diff --git a/test/jdk/java/net/httpclient/HttpSlowServerTest.java b/test/jdk/java/net/httpclient/HttpSlowServerTest.java index 85db9bba563..a71eaf746ad 100644 --- a/test/jdk/java/net/httpclient/HttpSlowServerTest.java +++ b/test/jdk/java/net/httpclient/HttpSlowServerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static java.net.http.HttpClient.Version.HTTP_2; * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer HttpSlowServerTest * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run main/othervm -Dtest.requiresHost=true + * @run main/othervm/timeout=480 -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.debug=false * HttpSlowServerTest diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java index 493c2c3a504..c196ef76466 100644 --- a/test/jdk/java/net/httpclient/ManyRequests.java +++ b/test/jdk/java/net/httpclient/ManyRequests.java @@ -33,10 +33,10 @@ * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ManyRequests - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ManyRequests - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests * @summary Send a large number of requests asynchronously */ // * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests diff --git a/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java b/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java index d1cffff72cf..beed8f86fa6 100644 --- a/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java +++ b/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules java.net.http/jdk.internal.net.http.common * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm ResponseBodyBeforeError + * @run testng/othervm/timeout=480 ResponseBodyBeforeError */ import java.io.Closeable; diff --git a/test/jdk/java/net/httpclient/ResponsePublisher.java b/test/jdk/java/net/httpclient/ResponsePublisher.java index e8d76430946..3d6cf601b2f 100644 --- a/test/jdk/java/net/httpclient/ResponsePublisher.java +++ b/test/jdk/java/net/httpclient/ResponsePublisher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * immediately with a Publisher> * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run testng/othervm ResponsePublisher + * @run testng/othervm/timeout=480 ResponsePublisher */ import com.sun.net.httpserver.HttpExchange; diff --git a/test/jdk/java/net/httpclient/SpecialHeadersTest.java b/test/jdk/java/net/httpclient/SpecialHeadersTest.java index 37cb47a6872..d3e1f37b592 100644 --- a/test/jdk/java/net/httpclient/SpecialHeadersTest.java +++ b/test/jdk/java/net/httpclient/SpecialHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +31,10 @@ * jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.net.SimpleSSLContext * @requires (vm.compMode != "Xcomp") - * @run testng/othervm + * @run testng/othervm/timeout=480 * -Djdk.httpclient.HttpClient.log=requests,headers,errors * SpecialHeadersTest - * @run testng/othervm -Djdk.httpclient.allowRestrictedHeaders=Host + * @run testng/othervm/timeout=480 -Djdk.httpclient.allowRestrictedHeaders=Host * -Djdk.httpclient.HttpClient.log=requests,headers,errors * SpecialHeadersTest */ diff --git a/test/jdk/java/net/httpclient/SplitResponse.java b/test/jdk/java/net/httpclient/SplitResponse.java index 48f958047b7..ad04e8a1627 100644 --- a/test/jdk/java/net/httpclient/SplitResponse.java +++ b/test/jdk/java/net/httpclient/SplitResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static java.net.http.HttpResponse.BodyHandlers.ofString; * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:CLOSE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseAsync.java b/test/jdk/java/net/httpclient/SplitResponseAsync.java index caed3dc8d67..dfb3843561a 100644 --- a/test/jdk/java/net/httpclient/SplitResponseAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:CLOSE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java b/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java index f805f26a1e4..a8477e8b289 100644 --- a/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java +++ b/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:KEEP_ALIVE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java b/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java index c8d034444b6..7d46989f976 100644 --- a/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:KEEP_ALIVE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSL.java b/test/jdk/java/net/httpclient/SplitResponseSSL.java index ba030d74efa..31c3f4f8f61 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSL.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:CLOSE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java b/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java index e78b6703d59..e54a0314d2d 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:CLOSE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java index 9892370cdef..a707c6c3921 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:KEEP_ALIVE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java index 96dbb5f5bc0..740baabd714 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:KEEP_ALIVE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java b/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java index aea81fb0a0b..a0130de5a67 100644 --- a/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,5 +24,5 @@ /* * @test * @modules java.net.http/jdk.internal.net.http - * @run testng java.net.http/jdk.internal.net.http.FlowTest + * @run testng/timeout=480 java.net.http/jdk.internal.net.http.FlowTest */ diff --git a/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java b/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java index 8f8f816cad6..331da97845a 100644 --- a/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java +++ b/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 6834246 6842687 * @summary Stress test connections through the loopback interface * @run main StressLoopback - * @run main/othervm -Djdk.net.useFastTcpLoopback StressLoopback + * @run main/othervm/timeout=480 -Djdk.net.useFastTcpLoopback StressLoopback * @key randomness */ diff --git a/test/jdk/java/nio/channels/Channels/TransferTo.java b/test/jdk/java/nio/channels/Channels/TransferTo.java index bc0dc01fdb0..b02bf7b3649 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static org.testng.Assert.assertThrows; * @test * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm/timeout=180 TransferTo + * @run testng/othervm/timeout=720 TransferTo * @bug 8265891 * @summary Tests whether sun.nio.ChannelInputStream.transferTo conforms to the * InputStream.transferTo specification diff --git a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java index 4829cc63f70..f57d6cca963 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +36,7 @@ import org.testng.annotations.Test; * @test * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm/timeout=180 TransferTo_2GB_transferFrom + * @run testng/othervm/timeout=720 TransferTo_2GB_transferFrom * @bug 8278268 * @summary Tests if ChannelInputStream.transferFrom correctly * transfers 2GB+ using FileChannel.transferFrom(ReadableByteChannel). diff --git a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java index 34b4e504b05..fdd3bddb126 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import org.testng.annotations.Test; * @test * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm/timeout=180 TransferTo_2GB_transferTo + * @run testng/othervm/timeout=720 TransferTo_2GB_transferTo * @bug 8265891 * @summary Tests if ChannelInputStream.transferTo correctly * transfers 2GB+ using FileChannel.transferTo(WritableByteChannel). diff --git a/test/jdk/java/nio/channels/FileChannel/CleanerTest.java b/test/jdk/java/nio/channels/FileChannel/CleanerTest.java index c999684a56d..48b00deabb9 100644 --- a/test/jdk/java/nio/channels/FileChannel/CleanerTest.java +++ b/test/jdk/java/nio/channels/FileChannel/CleanerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.util.FileUtils CleanerTest * @modules java.management java.base/sun.nio.ch:+open - * @run main/othervm CleanerTest + * @run main/othervm/timeout=480 CleanerTest */ import com.sun.management.UnixOperatingSystemMXBean; diff --git a/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java b/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java index c42db8f485f..2ec77d97958 100644 --- a/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java +++ b/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8198928 * @library /test/lib * @build jdk.test.lib.Utils - * @run main CloseDuringConnect + * @run main/timeout=480 CloseDuringConnect * @summary Attempt to cause a deadlock by closing a SocketChannel in one thread * where another thread is closing the channel after a connect fail */ diff --git a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java index c7eed1f27a0..cbfe4c9b7fb 100644 --- a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java +++ b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * connection cannot be established * @requires vm.flagless * @build OpenLeak - * @run junit/othervm OpenLeak + * @run junit/othervm/timeout=480 OpenLeak */ import java.io.IOException; diff --git a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java index 96478b2b20f..33a7b5ef3c4 100644 --- a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java +++ b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8245194 - * @run testng/othervm IOExchanges + * @run testng/othervm/timeout=480 IOExchanges */ import java.io.IOException; diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index 1cdd090d1be..f04bece07b6 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -26,22 +26,22 @@ * @bug 8284161 * @summary Test virtual threads doing blocking I/O on NIO channels * @library /test/lib - * @run junit BlockingChannelOps + * @run junit/timeout=480 BlockingChannelOps */ /* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib - * @run junit/othervm -Djdk.pollerMode=1 BlockingChannelOps - * @run junit/othervm -Djdk.pollerMode=2 BlockingChannelOps + * @run junit/othervm/timeout=480 -Djdk.pollerMode=1 BlockingChannelOps + * @run junit/othervm/timeout=480 -Djdk.pollerMode=2 BlockingChannelOps */ /* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations BlockingChannelOps + * @run junit/othervm/timeout=480 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations BlockingChannelOps */ import java.io.Closeable; diff --git a/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java b/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java index 2137cfb3721..baa20ff2b9c 100644 --- a/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java +++ b/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp * @build TestLibrary Test TestImpl RegistryVM RegistryRunner - * @run main/othervm/timeout=360 DGCDeadLock + * @run main/othervm/timeout=1440 DGCDeadLock */ /* This test attempts to cause a deadlock between the rmi leaseChecker @@ -56,8 +56,7 @@ import java.io.*; public class DGCDeadLock implements Runnable { final static public int HOLD_TARGET_TIME = 25000; - public static final double TEST_FAIL_TIME = - (HOLD_TARGET_TIME + 30000) * TestLibrary.getTimeoutFactor(); + public static final double TEST_FAIL_TIME = (HOLD_TARGET_TIME + 30000) * Math.max(TestLibrary.getTimeoutFactor(), 4); public static volatile boolean finished = false; static final DGCDeadLock test = new DGCDeadLock(); static volatile int registryPort = -1; diff --git a/test/jdk/java/security/SignedObject/Chain.java b/test/jdk/java/security/SignedObject/Chain.java index 883ac13890d..c4b83d1ec5b 100644 --- a/test/jdk/java/security/SignedObject/Chain.java +++ b/test/jdk/java/security/SignedObject/Chain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static jdk.test.lib.SigTestUtil.SignatureType; * @summary Verify a chain of signed objects * @library /test/lib * @build jdk.test.lib.SigTestUtil - * @run main Chain + * @run main/timeout=480 Chain */ public class Chain { diff --git a/test/jdk/java/text/Format/DateFormat/DateFormatTest.java b/test/jdk/java/text/Format/DateFormat/DateFormatTest.java index f0b30fa1065..06cb4fe7df4 100644 --- a/test/jdk/java/text/Format/DateFormat/DateFormatTest.java +++ b/test/jdk/java/text/Format/DateFormat/DateFormatTest.java @@ -27,7 +27,7 @@ * 8190748 8216969 8174269 8347841 8347955 * @summary test DateFormat and SimpleDateFormat. * @modules jdk.localedata - * @run junit DateFormatTest + * @run junit/timeout=480 DateFormatTest */ import java.time.ZoneId; diff --git a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java index e517d5570d0..f17d9194c14 100644 --- a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java +++ b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, Red Hat, Inc. All rights reserved. - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static org.testng.Assert.assertThrows; * @summary White box tests for HashMap-related internals around table sizing * @comment skip running this test on 32 bit VM * @requires vm.bits == "64" - * @run testng/othervm -Xmx2g WhiteBoxResizeTest + * @run testng/othervm/timeout=960 -Xmx2g WhiteBoxResizeTest */ public class WhiteBoxResizeTest { diff --git a/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java b/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java index bc1df961a57..46bee98a810 100644 --- a/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java +++ b/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.base/sun.util.resources * @build com.foobar.Utils * com.bar.* - * @run main/othervm -Djava.locale.providers=CLDR,SPI CurrencyNameProviderTest + * @run main/othervm/timeout=480 -Djava.locale.providers=CLDR,SPI CurrencyNameProviderTest */ import java.text.DecimalFormat; diff --git a/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java b/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java index 9d44dd79c02..fcec85a945b 100644 --- a/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java +++ b/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java @@ -31,7 +31,7 @@ * java.base/sun.util.resources * @build com.foobar.Utils * com.bar.* - * @run junit/othervm -Djava.locale.providers=CLDR,SPI LocaleNameProviderTest + * @run junit/othervm/timeout=960 -Djava.locale.providers=CLDR,SPI LocaleNameProviderTest */ import java.util.ArrayList; diff --git a/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java b/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java index 5ca755fc362..43490a711b2 100644 --- a/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java +++ b/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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 6602600 - * @run main/othervm -Xmx64m BasicCancelTest + * @run main/othervm/timeout=480 -Xmx64m BasicCancelTest * @summary Check effectiveness of RemoveOnCancelPolicy */ diff --git a/test/jdk/java/util/logging/FileHandlerPath.java b/test/jdk/java/util/logging/FileHandlerPath.java index 85ec52a0619..a4d23dbf458 100644 --- a/test/jdk/java/util/logging/FileHandlerPath.java +++ b/test/jdk/java/util/logging/FileHandlerPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.logging.LogManager; * @bug 8059269 * @summary tests that using a simple (non composite) pattern does not lead * to NPE when the lock file already exists. - * @run main/othervm FileHandlerPath + * @run main/othervm/timeout=480 FileHandlerPath * @author danielfuchs * @key randomness */ diff --git a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java index f24bb2e22ec..64fd22362ca 100644 --- a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java +++ b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.util.function.Function; import java.util.logging.FileHandler; import java.util.logging.LogManager; import java.util.logging.Logger; +import jdk.test.lib.Utils; /** * @test @@ -49,6 +50,7 @@ import java.util.logging.Logger; * Test a complex reconfiguration where a logger with handlers * suddenly appears in the hierarchy between a child logger and the * root logger. + * @library /test/lib * @run main/othervm HandlersOnComplexResetUpdate * @author danielfuchs */ @@ -60,13 +62,8 @@ public class HandlersOnComplexResetUpdate { test(properties); } - public static final double TIMEOUT_FACTOR; - static { - String toFactor = System.getProperty("test.timeout.factor", "1.0"); - TIMEOUT_FACTOR = Double.parseDouble(toFactor); - } static int adjustCount(int count) { - return Math.min(count, (int) Math.ceil(TIMEOUT_FACTOR * count)); + return Math.min(count, (int) Math.ceil(Utils.TIMEOUT_FACTOR * count)); } private static final String PREFIX = diff --git a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java index 8735c34aa98..146cfea1af8 100644 --- a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java +++ b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.util.function.Function; import java.util.logging.FileHandler; import java.util.logging.LogManager; import java.util.logging.Logger; +import jdk.test.lib.Utils; /** * @test @@ -49,6 +50,7 @@ import java.util.logging.Logger; * Test a complex reconfiguration where a logger with handlers * suddenly appears in the hierarchy between a child logger and the * root logger. + * @library /test/lib * @run main/othervm HandlersOnComplexUpdate * @author danielfuchs */ @@ -60,13 +62,8 @@ public class HandlersOnComplexUpdate { test(properties); } - public static final double TIMEOUT_FACTOR; - static { - String toFactor = System.getProperty("test.timeout.factor", "1.0"); - TIMEOUT_FACTOR = Double.parseDouble(toFactor); - } static int adjustCount(int count) { - return Math.min(count, (int) Math.ceil(TIMEOUT_FACTOR * count)); + return Math.min(count, (int) Math.ceil(Utils.TIMEOUT_FACTOR * count)); } private static final String PREFIX = diff --git a/test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties b/test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties new file mode 100644 index 00000000000..64710ba44a1 --- /dev/null +++ b/test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties @@ -0,0 +1 @@ +timeout.default.seconds=480 diff --git a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties new file mode 100644 index 00000000000..64710ba44a1 --- /dev/null +++ b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties @@ -0,0 +1 @@ +timeout.default.seconds=480 diff --git a/test/jdk/java/util/zip/DeInflate.java b/test/jdk/java/util/zip/DeInflate.java index 226d4ed4ae3..83ed417fed1 100644 --- a/test/jdk/java/util/zip/DeInflate.java +++ b/test/jdk/java/util/zip/DeInflate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +24,9 @@ /* * @test * @bug 7110149 8184306 6341887 8357145 - * @summary Test basic deflater & inflater functionality + * @summary Test basic deflater and inflater functionality * @key randomness + * @run main/timeout=480 DeInflate */ import java.io.*; diff --git a/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java b/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java index d8d474ae8d4..4e271912345 100644 --- a/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java +++ b/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8243254 * @summary Tests a simple set of operations on Zip files in various encodings * focusing on ensuring metadata is properly encoded and read. - * @run testng TestZipFileEncodings + * @run testng/timeout=480 TestZipFileEncodings */ import org.testng.annotations.AfterClass; import org.testng.annotations.DataProvider; diff --git a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java index 8db1dfdeac8..946951dfc98 100644 --- a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java +++ b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 Check if weak cipher suites are disabled * @library /javax/net/ssl/templates * @modules jdk.crypto.ec - * @run main/othervm DisabledAlgorithms default - * @run main/othervm DisabledAlgorithms empty + * @run main/othervm/timeout=480 DisabledAlgorithms default + * @run main/othervm/timeout=480 DisabledAlgorithms empty */ import java.io.BufferedInputStream; diff --git a/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java b/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java index 28ed114b807..07d24115218 100644 --- a/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java +++ b/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 6868611 8198004 * @summary FileSystemView throws NullPointerException * @author Pavel Porvatov - * @run main bug6868611 + * @run main/timeout=480 bug6868611 */ import javax.swing.*; diff --git a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java index 0c23ee23b5b..8b4d9ab8e69 100644 --- a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java +++ b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import javax.swing.JFileChooser; * @bug 8323670 8307091 8240690 * @requires os.family == "mac" | os.family == "linux" * @summary Verifies thread-safety of BasicDirectoryModel (JFileChooser) - * @run main/othervm -Djava.awt.headless=true ConcurrentModification + * @run main/othervm/timeout=480 -Djava.awt.headless=true ConcurrentModification */ public final class ConcurrentModification extends ThreadGroup { /** Initial number of files. */ diff --git a/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java b/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java index 0de35fbdaa9..363cb94d924 100644 --- a/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java +++ b/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java @@ -30,16 +30,18 @@ import javax.swing.SwingUtilities; import javax.swing.text.Document; import javax.swing.text.html.HTMLEditorKit; +import jdk.test.lib.Utils; + import static java.util.concurrent.TimeUnit.MILLISECONDS; /* @test @bug 8078268 @summary javax.swing.text.html.parser.Parser parseScript incorrectly optimized + @library /test/lib @run main bug8078268 */ public class bug8078268 { - private static final float tf = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - private static final long TIMEOUT = 10_000 * (long)tf; + private static final long TIMEOUT = (long) (10_000 * Utils.TIMEOUT_FACTOR); private static final String FILENAME = "slowparse.html"; diff --git a/test/jdk/javax/xml/crypto/dsig/GenerationTests.java b/test/jdk/javax/xml/crypto/dsig/GenerationTests.java index ac24ceb476c..0ecc40a8819 100644 --- a/test/jdk/javax/xml/crypto/dsig/GenerationTests.java +++ b/test/jdk/javax/xml/crypto/dsig/GenerationTests.java @@ -34,7 +34,7 @@ * @build jdk.test.lib.Asserts * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java * X509KeySelector.java GenerationTests.java - * @run main/othervm/timeout=300 -Dsun.net.httpserver.nodelay=true GenerationTests + * @run main/othervm/timeout=1200 -Dsun.net.httpserver.nodelay=true GenerationTests * @author Sean Mullan */ diff --git a/test/jdk/jdk/incubator/vector/AddTest.java b/test/jdk/jdk/incubator/vector/AddTest.java index bd11f0092be..8d0d7080c49 100644 --- a/test/jdk/jdk/incubator/vector/AddTest.java +++ b/test/jdk/jdk/incubator/vector/AddTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @modules jdk.incubator.vector * @requires vm.compiler2.enabled + * @run main/timeout=480 AddTest */ import jdk.incubator.vector.FloatVector; diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index 0587d5a6bfb..53f11f22d79 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -44,7 +44,7 @@ import jtreg.SkippedException; * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsMemoryTester - * @run main TestDockerMemoryMetricsSubgroup + * @run main/timeout=480 TestDockerMemoryMetricsSubgroup */ public class TestDockerMemoryMetricsSubgroup { diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index b9d031f0309..dc70fe32b16 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2020, 2022, Tencent. All rights reserved. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @requires !vm.asan * @library /test/lib * @build GetFreeSwapSpaceSize - * @run driver TestGetFreeSwapSpaceSize + * @run driver/timeout=480 TestGetFreeSwapSpaceSize */ import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index 31e90e8802a..e4decb7f903 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,7 +34,7 @@ * @library /test/lib * @modules java.base/jdk.internal.platform * @build LimitUpdateChecker - * @run driver TestLimitsUpdating + * @run driver/timeout=480 TestLimitsUpdating */ import java.io.File; diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 6b19bb475f1..033562b3951 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,7 +31,7 @@ * @requires !vm.asan * @library /test/lib * @build TestPidsLimit - * @run driver TestPidsLimit + * @run driver/timeout=480 TestPidsLimit */ import java.util.ArrayList; import java.util.List; diff --git a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java index 530bcb54f34..254583bf18b 100644 --- a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java +++ b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java @@ -153,7 +153,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xbatch -XX:-TieredCompilation * -XX:CompileCommand=dontinline,*::*dontinline* * -XX:CompileCommand=dontinline,*::*dontjit* @@ -173,7 +173,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xbatch -XX:-TieredCompilation * -XX:CompileCommand=dontinline,*::*dontinline* * -XX:CompileCommand=dontinline,*::*dontjit* @@ -193,7 +193,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xbatch -XX:-TieredCompilation * -XX:CompileCommand=dontinline,*::*dontinline* * -XX:CompileCommand=dontinline,*::*dontjit* diff --git a/test/jdk/jdk/internal/vm/Continuation/Fuzz.java b/test/jdk/jdk/internal/vm/Continuation/Fuzz.java index 5f4f8c85f61..8d522cc83e1 100644 --- a/test/jdk/jdk/internal/vm/Continuation/Fuzz.java +++ b/test/jdk/jdk/internal/vm/Continuation/Fuzz.java @@ -34,8 +34,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * Fuzz + * @run main/othervm/timeout=1200 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * Fuzz */ /* @@ -51,9 +51,9 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * -XX:+PreserveFramePointer - * Fuzz + * @run main/othervm/timeout=1200 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+PreserveFramePointer + * Fuzz */ import jdk.internal.vm.Continuation; @@ -84,8 +84,7 @@ public class Fuzz implements Runnable { static final boolean RANDOM = true; static final boolean VERBOSE = false; - static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - static int COMPILATION_TIMEOUT = (int)(5_000 * timeoutFactor); // ms + static int COMPILATION_TIMEOUT = (int)(5_000 * Utils.TIMEOUT_FACTOR); // ms static final Path TEST_DIR = Path.of(System.getProperty("test.src", ".")); diff --git a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java index c7e6c6e5922..512f6b39ef9 100644 --- a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java +++ b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java @@ -38,7 +38,7 @@ import jdk.jfr.consumer.RecordingStream; * @requires vm.flagless * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm -Xlog:jfr+streaming+system=trace jdk.jfr.api.consumer.recordingstream.TestClose + * @run main/othervm/timeout=480 -Xlog:jfr+streaming+system=trace jdk.jfr.api.consumer.recordingstream.TestClose */ public class TestClose { diff --git a/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java b/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java index b7c3a67ae68..43abc9cefff 100644 --- a/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java +++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.jfr.TestClassLoader; * @requires vm.hasJFR * @modules jdk.jfr/jdk.jfr.events * @library /test/lib /test/jdk - * @run main/othervm -Xlog:jfr=warning jdk.jfr.api.metadata.annotations.TestStackFilter + * @run main/othervm/timeout=480 -Xlog:jfr=warning jdk.jfr.api.metadata.annotations.TestStackFilter */ public class TestStackFilter { private static class Quux { diff --git a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java index a86229c65e3..fd09db01482 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java @@ -44,7 +44,7 @@ import jdk.test.lib.process.ProcessTools; * @requires vm.flagless * @requires vm.hasJFR * @library /test/lib -* @run main/othervm jdk.jfr.event.oldobject.TestEmergencyDumpAtOOM +* @run main/othervm/timeout=480 jdk.jfr.event.oldobject.TestEmergencyDumpAtOOM */ public class TestEmergencyDumpAtOOM { diff --git a/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java index 60f85e6ba72..56f48a810c3 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java @@ -46,7 +46,7 @@ import jdk.test.lib.jfr.Events; * @comment Marked as flagless until JDK-8344015 is fixed * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal.test - * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestObjectDescription + * @run main/othervm/timeout=960 -XX:TLABSize=2k jdk.jfr.event.oldobject.TestObjectDescription */ public class TestObjectDescription { diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java index 133df36684c..976d08f1250 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java @@ -36,7 +36,7 @@ import jdk.test.lib.jfr.EventNames; * @requires vm.hasJFR & os.family == "linux" * @library /test/lib * @modules jdk.jfr/jdk.jfr.internal - * @run main jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings + * @run main/timeout=480 jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings */ public class TestCPUTimeSampleMultipleRecordings { diff --git a/test/jdk/jdk/jfr/jvm/TestModularImage.java b/test/jdk/jdk/jfr/jvm/TestModularImage.java index fe49b460f18..41e8dc0fa5b 100644 --- a/test/jdk/jdk/jfr/jvm/TestModularImage.java +++ b/test/jdk/jdk/jfr/jvm/TestModularImage.java @@ -49,7 +49,7 @@ import jdk.test.lib.process.ProcessTools; * module java.base to add java.lang.JTRegModuleHelper. If then a * jlink run is attempted in-process - using the ToolProvider API - * on a JEP 493 enabled JDK, the test fails. - * @run main/othervm jdk.jfr.jvm.TestModularImage + * @run main/othervm/timeout=480 jdk.jfr.jvm.TestModularImage */ public class TestModularImage { private static final String STARTED_RECORDING = "Started recording"; diff --git a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java index b4291645007..2dc2b2b4587 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -35,6 +35,7 @@ import java.util.concurrent.Semaphore; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; diff --git a/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java b/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java index ef73a15256a..986fc338c71 100644 --- a/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java +++ b/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,11 +44,11 @@ import jdk.test.lib.RandomFactory; * @modules java.management * @library /test/lib * @build TestMaxCachedBufferSize - * @run main/othervm/timeout=150 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=0 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=2000 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=100000 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=10000000 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=0 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=2000 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=100000 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=10000000 TestMaxCachedBufferSize * @summary Test the implementation of the jdk.nio.maxCachedBufferSize property * (use -Dseed=X to set PRNG seed) * @key randomness diff --git a/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java b/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java index c61e85d6698..a93dac16ab6 100644 --- a/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java +++ b/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java @@ -45,8 +45,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @modules java.base/jdk.internal.access * java.base/sun.nio.cs * @build TestEncoderReplaceLatin1 - * @run junit/timeout=10 TestEncoderReplaceUTF16 - * @run junit/timeout=10/othervm -XX:-CompactStrings TestEncoderReplaceUTF16 + * @run junit/timeout=40 TestEncoderReplaceUTF16 + * @run junit/timeout=40/othervm -XX:-CompactStrings TestEncoderReplaceUTF16 */ class TestEncoderReplaceUTF16 { diff --git a/test/jdk/sun/security/ec/ed/EdDSATest.java b/test/jdk/sun/security/ec/ed/EdDSATest.java index c154bca4252..bebb9d2359e 100644 --- a/test/jdk/sun/security/ec/ed/EdDSATest.java +++ b/test/jdk/sun/security/ec/ed/EdDSATest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.HexFormat; * @summary Test Signature with variation of serialized EDDSA Keys. * @library /test/lib * @build jdk.test.lib.Convert - * @run main EdDSATest + * @run main/timeout=480 EdDSATest */ public class EdDSATest { diff --git a/test/jdk/sun/security/krb5/config/IncludeRandom.java b/test/jdk/sun/security/krb5/config/IncludeRandom.java index fe05917fd4c..5ee0e485d82 100644 --- a/test/jdk/sun/security/krb5/config/IncludeRandom.java +++ b/test/jdk/sun/security/krb5/config/IncludeRandom.java @@ -27,7 +27,7 @@ * @summary Support "include" anywhere * @modules java.security.jgss/sun.security.krb5 * @library /test/lib - * @run main/othervm IncludeRandom + * @run main/othervm/timeout=480 IncludeRandom */ import jdk.test.lib.Asserts; import jdk.test.lib.security.SeededSecureRandom; diff --git a/test/jdk/sun/security/krb5/name/Constructors.java b/test/jdk/sun/security/krb5/name/Constructors.java index 733a9e421f8..d2b04726bb1 100644 --- a/test/jdk/sun/security/krb5/name/Constructors.java +++ b/test/jdk/sun/security/krb5/name/Constructors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 6966259 * @summary Make PrincipalName and Realm immutable * @modules java.security.jgss/sun.security.krb5 - * @run main/othervm Constructors + * @run main/othervm/timeout=480 Constructors */ import java.util.Arrays; diff --git a/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java b/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java index aaaa8373f44..5cf0491cd7d 100644 --- a/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java +++ b/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java @@ -43,7 +43,7 @@ import java.util.List; * @bug 8328119 * @summary test HKDF key derivation in SunPKCS11 * @library /test/lib .. - * @run main/othervm/timeout=30 TestHKDF + * @run main/othervm/timeout=120 TestHKDF */ public final class TestHKDF extends PKCS11Test { diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java index a359ff7a13c..cee8f235f9f 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib .. * @modules java.base/sun.security.util * jdk.crypto.cryptoki - * @run main TestDefaultSize + * @run main/timeout=480 TestDefaultSize */ import java.security.InvalidParameterException; diff --git a/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java b/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java index 395fe416858..0e8cb36659f 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java @@ -42,7 +42,7 @@ import javax.crypto.spec.SecretKeySpec; * applied to PKCS #12 keystores * @library /test/lib .. * @modules java.base/sun.security.util - * @run main/othervm/timeout=30 ImportKeyToP12 + * @run main/othervm/timeout=120 ImportKeyToP12 */ public final class ImportKeyToP12 extends PKCS11Test { diff --git a/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java b/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java index dc263cfdb2b..948270d10d9 100644 --- a/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java +++ b/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java @@ -31,7 +31,7 @@ import java.security.Provider; * @test * @bug 8328556 * @library /test/lib .. - * @run main/othervm/timeout=30 -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt TestLargeSecretKeys + * @run main/othervm/timeout=120 -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt TestLargeSecretKeys */ public final class TestLargeSecretKeys extends PKCS11Test { diff --git a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java index facdbc8a187..4974ba06649 100644 --- a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java +++ b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java @@ -36,7 +36,7 @@ * @modules java.base/sun.security.pkcs * java.base/sun.security.util * @library /test/lib /sun/security/pkcs11/ - * @run main/othervm KeytoolOpensslInteropTest true + * @run main/othervm/timeout=480 KeytoolOpensslInteropTest true */ /* @@ -48,7 +48,7 @@ * @modules java.base/sun.security.pkcs * java.base/sun.security.util * @library /test/lib /sun/security/pkcs11/ - * @run main/othervm KeytoolOpensslInteropTest false + * @run main/othervm/timeout=480 KeytoolOpensslInteropTest false */ import jdk.test.lib.Asserts; diff --git a/test/jdk/sun/security/provider/acvp/Launcher.java b/test/jdk/sun/security/provider/acvp/Launcher.java index c07b7929d89..f420b61d6f4 100644 --- a/test/jdk/sun/security/provider/acvp/Launcher.java +++ b/test/jdk/sun/security/provider/acvp/Launcher.java @@ -37,7 +37,7 @@ import java.util.zip.ZipFile; * @bug 8342442 8345057 * @library /test/lib * @modules java.base/sun.security.provider - * @run main Launcher + * @run main/timeout=480 Launcher */ /* @@ -46,7 +46,7 @@ import java.util.zip.ZipFile; * @bug 8342442 8345057 * @library /test/lib * @modules java.base/sun.security.provider - * @run main/othervm -Xcomp Launcher + * @run main/othervm/timeout=480 -Xcomp Launcher */ /// This test runs on `internalProjection.json`-style files generated by NIST's diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java index 3f69ae2d120..75a790bfd27 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @bug 8184328 8253368 8260923 * @summary JDK8u131-b34-socketRead0 hang at SSL read + * @library /test/lib * @run main/othervm SSLSocketCloseHang TLSv1.2 * @run main/othervm SSLSocketCloseHang TLSv1.2 shutdownInput * @run main/othervm SSLSocketCloseHang TLSv1.2 shutdownOutput @@ -39,6 +40,7 @@ import java.net.*; import java.util.*; import java.security.*; import javax.net.ssl.*; +import jdk.test.lib.Utils; public class SSLSocketCloseHang { /* @@ -137,8 +139,7 @@ public class SSLSocketCloseHang { System.out.println("server ready"); Socket baseSocket = new Socket("localhost", serverPort); - float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - baseSocket.setSoTimeout((int)(1000 * timeoutFactor)); + baseSocket.setSoTimeout((int)(1000 * Utils.TIMEOUT_FACTOR)); SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault(); diff --git a/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java b/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java index 81e16b925fc..a6963e314f3 100644 --- a/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java +++ b/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java @@ -62,10 +62,10 @@ import sun.security.x509.X500Name; * @modules java.base/sun.security.x509 * java.base/sun.security.util * @library /test/lib - * @run main/othervm CertChecking false SunX509 - * @run main/othervm CertChecking true SunX509 - * @run main/othervm CertChecking false PKIX - * @run main/othervm CertChecking true PKIX + * @run main/othervm/timeout=480 CertChecking false SunX509 + * @run main/othervm/timeout=480 CertChecking true SunX509 + * @run main/othervm/timeout=480 CertChecking false PKIX + * @run main/othervm/timeout=480 CertChecking true PKIX */ /* diff --git a/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java b/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java index e81a25712a6..ef440cb3358 100644 --- a/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java +++ b/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java @@ -26,7 +26,7 @@ * @bug 6802846 8172529 8227758 8260960 * @summary jarsigner needs enhanced cert validation(options) * @library /test/lib - * @run main/timeout=240 ConciseJarsigner + * @run main/timeout=960 ConciseJarsigner */ import jdk.test.lib.Asserts; diff --git a/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java b/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java index 4c201a6baf3..dbc0ec1d203 100644 --- a/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java +++ b/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; * @test * @bug 8217375 * @library /test/lib - * @run testng InsufficientSectionDelimiter + * @run testng/timeout=480 InsufficientSectionDelimiter * @summary Checks some cases signing a jar the manifest of which has no or * only one line break at the end and no proper delimiting blank line does not * result in an invalid signed jar without jarsigner noticing and failing. diff --git a/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java b/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java index 65fb1374bdc..46a787f7798 100644 --- a/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java +++ b/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +39,8 @@ import jdk.test.lib.process.OutputAnalyzer; * key sizes, with and without entries in jdk.jar.disabledAlgorithms, * jdk.certpath.disabledAlgorithms * @library /test/lib - * @run main/othervm RestrictedAlgo RESTRICT - * @run main/othervm RestrictedAlgo NO_RESTRICT + * @run main/othervm/timeout=480 RestrictedAlgo RESTRICT + * @run main/othervm/timeout=480 RestrictedAlgo NO_RESTRICT */ public class RestrictedAlgo { diff --git a/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java b/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java index 4464314bf28..d17b2743857 100644 --- a/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java +++ b/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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 static java.nio.charset.StandardCharsets.UTF_8; * @bug 8217375 8267319 * @library /test/lib * @modules jdk.jartool/jdk.security.jarsigner - * @run testng SectionNameContinuedVsLineBreak + * @run testng/timeout=480 SectionNameContinuedVsLineBreak * @summary Checks some specific line break character sequences in section name * continuation line breaks. */ diff --git a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java index 1c81543e435..889ff3208e4 100644 --- a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java +++ b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java @@ -75,7 +75,7 @@ import sun.security.timestamp.TimestampToken; * jdk.test.lib.Platform * jdk.test.lib.process.* * @compile -XDignore.symbol.file TimestampCheck.java - * @run main/timeout=600 TimestampCheck + * @run main/timeout=2400 TimestampCheck */ public class TimestampCheck { diff --git a/test/jdk/sun/security/tools/keytool/GenerateAll.java b/test/jdk/sun/security/tools/keytool/GenerateAll.java index 5435372cdcf..e9a653eabe9 100644 --- a/test/jdk/sun/security/tools/keytool/GenerateAll.java +++ b/test/jdk/sun/security/tools/keytool/GenerateAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary keytool and jarsigner for all algorithms * @library /test/lib * @modules java.base/sun.security.util - * @run testng/timeout=300 GenerateAll + * @run testng/timeout=1200 GenerateAll */ import jdk.test.lib.SecurityTools; diff --git a/test/jdk/sun/security/tools/keytool/ReadJar.java b/test/jdk/sun/security/tools/keytool/ReadJar.java index 97c65e1fb3b..00f6c7b3f8c 100644 --- a/test/jdk/sun/security/tools/keytool/ReadJar.java +++ b/test/jdk/sun/security/tools/keytool/ReadJar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.test.lib.JDKToolLauncher * jdk.test.lib.Platform * jdk.test.lib.process.* - * @run main ReadJar + * @run main/timeout=480 ReadJar */ import java.nio.file.Files; diff --git a/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java b/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java index c90b3f37eaa..5c0694887fd 100644 --- a/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java +++ b/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build java.base/sun.security.util.FilePaths * @modules java.base/sun.security.util * java.base/jdk.internal.misc - * @run main TrustedCert + * @run main/timeout=480 TrustedCert */ import jdk.test.lib.SecurityTools; diff --git a/test/jdk/sun/tools/jcmd/TestJcmdSanity.java b/test/jdk/sun/tools/jcmd/TestJcmdSanity.java index 017392565dd..92f73597ce6 100644 --- a/test/jdk/sun/tools/jcmd/TestJcmdSanity.java +++ b/test/jdk/sun/tools/jcmd/TestJcmdSanity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.lib.Utils; * * @library /test/lib * - * @run main/othervm -XX:+UsePerfData TestJcmdSanity + * @run main/othervm/timeout=480 -XX:+UsePerfData TestJcmdSanity */ public class TestJcmdSanity { diff --git a/test/jdk/sun/util/resources/TimeZone/Bug8139107.java b/test/jdk/sun/util/resources/TimeZone/Bug8139107.java index 1320d228793..3a65569ad98 100644 --- a/test/jdk/sun/util/resources/TimeZone/Bug8139107.java +++ b/test/jdk/sun/util/resources/TimeZone/Bug8139107.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test that date parsing with DateTimeFormatter pattern * that contains timezone field doesn't trigger NPE. All supported * locales are tested. - * @run testng Bug8139107 + * @run testng/timeout=480 Bug8139107 */ import java.time.format.DateTimeFormatter; import java.util.Locale; @@ -56,4 +56,3 @@ public class Bug8139107 { // Pattern with time zone field static final String pattern = "dd-MM-yyyy HH:mm:ss z"; } - diff --git a/test/jdk/tools/jlink/JLink100Modules.java b/test/jdk/tools/jlink/JLink100Modules.java index 1ce63aec9e6..7927a2de2b4 100644 --- a/test/jdk/tools/jlink/JLink100Modules.java +++ b/test/jdk/tools/jlink/JLink100Modules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import tests.JImageGenerator; * jdk.jlink/jdk.tools.jimage * jdk.compiler * @build tests.* - * @run main/othervm -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink100Modules + * @run main/othervm/timeout=480 -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink100Modules */ public class JLink100Modules { private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") diff --git a/test/jdk/tools/jlink/JLink20000Packages.java b/test/jdk/tools/jlink/JLink20000Packages.java index 865cf7ca98c..d592cbc112b 100644 --- a/test/jdk/tools/jlink/JLink20000Packages.java +++ b/test/jdk/tools/jlink/JLink20000Packages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +45,7 @@ import tests.JImageGenerator; * jdk.jlink/jdk.tools.jimage * jdk.compiler * @build tests.* - * @run main/othervm -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages + * @run main/othervm/timeout=1920 -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages */ public class JLink20000Packages { private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index 0b7de201ac9..bc4d2a08800 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +55,7 @@ import tests.JImageGenerator; * jdk.jlink/jdk.tools.jimage * jdk.compiler * @build tests.* - * @run main/othervm -Xmx1g JLinkTest + * @run main/othervm/timeout=480 -Xmx1g JLinkTest */ public class JLinkTest { static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") diff --git a/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java b/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java index 008b4a175a9..d2c3f2800a8 100644 --- a/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java +++ b/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java @@ -68,7 +68,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @build tests.* * @build jdk.test.lib.Platform * @build tools.jlink.plugins.GetAvailableLocales - * @run junit/othervm/timeout=180 -Xmx1g IncludeLocalesPluginTest + * @run junit/othervm/timeout=720 -Xmx1g IncludeLocalesPluginTest */ public class IncludeLocalesPluginTest { diff --git a/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java b/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java index d923358aed9..49ce65b08ed 100644 --- a/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java +++ b/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java @@ -40,7 +40,7 @@ import tests.Helper; * jdk.jlink/jdk.tools.jimage * @build tests.* jdk.test.lib.process.OutputAnalyzer * jdk.test.lib.process.ProcessTools - * @run main/othervm -Xmx1g JavaSEReproducibleTest + * @run main/othervm/timeout=480 -Xmx1g JavaSEReproducibleTest */ public class JavaSEReproducibleTest extends AbstractLinkableRuntimeTest { diff --git a/test/jdk/tools/jpackage/macosx/DmgContentTest.java b/test/jdk/tools/jpackage/macosx/DmgContentTest.java index c670d111e20..f6c2fe63671 100644 --- a/test/jdk/tools/jpackage/macosx/DmgContentTest.java +++ b/test/jdk/tools/jpackage/macosx/DmgContentTest.java @@ -42,7 +42,7 @@ import java.util.List; * @build jdk.jpackage.test.* * @build DmgContentTest * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=DmgContentTest */ public class DmgContentTest { diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 889a5bb374e..81831f59da3 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -44,7 +44,7 @@ import jdk.jpackage.test.Annotations.Test; * @build jdk.jpackage.test.* * @build MacFileAssociationsTest * @requires (os.family == "mac") - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=480 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacFileAssociationsTest */ public class MacFileAssociationsTest { diff --git a/test/jdk/tools/jpackage/share/AddLauncherTest.java b/test/jdk/tools/jpackage/share/AddLauncherTest.java index 8d5f0de28f2..a7bfbf376ed 100644 --- a/test/jdk/tools/jpackage/share/AddLauncherTest.java +++ b/test/jdk/tools/jpackage/share/AddLauncherTest.java @@ -50,7 +50,7 @@ import jdk.jpackage.test.CfgFile; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AddLauncherTest.java - * @run main/othervm/timeout=360 -Xmx512m + * @run main/othervm/timeout=1440 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=AddLauncherTest.test */ @@ -63,7 +63,7 @@ import jdk.jpackage.test.CfgFile; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AddLauncherTest.java - * @run main/othervm/timeout=540 -Xmx512m + * @run main/othervm/timeout=2160 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=AddLauncherTest */ diff --git a/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java b/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java index abd1288e024..3cbb14e4015 100644 --- a/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java +++ b/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java @@ -52,7 +52,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build AppLauncherSubstTest - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=480 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppLauncherSubstTest */ public class AppLauncherSubstTest { diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index c9e66cbd7a1..ad96a9b9e0c 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -39,7 +39,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AppVersionTest.java - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppVersionTest */ diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index b55f7bb87ad..7dcd9f73d2d 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -57,7 +57,7 @@ import jdk.tools.jlink.internal.LinkableRuntimeImage; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror BasicTest.java - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=BasicTest */ diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index df207d1c30a..a2a9e67bd91 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -52,7 +52,7 @@ import jdk.jpackage.test.Annotations.Test; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror IconTest.java - * @run main/othervm/timeout=720 -Xmx512m + * @run main/othervm/timeout=2880 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=IconTest */ diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index f5fe3c618ae..f7c597d2ed3 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -50,7 +50,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InOutPathTest.java - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InOutPathTest */ public final class InOutPathTest { diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index bbdc118d60b..5106eed3fc6 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -66,7 +66,7 @@ import jdk.jpackage.test.TKit.TextStreamVerifier; * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InstallDirTest.java * @requires (jpackage.test.SQETest != null) - * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=4000 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InstallDirTest.testCommon */ @@ -78,7 +78,7 @@ import jdk.jpackage.test.TKit.TextStreamVerifier; * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InstallDirTest.java * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=4000 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InstallDirTest */ public class InstallDirTest { diff --git a/test/jdk/tools/jpackage/share/JavaOptionsTest.java b/test/jdk/tools/jpackage/share/JavaOptionsTest.java index cb720dfb2a3..d1a0dbccf83 100644 --- a/test/jdk/tools/jpackage/share/JavaOptionsTest.java +++ b/test/jdk/tools/jpackage/share/JavaOptionsTest.java @@ -37,7 +37,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror JavaOptionsTest.java - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2840 -Xmx512m jdk.jpackage.test.Main * --jpt-run=JavaOptionsTest * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault */ diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index dd89d84e46d..bc813c4ec15 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -58,7 +58,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror MainClassTest.java - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MainClassTest */ diff --git a/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java index 8becb6f3dc3..de8412c2839 100644 --- a/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java @@ -46,7 +46,7 @@ import jdk.jpackage.test.JPackageCommand; * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror MultiNameTwoPhaseTest.java - * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2160 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MultiNameTwoPhaseTest */ diff --git a/test/jdk/tools/jpackage/share/PostImageScriptTest.java b/test/jdk/tools/jpackage/share/PostImageScriptTest.java index bbdd0b7c581..68ded999e4a 100644 --- a/test/jdk/tools/jpackage/share/PostImageScriptTest.java +++ b/test/jdk/tools/jpackage/share/PostImageScriptTest.java @@ -52,7 +52,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror PostImageScriptTest.java - * @run main/othervm/timeout=720 -Xmx512m + * @run main/othervm/timeout=2880 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=PostImageScriptTest */ diff --git a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java index c76f68476db..7f04ee2bd2e 100644 --- a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java +++ b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; * @requires os.family == "windows" * @build jdk.jpackage.test.* * @build WinNoRestartTest - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=480 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinNoRestartTest */ diff --git a/test/jdk/tools/launcher/InstanceMainTest.java b/test/jdk/tools/launcher/InstanceMainTest.java index 699db27d7bb..273d56a86bd 100644 --- a/test/jdk/tools/launcher/InstanceMainTest.java +++ b/test/jdk/tools/launcher/InstanceMainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 java.util.function.Consumer; * @test * @bug 8329420 * @summary test execution priority and behavior of main methods - * @run main InstanceMainTest + * @run main/timeout=480 InstanceMainTest */ public class InstanceMainTest extends TestHelper { diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java index 9a80ca4d089..3c51b938396 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java @@ -34,7 +34,7 @@ * @build toolbox.ToolBox toolbox.JavacTask javadoc.tester.* * @build jtreg.SkippedException * @build jdk.test.lib.Platform jdk.test.lib.net.SimpleSSLContext jdk.test.lib.net.URIBuilder - * @run main TestRedirectLinks + * @run main/timeout=480 TestRedirectLinks */ import java.io.File; diff --git a/test/langtools/jdk/jshell/ClassesTest.java b/test/langtools/jdk/jshell/ClassesTest.java index 8c17c8072f8..3da389e5059 100644 --- a/test/langtools/jdk/jshell/ClassesTest.java +++ b/test/langtools/jdk/jshell/ClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456 8282160 8292755 8319532 * @summary Tests for EvaluationState.classes * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng ClassesTest + * @run testng/timeout=480 ClassesTest */ import java.util.ArrayList; diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index fb9e8eacc4a..cfbe874e6f2 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -32,7 +32,7 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng CompletionSuggestionTest + * @run testng/timeout=480 CompletionSuggestionTest */ import java.io.IOException; diff --git a/test/langtools/jdk/jshell/HangingRemoteAgent.java b/test/langtools/jdk/jshell/HangingRemoteAgent.java index 515f98731a3..141499b0cfd 100644 --- a/test/langtools/jdk/jshell/HangingRemoteAgent.java +++ b/test/langtools/jdk/jshell/HangingRemoteAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,9 +35,7 @@ import jdk.jshell.spi.ExecutionControlProvider; */ class HangingRemoteAgent extends RemoteExecutionControl { - private static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - - private static final int TIMEOUT = (int)(2000 * timeoutFactor); + private static final int TIMEOUT = (int)(2000 * Double.parseDouble(System.getProperty("test.timeout.factor", "1.0"))); private static final long DELAY = TIMEOUT * 2L; private static final boolean INFRA_VERIFY = false; diff --git a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java index 577228d4820..cb8fc2ea408 100644 --- a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng JdiHangingLaunchExecutionControlTest + * @run testng/timeout=480 JdiHangingLaunchExecutionControlTest */ import org.testng.annotations.Test; diff --git a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java index 2e9b04a634b..d43c3f170bd 100644 --- a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java @@ -27,7 +27,7 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng JdiHangingListenExecutionControlTest + * @run testng/timeout=480 JdiHangingListenExecutionControlTest * @key intermittent */ diff --git a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java index bb6f4588968..6af4b82dbb9 100644 --- a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream ToolSimpleTest - * @run testng/othervm ToolLocalSimpleTest + * @run testng/othervm/timeout=480 ToolLocalSimpleTest */ import java.util.Locale; diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 62ea2451fb4..4ed0e741d49 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * jdk.jshell/jdk.internal.jshell.tool * java.desktop * @build KullaTesting TestingInputStream - * @run testng ToolSimpleTest + * @run testng/timeout=480 ToolSimpleTest */ import java.util.ArrayList; diff --git a/test/langtools/jdk/jshell/UITesting.java b/test/langtools/jdk/jshell/UITesting.java index cc821b1874b..e7daa4df8e6 100644 --- a/test/langtools/jdk/jshell/UITesting.java +++ b/test/langtools/jdk/jshell/UITesting.java @@ -145,18 +145,7 @@ public class UITesting { public void test(Writer inputSink, StringBuilder out) throws Exception; } - private static final long TIMEOUT; - - static { - long factor; - - try { - factor = (long) Double.parseDouble(System.getProperty("test.timeout.factor", "1")); - } catch (NumberFormatException ex) { - factor = 1; - } - TIMEOUT = 60_000 * factor; - } + private static final long TIMEOUT = (long) (60_000 * Double.parseDouble(System.getProperty("test.timeout.factor", "1.0"))); protected void waitOutput(StringBuilder out, String expected) { waitOutput(out, expected, null); diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index a7aabc0ead6..64d25e8a63c 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jshell * @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng VariablesTest + * @run testng/timeout=480 VariablesTest */ import java.nio.file.Path; diff --git a/test/langtools/tools/javac/Paths/MineField.java b/test/langtools/tools/javac/Paths/MineField.java index ee8ead00027..f01afeef3aa 100644 --- a/test/langtools/tools/javac/Paths/MineField.java +++ b/test/langtools/tools/javac/Paths/MineField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test that javac and java find files in similar ways * @library /tools/lib * @build toolbox.ToolBox Util MineField - * @run main MineField + * @run main/timeout=480 MineField */ /* diff --git a/test/langtools/tools/javac/Paths/WildcardMineField.java b/test/langtools/tools/javac/Paths/WildcardMineField.java index ad1362080b1..c47337923f6 100644 --- a/test/langtools/tools/javac/Paths/WildcardMineField.java +++ b/test/langtools/tools/javac/Paths/WildcardMineField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test classpath wildcards for javac and java -classpath option. * @library /tools/lib * @build toolbox.ToolBox Util WildcardMineField - * @run main WildcardMineField + * @run main/timeout=480 WildcardMineField */ /* diff --git a/test/langtools/tools/javac/diags/CheckExamples.java b/test/langtools/tools/javac/diags/CheckExamples.java index dd763f3d3da..502f5fa8b88 100644 --- a/test/langtools/tools/javac/diags/CheckExamples.java +++ b/test/langtools/tools/javac/diags/CheckExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.resources:open * jdk.compiler/com.sun.tools.javac.util * @build Example CheckExamples DocCommentProcessor - * @run main/othervm CheckExamples + * @run main/othervm/timeout=480 CheckExamples */ /* diff --git a/test/langtools/tools/javac/diags/RunExamples.java b/test/langtools/tools/javac/diags/RunExamples.java index 7e956aefb36..7805efa734b 100644 --- a/test/langtools/tools/javac/diags/RunExamples.java +++ b/test/langtools/tools/javac/diags/RunExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.parser * jdk.compiler/com.sun.tools.javac.util * @build ArgTypeCompilerFactory Example HTMLWriter RunExamples DocCommentProcessor - * @run main/othervm RunExamples + * @run main/othervm/timeout=480 RunExamples */ /* * See CR 7127924 for info on why othervm is used. diff --git a/test/langtools/tools/javac/failover/CheckAttributedTree.java b/test/langtools/tools/javac/failover/CheckAttributedTree.java index 1969a97df05..9b28d2bebd4 100644 --- a/test/langtools/tools/javac/failover/CheckAttributedTree.java +++ b/test/langtools/tools/javac/failover/CheckAttributedTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main CheckAttributedTree -q -r -et ERRONEOUS . + * @run main/timeout=480 CheckAttributedTree -q -r -et ERRONEOUS . */ import java.awt.BorderLayout; diff --git a/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java b/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java index ce2ce4530f8..09209e14c9d 100644 --- a/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java +++ b/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask - * @run testng MultiReleaseJarTest + * @run testng/timeout=480 MultiReleaseJarTest */ import org.testng.annotations.AfterClass; diff --git a/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java b/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java index 727f749c1c9..4c4775ed744 100644 --- a/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java +++ b/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @bug 7030150 7039931 * @summary Type inference for generic instance creation failed for formal type parameter * @modules jdk.compiler + * @run main/timeout=480 GenericConstructorAndDiamondTest */ import com.sun.source.util.JavacTask; diff --git a/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java b/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java index cf204264367..83ff216ef7a 100644 --- a/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java +++ b/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox NegativeCyclicDependencyTest - * @run main NegativeCyclicDependencyTest + * @run main/timeout=480 NegativeCyclicDependencyTest */ import javax.tools.JavaCompiler; diff --git a/test/langtools/tools/javac/lambda/LambdaParserTest.java b/test/langtools/tools/javac/lambda/LambdaParserTest.java index e3440d3b17f..53578d9c40d 100644 --- a/test/langtools/tools/javac/lambda/LambdaParserTest.java +++ b/test/langtools/tools/javac/lambda/LambdaParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main LambdaParserTest + * @run main/timeout=480 LambdaParserTest */ import java.io.IOException; diff --git a/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties b/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties index 90f2fe459c2..9acbe8f1700 100644 --- a/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties +++ b/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties @@ -6,3 +6,5 @@ lib.dirs = /lib/combo modules = \ jdk.compiler/com.sun.tools.javac.util + +timeout.default.seconds=480 diff --git a/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java b/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java index e702ea3e75a..27a902fcb32 100644 --- a/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java +++ b/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @bug 8002099 8010822 * @summary Add support for intersection types in cast expression * @modules jdk.compiler/com.sun.tools.javac.util + * @run main/timeout=480 IntersectionTargetTypeTest */ import com.sun.source.util.JavacTask; diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java index a6298bfa8ce..ee3bb8c897d 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java @@ -49,7 +49,7 @@ import org.junit.jupiter.api.Test; * * @compile ${test.root}/../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java * - * @run junit CreateSymbolsReproducibleTest + * @run junit/timeout=480 CreateSymbolsReproducibleTest */ public class CreateSymbolsReproducibleTest { diff --git a/test/langtools/tools/javac/tree/JavacTreeScannerTest.java b/test/langtools/tools/javac/tree/JavacTreeScannerTest.java index 590cdb849c4..8e9c0501f8e 100644 --- a/test/langtools/tools/javac/tree/JavacTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/JavacTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest JavacTreeScannerTest - * @run main JavacTreeScannerTest -q -r . + * @run main/timeout=480 JavacTreeScannerTest -q -r . */ import java.io.*; diff --git a/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java b/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java index 72cc2d2e9d1..da069f4f911 100644 --- a/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest SourceDocTreeScannerTest - * @run main SourceDocTreeScannerTest -q -r . + * @run main/timeout=480 SourceDocTreeScannerTest -q -r . */ import java.io.*; diff --git a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java index bf50f298871..de68377a3c6 100644 --- a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest SourceTreeScannerTest - * @run main SourceTreeScannerTest -q -r . + * @run main/timeout=480 SourceTreeScannerTest -q -r . */ import java.io.*; diff --git a/test/langtools/tools/javac/types/TestComparisons.java b/test/langtools/tools/javac/types/TestComparisons.java index 9835e1271f5..8b15edd6715 100644 --- a/test/langtools/tools/javac/types/TestComparisons.java +++ b/test/langtools/tools/javac/types/TestComparisons.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @bug 8013357 * @summary javac should correctly enforce binary comparison rules. * @modules jdk.compiler + * @run main/timeout=480 TestComparisons */ import java.io.*; diff --git a/test/langtools/tools/javac/util/IteratorsTest.java b/test/langtools/tools/javac/util/IteratorsTest.java index cbfde59b1e1..bd05bebeb09 100644 --- a/test/langtools/tools/javac/util/IteratorsTest.java +++ b/test/langtools/tools/javac/util/IteratorsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8303882 * @summary Verify that Iterators method work as expected * @modules jdk.compiler/com.sun.tools.javac.util - * @run junit IteratorsTest + * @run junit/timeout=480 IteratorsTest */ import com.sun.tools.javac.util.Iterators; diff --git a/test/langtools/tools/javac/varargs/warning/Warn5.java b/test/langtools/tools/javac/varargs/warning/Warn5.java index af8c045e62b..114f94ebc91 100644 --- a/test/langtools/tools/javac/varargs/warning/Warn5.java +++ b/test/langtools/tools/javac/varargs/warning/Warn5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main/othervm Warn5 + * @run main/othervm/timeout=480 Warn5 */ import java.io.IOException; diff --git a/test/langtools/tools/lib/toolbox/ToolBox.java b/test/langtools/tools/lib/toolbox/ToolBox.java index 0763da16ee5..ee217ab2c0c 100644 --- a/test/langtools/tools/lib/toolbox/ToolBox.java +++ b/test/langtools/tools/lib/toolbox/ToolBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,12 +102,6 @@ public class ToolBox { public static final String testSrc = System.getProperty("test.src"); /** The location of the test JDK for this test, or null if not set. */ public static final String testJDK = System.getProperty("test.jdk"); - /** The timeout factor for slow systems. */ - public static final float timeoutFactor; - static { - String ttf = System.getProperty("test.timeout.factor"); - timeoutFactor = (ttf == null) ? 1.0f : Float.parseFloat(ttf); - } /** The current directory. */ public static final Path currDir = Path.of("."); @@ -482,8 +476,8 @@ public class ToolBox { throw new IOException("File not deleted: " + path); } - private static final int RETRY_DELETE_MILLIS = isWindows() ? (int)(500 * timeoutFactor): 0; - private static final int MAX_RETRY_DELETE_MILLIS = isWindows() ? (int)(15 * 1000 * timeoutFactor) : 0; + private static final int RETRY_DELETE_MILLIS = isWindows() ? 500 : 0; + private static final int MAX_RETRY_DELETE_MILLIS = isWindows() ? 60 * 1000 : 0; /** * Moves a file. diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index 56e3baa2e25..13ac2e4e97a 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -228,9 +228,6 @@ public class CDSTestUtils { public static final boolean copyChildStdoutToMainStdout = Boolean.getBoolean("test.cds.copy.child.stdout"); - // This property is passed to child test processes - public static final String TestTimeoutFactor = System.getProperty("test.timeout.factor", "1.0"); - public static final String UnableToMapMsg = "Unable to map shared archive: test did not complete"; @@ -433,7 +430,7 @@ public class CDSTestUtils { ArrayList cmd = new ArrayList(); cmd.addAll(opts.prefix); cmd.add("-Xshare:" + opts.xShareMode); - cmd.add("-Dtest.timeout.factor=" + TestTimeoutFactor); + cmd.add("-Dtest.timeout.factor=" + Utils.TIMEOUT_FACTOR); if (!opts.useSystemArchive) { if (opts.archiveName == null) diff --git a/test/lib/jdk/test/lib/util/ForceGC.java b/test/lib/jdk/test/lib/util/ForceGC.java index e3587b9a2be..b1517d38175 100644 --- a/test/lib/jdk/test/lib/util/ForceGC.java +++ b/test/lib/jdk/test/lib/util/ForceGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +27,12 @@ import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.function.BooleanSupplier; +import jdk.test.lib.Utils; /** * Utility class to invoke System.gc() */ public class ForceGC { - // The jtreg testing timeout factor. - private static final double TIMEOUT_FACTOR = Double.valueOf( - System.getProperty("test.timeout.factor", "1.0")); - /** * Causes the current thread to wait until the {@code booleanSupplier} * returns true, or the waiting time elapses. The waiting time @@ -57,7 +54,7 @@ public class ForceGC { */ public static boolean wait(BooleanSupplier booleanSupplier) { - return waitFor(booleanSupplier, Math.round(1000L * TIMEOUT_FACTOR)); + return waitFor(booleanSupplier, Math.round(1000L * Utils.TIMEOUT_FACTOR)); } /** From 3fb9246af9a006c0b3a1f9c41d60dff74f7bf140 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Sep 2025 07:54:36 +0000 Subject: [PATCH 084/295] 8366544: Parallel: Inline PSParallelCompact::invoke_no_policy Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 10 +--------- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index b549c61e1c0..5a0dbe3d4e6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -969,19 +969,11 @@ 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"); + assert(ref_processor() != nullptr, "Sanity"); SvcGCMarker sgcm(SvcGCMarker::FULL); IsSTWGCActiveMark mark; - 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 clear_all_soft_refs) { - assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); - assert(ref_processor() != nullptr, "Sanity"); - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCIdMark gc_id_mark; diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index a0118717f9d..874c72d5671 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -762,7 +762,6 @@ public: static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); static bool invoke(bool clear_all_soft_refs); - static bool invoke_no_policy(bool clear_all_soft_refs); template static void adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe); From d19eab4f08592140229de43689c7d20ff7fbf4ee Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Tue, 2 Sep 2025 07:57:03 +0000 Subject: [PATCH 085/295] 8366556: Sort share/runtime includes Reviewed-by: dholmes, ayang --- src/hotspot/share/runtime/basicLock.inline.hpp | 1 + src/hotspot/share/runtime/continuationFreezeThaw.cpp | 6 +++--- src/hotspot/share/runtime/continuationHelper.inline.hpp | 1 - src/hotspot/share/runtime/continuationWrapper.inline.hpp | 2 +- src/hotspot/share/runtime/cpuTimeCounters.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 4 +--- src/hotspot/share/runtime/fieldDescriptor.cpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.hpp | 3 ++- src/hotspot/share/runtime/flags/jvmFlagAccess.cpp | 2 +- .../share/runtime/flags/jvmFlagConstraintsCompiler.cpp | 4 ++-- .../share/runtime/flags/jvmFlagConstraintsRuntime.cpp | 2 +- src/hotspot/share/runtime/flags/jvmFlagLimit.cpp | 7 +++---- src/hotspot/share/runtime/flags/jvmFlagLookup.hpp | 2 +- src/hotspot/share/runtime/frame.cpp | 2 +- src/hotspot/share/runtime/frame.inline.hpp | 2 +- src/hotspot/share/runtime/handles.inline.hpp | 2 +- src/hotspot/share/runtime/handshake.cpp | 2 +- src/hotspot/share/runtime/interfaceSupport.cpp | 1 - src/hotspot/share/runtime/java.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 6 +++--- src/hotspot/share/runtime/javaThread.hpp | 2 +- src/hotspot/share/runtime/keepStackGCProcessed.cpp | 2 +- src/hotspot/share/runtime/objectMonitor.cpp | 1 - src/hotspot/share/runtime/os.cpp | 4 ++-- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- src/hotspot/share/runtime/signature.cpp | 1 - src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp | 2 +- src/hotspot/share/runtime/stubCodeGenerator.cpp | 1 - src/hotspot/share/runtime/stubRoutines.cpp | 2 +- src/hotspot/share/runtime/synchronizer.cpp | 1 - src/hotspot/share/runtime/threadSMR.inline.hpp | 2 +- src/hotspot/share/runtime/threads.cpp | 6 +++--- src/hotspot/share/runtime/vframe.cpp | 3 +-- src/hotspot/share/runtime/vframeArray.cpp | 2 +- src/hotspot/share/runtime/vframe_hp.cpp | 2 +- src/hotspot/share/runtime/vmOperations.cpp | 2 +- src/hotspot/share/runtime/vmOperations.hpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 5 ++--- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 39 files changed, 45 insertions(+), 53 deletions(-) diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index ee4791edecf..773d8a1c848 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_BASICLOCK_INLINE_HPP #include "runtime/basicLock.hpp" + #include "runtime/objectMonitor.inline.hpp" inline markWord BasicLock::displaced_header() const { diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 1027b4447c5..40a8987e139 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -28,9 +28,9 @@ #include "code/nmethod.inline.hpp" #include "code/vmreg.inline.hpp" #include "compiler/oopMap.inline.hpp" +#include "gc/shared/barrierSet.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gc_globals.hpp" -#include "gc/shared/barrierSet.hpp" #include "gc/shared/memAllocator.hpp" #include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "interpreter/interpreter.hpp" @@ -39,8 +39,8 @@ #include "logging/logStream.hpp" #include "oops/access.inline.hpp" #include "oops/method.inline.hpp" -#include "oops/oopsHierarchy.hpp" #include "oops/objArrayOop.inline.hpp" +#include "oops/oopsHierarchy.hpp" #include "oops/stackChunkOop.inline.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/arguments.hpp" @@ -57,8 +57,8 @@ #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" -#include "runtime/smallRegisterMap.inline.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/smallRegisterMap.inline.hpp" #include "runtime/stackChunkFrameStream.inline.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stackOverflow.hpp" diff --git a/src/hotspot/share/runtime/continuationHelper.inline.hpp b/src/hotspot/share/runtime/continuationHelper.inline.hpp index 279e2a5ffd5..9aadfd8a388 100644 --- a/src/hotspot/share/runtime/continuationHelper.inline.hpp +++ b/src/hotspot/share/runtime/continuationHelper.inline.hpp @@ -28,7 +28,6 @@ #include "runtime/continuationHelper.hpp" #include "code/scopeDesc.hpp" -#include "compiler/oopMap.hpp" #include "compiler/oopMap.inline.hpp" #include "interpreter/oopMapCache.hpp" #include "runtime/frame.inline.hpp" diff --git a/src/hotspot/share/runtime/continuationWrapper.inline.hpp b/src/hotspot/share/runtime/continuationWrapper.inline.hpp index 0215f765c5d..ddf5e0be02d 100644 --- a/src/hotspot/share/runtime/continuationWrapper.inline.hpp +++ b/src/hotspot/share/runtime/continuationWrapper.inline.hpp @@ -28,8 +28,8 @@ // There is no continuationWrapper.hpp file #include "classfile/javaClasses.inline.hpp" -#include "oops/oop.inline.hpp" #include "memory/allocation.hpp" +#include "oops/oop.inline.hpp" #include "oops/oopsHierarchy.hpp" #include "oops/stackChunkOop.hpp" #include "runtime/continuationEntry.inline.hpp" diff --git a/src/hotspot/share/runtime/cpuTimeCounters.cpp b/src/hotspot/share/runtime/cpuTimeCounters.cpp index 0248db8fec3..c6bcffbd024 100644 --- a/src/hotspot/share/runtime/cpuTimeCounters.cpp +++ b/src/hotspot/share/runtime/cpuTimeCounters.cpp @@ -23,8 +23,8 @@ * */ -#include "runtime/cpuTimeCounters.hpp" #include "runtime/atomic.hpp" +#include "runtime/cpuTimeCounters.hpp" const char* CPUTimeGroups::to_string(CPUTimeType val) { switch (val) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index efc7bfde3dd..521ac5454ea 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -35,7 +35,6 @@ #include "compiler/compilerDefinitions.inline.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/memAllocator.hpp" -#include "interpreter/bytecode.hpp" #include "interpreter/bytecode.inline.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/interpreter.hpp" @@ -68,7 +67,6 @@ #include "runtime/continuationEntry.inline.hpp" #include "runtime/deoptimization.hpp" #include "runtime/escapeBarrier.hpp" -#include "runtime/fieldDescriptor.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" @@ -91,8 +89,8 @@ #include "runtime/threadSMR.hpp" #include "runtime/threadWXSetters.inline.hpp" #include "runtime/vframe.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" #include "runtime/vmOperations.hpp" #include "utilities/checkedCast.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index 28f44d4de8d..c5c3bdbd4bc 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -26,10 +26,10 @@ #include "memory/resourceArea.hpp" #include "oops/annotations.hpp" #include "oops/constantPool.hpp" +#include "oops/fieldStreams.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/fieldStreams.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlag.hpp b/src/hotspot/share/runtime/flags/jvmFlag.hpp index 5bd5c2bdb4f..a9dace1e19c 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.hpp @@ -25,10 +25,11 @@ #ifndef SHARE_RUNTIME_FLAGS_JVMFLAG_HPP #define SHARE_RUNTIME_FLAGS_JVMFLAG_HPP -#include "utilities/globalDefinitions.hpp" #include "utilities/enumIterator.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/vmEnums.hpp" + #include class outputStream; diff --git a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp index dead6e632ef..2db9f198ddd 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp @@ -26,8 +26,8 @@ #include "memory/allocation.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/flags/jvmFlagAccess.hpp" -#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 17dc71bc59d..4e28135dccf 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -25,14 +25,14 @@ #include "code/relocInfo.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "compiler/compilerDirectives.hpp" -#include "oops/metadata.hpp" -#include "runtime/os.hpp" #include "interpreter/invocationCounter.hpp" +#include "oops/metadata.hpp" #include "runtime/arguments.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/flags/jvmFlagConstraintsCompiler.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/os.hpp" #include "utilities/powerOfTwo.hpp" /** diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp index 6a618cd7fea..1e6efd893c8 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp @@ -23,8 +23,8 @@ */ #include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "runtime/safepointMechanism.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp b/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp index 3d5faa85a0d..b5507c07ee7 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp @@ -22,16 +22,15 @@ * */ -#include "memory/allocation.inline.hpp" #include "gc/shared/jvmFlagConstraintsGC.hpp" +#include "memory/allocation.inline.hpp" +#include "oops/markWord.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/flags/jvmFlagAccess.hpp" -#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/flags/jvmFlagConstraintsCompiler.hpp" #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/globals_extension.hpp" -#include "gc/shared/referenceProcessor.hpp" -#include "oops/markWord.hpp" #include "runtime/task.hpp" #include "utilities/vmError.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp b/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp index 128025b8e22..256f674f19c 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_RUNTIME_FLAGS_JVMFLAGLOOKUP_HPP #define SHARE_RUNTIME_FLAGS_JVMFLAGLOOKUP_HPP -#include "runtime/globals_extension.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/globals_extension.hpp" // This is a hashtable that maps from (const char*) to (JVMFlag*) to speed up // the processing of JVM command-line arguments at runtime. diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index ba9aa3eb29a..75c6e388b0d 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -50,8 +50,8 @@ #include "runtime/javaThread.hpp" #include "runtime/monitorChunk.hpp" #include "runtime/os.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/safefetch.hpp" +#include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stackValue.hpp" #include "runtime/stubCodeGenerator.hpp" diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index aa2de69a739..449abddd443 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -30,8 +30,8 @@ #include "code/codeBlob.inline.hpp" #include "code/nmethod.inline.hpp" #include "interpreter/interpreter.hpp" -#include "oops/stackChunkOop.inline.hpp" #include "oops/method.hpp" +#include "oops/stackChunkOop.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/registerMap.hpp" #include "runtime/stubRoutines.hpp" diff --git a/src/hotspot/share/runtime/handles.inline.hpp b/src/hotspot/share/runtime/handles.inline.hpp index 4d3dd527c0d..15b06315823 100644 --- a/src/hotspot/share/runtime/handles.inline.hpp +++ b/src/hotspot/share/runtime/handles.inline.hpp @@ -27,9 +27,9 @@ #include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" #include "oops/metadata.hpp" #include "oops/oop.hpp" +#include "runtime/javaThread.hpp" // these inline functions are in a separate file to break an include cycle // between Thread and Handle diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index e6a12677a19..f9e48b7f711 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -40,8 +40,8 @@ #include "runtime/task.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vmThread.hpp" -#include "utilities/formatBuffer.hpp" #include "utilities/filterQueue.inline.hpp" +#include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/preserveException.hpp" #include "utilities/systemMemoryBarrier.hpp" diff --git a/src/hotspot/share/runtime/interfaceSupport.cpp b/src/hotspot/share/runtime/interfaceSupport.cpp index 42dc37f4ccb..53216f14f24 100644 --- a/src/hotspot/share/runtime/interfaceSupport.cpp +++ b/src/hotspot/share/runtime/interfaceSupport.cpp @@ -22,7 +22,6 @@ * */ -#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 2aaf020d6d6..b3b46e5a9ab 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -75,9 +75,9 @@ #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "runtime/trimNativeHeap.hpp" +#include "runtime/vm_version.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" -#include "runtime/vm_version.hpp" #include "sanitizers/leak.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index a0ac7bd4768..5ea2a4e4385 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -32,8 +32,8 @@ #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" #include "code/scopeDesc.hpp" -#include "compiler/compileTask.hpp" #include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/tlab_globals.hpp" @@ -88,10 +88,10 @@ #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "runtime/vframe.inline.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" -#include "runtime/vmThread.hpp" +#include "runtime/vframeArray.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "services/threadService.hpp" #include "utilities/copy.hpp" #include "utilities/defaultStream.hpp" diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index fac263d9048..bf72fac5737 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -38,8 +38,8 @@ #include "runtime/lockStack.hpp" #include "runtime/park.hpp" #include "runtime/safepointMechanism.hpp" -#include "runtime/stackWatermarkSet.hpp" #include "runtime/stackOverflow.hpp" +#include "runtime/stackWatermarkSet.hpp" #include "runtime/suspendResumeManager.hpp" #include "runtime/thread.hpp" #include "runtime/threadHeapSampler.hpp" diff --git a/src/hotspot/share/runtime/keepStackGCProcessed.cpp b/src/hotspot/share/runtime/keepStackGCProcessed.cpp index d928e689fea..01029b6b977 100644 --- a/src/hotspot/share/runtime/keepStackGCProcessed.cpp +++ b/src/hotspot/share/runtime/keepStackGCProcessed.cpp @@ -22,10 +22,10 @@ * */ +#include "runtime/keepStackGCProcessed.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackWatermark.inline.hpp" #include "runtime/stackWatermarkSet.inline.hpp" -#include "runtime/keepStackGCProcessed.hpp" KeepStackGCProcessedMark::KeepStackGCProcessedMark(JavaThread* jt) : _active(true), diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 39ba328b0d0..9e3638ddadc 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -45,7 +45,6 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/lightweightSynchronizer.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/osThread.hpp" diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 3152f734dfa..f2a7587d364 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -65,8 +65,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/threadCrashProtection.hpp" #include "runtime/threadSMR.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "sanitizers/address.hpp" #include "services/attachListener.hpp" #include "services/threadService.hpp" @@ -89,8 +89,8 @@ # include #endif -# include # include +# include OSThread* os::_starting_thread = nullptr; volatile unsigned int os::_rand_seed = 1234567; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 13612496fbd..044359eba8d 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -42,8 +42,8 @@ #include "gc/shared/collectedHeap.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "jvm.h" #include "jfr/jfrEvents.hpp" +#include "jvm.h" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp index fb649b8c872..9ae5b3df415 100644 --- a/src/hotspot/share/runtime/signature.cpp +++ b/src/hotspot/share/runtime/signature.cpp @@ -39,7 +39,6 @@ #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" -#include "runtime/sharedRuntime.hpp" // Implementation of SignatureIterator diff --git a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp index 734d31d3390..09c267b408b 100644 --- a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp +++ b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp @@ -31,10 +31,10 @@ #include "compiler/oopMap.hpp" #include "interpreter/interpreter.hpp" #include "logging/log.hpp" +#include "oops/instanceStackChunkKlass.inline.hpp" #include "oops/method.hpp" #include "oops/oop.hpp" #include "oops/stackChunkOop.inline.hpp" -#include "oops/instanceStackChunkKlass.inline.hpp" #include "runtime/frame.inline.hpp" #include "utilities/debug.hpp" #include "utilities/devirtualizer.inline.hpp" diff --git a/src/hotspot/share/runtime/stubCodeGenerator.cpp b/src/hotspot/share/runtime/stubCodeGenerator.cpp index 4e5f1635e42..43250c004ca 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.cpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp @@ -22,7 +22,6 @@ * */ -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/codeCache.hpp" #include "compiler/disassembler.hpp" diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 82608737be8..5246613738e 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -31,9 +31,9 @@ #include "prims/vectorSupport.hpp" #include "runtime/continuation.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" #ifdef COMPILER2 diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 221e7dd71ec..f3e3072978b 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -44,7 +44,6 @@ #include "runtime/lightweightSynchronizer.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.inline.hpp" #include "runtime/osThread.hpp" diff --git a/src/hotspot/share/runtime/threadSMR.inline.hpp b/src/hotspot/share/runtime/threadSMR.inline.hpp index 3bca94a82e5..a78fbf48761 100644 --- a/src/hotspot/share/runtime/threadSMR.inline.hpp +++ b/src/hotspot/share/runtime/threadSMR.inline.hpp @@ -29,8 +29,8 @@ #include "gc/shared/gc_globals.hpp" #include "gc/shared/tlab_globals.hpp" -#include "runtime/atomic.hpp" #include "memory/iterator.hpp" +#include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 1ac44b8a2f5..5ba3499efbe 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -37,8 +37,8 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" -#include "compiler/compileTask.hpp" #include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/gcVMOperations.hpp" @@ -91,13 +91,13 @@ #include "runtime/stackWatermarkSet.inline.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.inline.hpp" #include "runtime/threads.hpp" +#include "runtime/threadSMR.inline.hpp" #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "runtime/trimNativeHeap.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadIdTable.hpp" diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index a3c0c41b1b1..74d42b7dc9d 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -43,7 +43,6 @@ #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.inline.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/signature.hpp" @@ -51,8 +50,8 @@ #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.inline.hpp" #include "runtime/vframe.inline.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" vframe::vframe(const frame* fr, const RegisterMap* reg_map, JavaThread* thread) : _reg_map(reg_map), _thread(thread), diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 224bce4513a..a68a0adf299 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -40,8 +40,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/synchronizer.hpp" #include "runtime/vframe.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" #include "utilities/copy.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/runtime/vframe_hp.cpp b/src/hotspot/share/runtime/vframe_hp.cpp index 5e3ef80a2ca..c901dd9f23a 100644 --- a/src/hotspot/share/runtime/vframe_hp.cpp +++ b/src/hotspot/share/runtime/vframe_hp.cpp @@ -42,8 +42,8 @@ #include "runtime/signature.hpp" #include "runtime/stackValue.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" // ------------- compiledVFrame -------------- diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 2cfc84376af..c5539fd5e50 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -31,8 +31,8 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "logging/log.hpp" -#include "logging/logStream.hpp" #include "logging/logConfiguration.hpp" +#include "logging/logStream.hpp" #include "memory/heapInspection.hpp" #include "memory/metaspace/metaspaceReporter.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index baeea722dce..2ed9626652c 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -27,8 +27,8 @@ #include "oops/oop.hpp" #include "runtime/javaThread.hpp" -#include "runtime/vmOperation.hpp" #include "runtime/threadSMR.hpp" +#include "runtime/vmOperation.hpp" class ObjectMonitorsView; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index b95c1aaf60c..3575ef70d19 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -46,7 +46,6 @@ #include "interpreter/interpreter.hpp" #include "jfr/recorder/service/jfrRecorderThread.hpp" #include "logging/logAsyncWriter.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/heap.hpp" #include "memory/padded.hpp" @@ -56,8 +55,8 @@ #include "oops/array.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" -#include "oops/constMethod.hpp" #include "oops/constantPool.hpp" +#include "oops/constMethod.hpp" #include "oops/cpCache.hpp" #include "oops/fieldInfo.hpp" #include "oops/instanceClassLoaderKlass.hpp" @@ -99,8 +98,8 @@ #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" #include "runtime/vframeArray.hpp" -#include "runtime/vmStructs.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmStructs.hpp" #include "services/attachListener.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index e2724a93890..be35f8fa2b2 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -61,6 +61,7 @@ public class TestIncludesAreSorted { "share/opto", "share/precompiled", "share/prims", + "share/runtime", "share/services", "share/utilities" }; From af532cc1b227c56cd03caca7d7558d58687d8584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nordstr=C3=B6m?= Date: Tue, 2 Sep 2025 07:58:38 +0000 Subject: [PATCH 086/295] 8365913: Support latest MSC_VER in abstract_vm_version.cpp Reviewed-by: dholmes --- src/hotspot/share/runtime/abstract_vm_version.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 97d4f7f228d..7d460d83e1b 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -271,6 +271,18 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.7 (VS2022)" #elif _MSC_VER == 1938 #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.8 (VS2022)" + #elif _MSC_VER == 1939 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.9 (VS2022)" + #elif _MSC_VER == 1940 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.10 (VS2022)" + #elif _MSC_VER == 1941 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.11 (VS2022)" + #elif _MSC_VER == 1942 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.12 (VS2022)" + #elif _MSC_VER == 1943 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.13 (VS2022)" + #elif _MSC_VER == 1944 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.14 (VS2022)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif From 523bc77981cfe82956d2176f74917c41788da6db Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Tue, 2 Sep 2025 08:15:27 +0000 Subject: [PATCH 087/295] 8364816: GetLastError() in os_windows.cpp should not store value to errno Reviewed-by: dholmes, jsikstro --- src/hotspot/os/windows/os_windows.cpp | 51 ++++++++++++---------- src/hotspot/share/cds/aotClassLocation.cpp | 6 --- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 3f3d9f6ac63..09d8b542a10 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -4700,13 +4700,13 @@ static bool is_symbolic_link(const wchar_t* wide_path) { if (f != INVALID_HANDLE_VALUE) { const bool result = fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && fd.dwReserved0 == IO_REPARSE_TAG_SYMLINK; if (::FindClose(f) == 0) { - errno = ::GetLastError(); - log_debug(os)("is_symbolic_link() failed to FindClose: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("is_symbolic_link() failed to FindClose: GetLastError->%lu.", errcode); } return result; } else { - errno = ::GetLastError(); - log_debug(os)("is_symbolic_link() failed to FindFirstFileW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("is_symbolic_link() failed to FindFirstFileW: GetLastError->%lu.", errcode); return false; } } @@ -4716,8 +4716,8 @@ static WCHAR* get_path_to_target(const wchar_t* wide_path) { HANDLE hFile = CreateFileW(wide_path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to CreateFileW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to CreateFileW: GetLastError->%lu.", errcode); return nullptr; } @@ -4725,8 +4725,8 @@ static WCHAR* get_path_to_target(const wchar_t* wide_path) { const size_t target_path_size = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED); if (target_path_size == 0) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%lu.", errcode); return nullptr; } @@ -4736,14 +4736,14 @@ static WCHAR* get_path_to_target(const wchar_t* wide_path) { const size_t res = ::GetFinalPathNameByHandleW(hFile, path_to_target, static_cast(target_path_size), FILE_NAME_NORMALIZED); if (res != target_path_size - 1) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%lu.", errcode); return nullptr; } if (::CloseHandle(hFile) == 0) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to CloseHandle: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to CloseHandle: GetLastError->%lu.", errcode); return nullptr; } @@ -4824,9 +4824,8 @@ int os::stat(const char *path, struct stat *sbuf) { if (is_symlink) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { - // it is a symbolic link, but we failed to resolve it, - // errno has been set in the call to get_path_to_target(), - // no need to overwrite it + // it is a symbolic link, but we failed to resolve it + errno = ENOENT; os::free(wide_path); return -1; } @@ -4837,8 +4836,13 @@ int os::stat(const char *path, struct stat *sbuf) { // if getting attributes failed, GetLastError should be called immediately after that if (!bret) { - errno = ::GetLastError(); - log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + if (errcode == ERROR_FILE_NOT_FOUND || errcode == ERROR_PATH_NOT_FOUND) { + errno = ENOENT; + } else { + errno = 0; + } + log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%lu.", errcode); os::free(wide_path); os::free(path_to_target); return -1; @@ -5038,9 +5042,8 @@ int os::open(const char *path, int oflag, int mode) { if (is_symlink) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { - // it is a symbolic link, but we failed to resolve it, - // errno has been set in the call to get_path_to_target(), - // no need to overwrite it + // it is a symbolic link, but we failed to resolve it + errno = ENOENT; os::free(wide_path); return -1; } @@ -5048,10 +5051,9 @@ int os::open(const char *path, int oflag, int mode) { int fd = ::_wopen(is_symlink ? path_to_target : wide_path, oflag | O_BINARY | O_NOINHERIT, mode); - // if opening files failed, GetLastError should be called immediately after that + // if opening files failed, errno has been set to indicate the problem if (fd == -1) { - errno = ::GetLastError(); - log_debug(os)("os::open() failed to _wopen: GetLastError->%ld.", errno); + log_debug(os)("os::open() failed to _wopen: errno->%s.", strerror(errno)); } os::free(wide_path); os::free(path_to_target); @@ -5119,7 +5121,8 @@ bool os::dir_is_empty(const char* path) { } FindClose(f); } else { - errno = ::GetLastError(); + DWORD errcode = ::GetLastError(); + log_debug(os)("os::dir_is_empty() failed to FindFirstFileW: GetLastError->%lu.", errcode); } return is_empty; diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index 4119b9236e1..f04c601ac86 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -241,12 +241,6 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa // The timestamp of $JAVA_HOME/lib/modules is not checked at runtime. check_time = !is_jrt; } -#ifdef _WINDOWS - } else if (errno == ERROR_FILE_NOT_FOUND || errno == ERROR_PATH_NOT_FOUND) { - // On Windows, the errno could be ERROR_PATH_NOT_FOUND (3) in case the directory - // path doesn't exist. - type = FileType::NOT_EXIST; -#endif } else if (errno == ENOENT) { // We allow the file to not exist, as long as it also doesn't exist during runtime. type = FileType::NOT_EXIST; From ef7872cc31d4d7c0a9f311eafc28132ead3476b6 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 2 Sep 2025 09:08:26 +0000 Subject: [PATCH 088/295] 8365163: [ubsan] left-shift issue in globalDefinitions.hpp Reviewed-by: kbarrett, stefank, aph --- .../share/utilities/globalDefinitions.hpp | 16 +++-------- .../utilities/test_globalDefinitions.cpp | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 2a179f5814f..1ef548d6510 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -641,19 +641,11 @@ inline jdouble jdouble_cast (jlong x) { return ((DoubleLongConv*)&x)->d; } inline jint low (jlong value) { return jint(value); } inline jint high(jlong value) { return jint(value >> 32); } -// the fancy casts are a hopefully portable way -// to do unsigned 32 to 64 bit type conversion -inline void set_low (jlong* value, jint low ) { *value &= (jlong)0xffffffff << 32; - *value |= (jlong)(julong)(juint)low; } - -inline void set_high(jlong* value, jint high) { *value &= (jlong)(julong)(juint)0xffffffff; - *value |= (jlong)high << 32; } - inline jlong jlong_from(jint h, jint l) { - jlong result = 0; // initialization to avoid warning - set_high(&result, h); - set_low(&result, l); - return result; + // First cast jint values to juint, so cast to julong will zero-extend. + julong high = (julong)(juint)h << 32; + julong low = (julong)(juint)l; + return (jlong)(high | low); } union jlong_accessor { diff --git a/test/hotspot/gtest/utilities/test_globalDefinitions.cpp b/test/hotspot/gtest/utilities/test_globalDefinitions.cpp index 38aa7aa477b..4c04b77a51b 100644 --- a/test/hotspot/gtest/utilities/test_globalDefinitions.cpp +++ b/test/hotspot/gtest/utilities/test_globalDefinitions.cpp @@ -295,3 +295,30 @@ TEST(globalDefinitions, format_specifiers) { // Check all platforms print this compatibly without leading 0x. check_format(UINT64_FORMAT_0, (u8)0x123, "0000000000000123"); } + +TEST(globalDefinitions, jlong_from) { + jlong val = jlong_from(0xFF, 0); + EXPECT_EQ(val, CONST64(0x00000000FF00000000)); + + val = jlong_from(0, 0xFF); + EXPECT_EQ(val, CONST64(0x00000000000000FF)); + + val = jlong_from(0xFFFFFFFF, 0); + EXPECT_EQ((julong)val, UCONST64(0xFFFFFFFF00000000)); + + val = jlong_from(0, 0xFFFFFFFF); + EXPECT_EQ(val, CONST64(0x00000000FFFFFFFF)); + + val = jlong_from(0, -1); + EXPECT_EQ(val, CONST64(0x00000000FFFFFFFF)); + + val = jlong_from(-1, 0); + EXPECT_EQ((julong)val, UCONST64(0xFFFFFFFF00000000)); + + val = jlong_from(-1, -1); + EXPECT_EQ((julong)val, UCONST64(0xFFFFFFFFFFFFFFFF)); + EXPECT_EQ(val, CONST64(-1)); + + val = jlong_from(0xABCD, 0xEFEF); + EXPECT_EQ(val, CONST64(0x0000ABCD0000EFEF)); +} From e66ed4d72948a56863f2979b976ef81c0fc43f75 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 2 Sep 2025 09:30:29 +0000 Subject: [PATCH 089/295] 8366666: Bump timeout on StressAsyncUL Reviewed-by: stefank --- test/hotspot/jtreg/runtime/logging/StressAsyncUL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java index e14cad6cc65..2967507fa64 100644 --- a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java @@ -28,7 +28,7 @@ * @requires vm.debug * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver StressAsyncUL + * @run driver/timeout=480 StressAsyncUL */ import jdk.test.lib.process.OutputAnalyzer; From 31847149c1956b23c19a99309982660b4bbdd2d6 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Tue, 2 Sep 2025 11:17:56 +0000 Subject: [PATCH 090/295] 8325766: Extend CertificateBuilder to create trust and end entity certificates programmatically Reviewed-by: mullan, abarashev --- .../HttpsURLConnection/IPIdentities.java | 708 +++--------------- .../https/HttpsURLConnection/TEST.properties | 3 + .../test/lib/security/CertificateBuilder.java | 95 ++- 3 files changed, 202 insertions(+), 604 deletions(-) create mode 100644 test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java index 6ea62526566..9ce71064b54 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java @@ -34,379 +34,41 @@ * @author Xuelei Fan */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; -import java.security.Security; + +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.security.KeyStore; -import java.security.KeyFactory; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.X509Certificate; + import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; import java.math.BigInteger; import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.security.CertificateBuilder; +import jdk.test.lib.security.CertificateBuilder.KeyUsage; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.SerialNumber; +import sun.security.x509.X500Name; -/* - * Certificates and key used in the test. - * - * TLS server certificate: - * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A - * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * publicExponent: 65537 (0x10001) - * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 - * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 - * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f - * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 - * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 - * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * - * - * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 7 (0x7) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:27:57 2008 GMT - * Not After : Aug 25 03:27:57 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1 - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICnzCCAgigAwIBAgIBBzANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3NTdaFw0yODA4MjUwMzI3NTdaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjbjBsMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB - * MA0GCSqGSIb3DQEBBAUAA4GBAFJjItCtCBZcjD69wdqfIbKmRFa6eJAjR6LcoDva - * cKC/sDOLelpspiZ66Zb0Xdv5qQ7QrfOXt3K8QqJKRMdZLF9WfUfy0gJDM32ub91h - * pu+TmcGPs+6RdrAQcuvU1ZDV9X8SMj7BtKaim4d5sqFw1npncKiA5xFn8vOYwdun - * nZif - * -----END CERTIFICATE----- - * - * - * TLS client certificate: - * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * publicExponent: 65537 (0x10001) - * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 - * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 - * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f - * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 - * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd - * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 - * - * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 6 (0x6) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:27:34 2008 GMT - * Not After : Aug 25 03:27:34 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1 - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICnzCCAgigAwIBAgIBBjANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3MzRaFw0yODA4MjUwMzI3MzRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjbjBsMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB - * MA0GCSqGSIb3DQEBBAUAA4GBACjj9PS+W6XOF7toFMwMOv/AemZeBOpcEF1Ei1Hx - * HjvB6EOHkMY8tFm5OPzkiWiK3+s3awpSW0jWdzMYwrQJ3/klMsPDpI7PEuirqwHP - * i5Wyl/vk7jmfWVcBO9MVhPUo4BYl4vS9aj6JA5QbkbkB95LOgT/BowY0WmHeVsXC - * I9aw - * -----END CERTIFICATE----- - * - * - * - * Trusted CA certificate: - * Certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- - */ +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; public class IPIdentities { - static Map cookies; - ServerSocket ss; /* * ============================================================= @@ -421,208 +83,14 @@ public class IPIdentities { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - static String trusedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + - "-----END CERTIFICATE-----"; + static X509Certificate trustedCert; - static String serverCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICnzCCAgigAwIBAgIBBzANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3NTdaFw0yODA4MjUwMzI3NTdaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjbjBsMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB\n" + - "MA0GCSqGSIb3DQEBBAUAA4GBAFJjItCtCBZcjD69wdqfIbKmRFa6eJAjR6LcoDva\n" + - "cKC/sDOLelpspiZ66Zb0Xdv5qQ7QrfOXt3K8QqJKRMdZLF9WfUfy0gJDM32ub91h\n" + - "pu+TmcGPs+6RdrAQcuvU1ZDV9X8SMj7BtKaim4d5sqFw1npncKiA5xFn8vOYwdun\n" + - "nZif\n" + - "-----END CERTIFICATE-----"; + static X509Certificate serverCert; - static String clientCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICnzCCAgigAwIBAgIBBjANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3MzRaFw0yODA4MjUwMzI3MzRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjbjBsMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB\n" + - "MA0GCSqGSIb3DQEBBAUAA4GBACjj9PS+W6XOF7toFMwMOv/AemZeBOpcEF1Ei1Hx\n" + - "HjvB6EOHkMY8tFm5OPzkiWiK3+s3awpSW0jWdzMYwrQJ3/klMsPDpI7PEuirqwHP\n" + - "i5Wyl/vk7jmfWVcBO9MVhPUo4BYl4vS9aj6JA5QbkbkB95LOgT/BowY0WmHeVsXC\n" + - "I9aw\n" + - "-----END CERTIFICATE-----"; + static X509Certificate clientCert; - - static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 - }; - - static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 - }; - - static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 - }; - - static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b - }; + static KeyPair serverKeys; + static KeyPair clientKeys; static char passphrase[] = "passphrase".toCharArray(); @@ -639,7 +107,7 @@ public class IPIdentities { /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); private SSLServerSocket sslServerSocket = null; @@ -650,8 +118,8 @@ public class IPIdentities { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = getSSLContext(trusedCertStr, serverCertStr, - serverModulus, serverPrivateExponent, passphrase); + SSLContext context = getSSLContext(trustedCert, serverCert, + serverKeys, passphrase); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); // doClientSide() connects to the loopback address @@ -706,8 +174,8 @@ public class IPIdentities { void doClientSide() throws Exception { SSLContext reservedSSLContext = SSLContext.getDefault(); try { - SSLContext context = getSSLContext(trusedCertStr, clientCertStr, - clientModulus, clientPrivateExponent, passphrase); + SSLContext context = getSSLContext(trustedCert, clientCert, + clientKeys, passphrase); SSLContext.setDefault(context); /* @@ -755,6 +223,65 @@ public class IPIdentities { volatile Exception serverException = null; volatile Exception clientException = null; + private static X509Certificate createTrustedCert(KeyPair caKeys) throws Exception { + SecureRandom random = new SecureRandom(); + + KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); + GeneralNames gns = new GeneralNames(); + GeneralName name = new GeneralName(new X500Name( + "O=Some-Org, L=Some-City, ST=Some-State, C=US")); + gns.add(name); + BigInteger serialNumber = BigInteger.valueOf(random.nextLong(1000000)+1); + return CertificateBuilder.newCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .setSerialNumber(serialNumber) + .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, + new SerialNumber(serialNumber))) + .addBasicConstraintsExt(true, true, -1) + .setOneHourValidity() + .build(null, caKeys.getPrivate(), "MD5WithRSA"); + } + + private static void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + KeyPair caKeys = kpg.generateKeyPair(); + serverKeys = kpg.generateKeyPair(); + clientKeys = kpg.generateKeyPair(); + + trustedCert = createTrustedCert(caKeys); + if (debug) { + System.out.println("----------- Trusted Cert -----------"); + CertificateBuilder.printCertificate(trustedCert, System.out); + } + + serverCert = CertificateBuilder.newCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + serverKeys.getPublic(), caKeys.getPublic(), + KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NONREPUDIATION, KeyUsage.KEY_ENCIPHERMENT) + .addBasicConstraintsExt(false, false, -1) + .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1")) + .setOneHourValidity() + .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); + if (debug) { + System.out.println("----------- Server Cert -----------"); + CertificateBuilder.printCertificate(serverCert, System.out); + } + + clientCert = CertificateBuilder.newCertificateBuilder( + "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US", + clientKeys.getPublic(), caKeys.getPublic(), + KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NONREPUDIATION, KeyUsage.KEY_ENCIPHERMENT) + .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1")) + .addBasicConstraintsExt(false, false, -1) + .setOneHourValidity() + .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); + if (debug) { + System.out.println("----------- Client Cert -----------"); + CertificateBuilder.printCertificate(clientCert, System.out); + } + } + public static void main(String args[]) throws Exception { // MD5 is used in this test case, don't disable MD5 algorithm. Security.setProperty("jdk.certpath.disabledAlgorithms", @@ -762,8 +289,11 @@ public class IPIdentities { Security.setProperty("jdk.tls.disabledAlgorithms", "SSLv3, RC4, DH keySize < 768"); - if (debug) + if (debug) { System.setProperty("javax.net.debug", "all"); + } + + setupCertificates(); /* * Start the tests. @@ -855,45 +385,23 @@ public class IPIdentities { } // get the ssl context - private static SSLContext getSSLContext(String trusedCertStr, - String keyCertStr, byte[] modulus, - byte[] privateExponent, char[] passphrase) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); + private static SSLContext getSSLContext(X509Certificate trustedCert, + X509Certificate keyCert, KeyPair key, char[] passphrase) throws Exception { // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); + KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(null, null); // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trusedCert); - - if (keyCertStr != null) { - // generate the private key. - RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec( - new BigInteger(modulus), - new BigInteger(privateExponent)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); + ks.setCertificateEntry("RSA Export Signer", trustedCert); + if (keyCert != null) { Certificate[] chain = new Certificate[2]; chain[0] = keyCert; - chain[1] = trusedCert; + chain[1] = trustedCert; // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); + ks.setKeyEntry("Whatever", key.getPrivate(), passphrase, chain); } // create SSL context @@ -902,7 +410,7 @@ public class IPIdentities { SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - if (keyCertStr != null) { + if (keyCert != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passphrase); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties new file mode 100644 index 00000000000..e1ed216f21d --- /dev/null +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties @@ -0,0 +1,3 @@ +modules = \ + java.base/sun.security.util \ + java.base/sun.security.x509 diff --git a/test/lib/jdk/test/lib/security/CertificateBuilder.java b/test/lib/jdk/test/lib/security/CertificateBuilder.java index 857d585f029..e5044d46b0f 100644 --- a/test/lib/jdk/test/lib/security/CertificateBuilder.java +++ b/test/lib/jdk/test/lib/security/CertificateBuilder.java @@ -24,12 +24,10 @@ package jdk.test.lib.security; import java.io.*; +import java.security.cert.*; +import java.security.cert.Extension; import java.util.*; import java.security.*; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.Extension; import java.time.temporal.ChronoUnit; import java.time.Instant; import javax.security.auth.x500.X500Principal; @@ -56,6 +54,7 @@ import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.URIName; import sun.security.x509.KeyIdentifier; + /** * Helper class that builds and signs X.509 certificates. * @@ -100,6 +99,89 @@ public class CertificateBuilder { private byte[] tbsCertBytes; private byte[] signatureBytes; + public enum KeyUsage { + DIGITAL_SIGNATURE, + NONREPUDIATION, + KEY_ENCIPHERMENT, + DATA_ENCIPHERMENT, + KEY_AGREEMENT, + KEY_CERT_SIGN, + CRL_SIGN, + ENCIPHER_ONLY, + DECIPHER_ONLY; + } + + /** + * Create a new CertificateBuilder instance. This method sets the subject name, + * public key, authority key id, and serial number. + * + * @param subjectName entity associated with the public key + * @param publicKey the entity's public key + * @param caKey public key of certificate signer + * @param keyUsages list of key uses + * @return + * @throws CertificateException + * @throws IOException + */ + public static CertificateBuilder newCertificateBuilder(String subjectName, + PublicKey publicKey, PublicKey caKey, KeyUsage... keyUsages) + throws CertificateException, IOException { + SecureRandom random = new SecureRandom(); + + boolean [] keyUsage = new boolean[KeyUsage.values().length]; + for (KeyUsage ku : keyUsages) { + keyUsage[ku.ordinal()] = true; + } + + CertificateBuilder builder = new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setSerialNumber(BigInteger.valueOf(random.nextLong(1000000)+1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey); + if (keyUsages.length != 0) { + builder.addKeyUsageExt(keyUsage); + } + return builder; + } + + /** + * Create a Subject Alternative Name extension for the given DNS name + * @param critical Sets the extension to critical or non-critical + * @param dnsName DNS name to use in the extension + * @throws IOException + */ + public static SubjectAlternativeNameExtension createDNSSubjectAltNameExt( + boolean critical, String dnsName) throws IOException { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new DNSName(dnsName))); + return new SubjectAlternativeNameExtension(critical, gns); + } + + /** + * Create a Subject Alternative Name extension for the given IP address + * @param critical Sets the extension to critical or non-critical + * @param ipAddress IP address to use in the extension + * @throws IOException + */ + public static SubjectAlternativeNameExtension createIPSubjectAltNameExt( + boolean critical, String ipAddress) throws IOException { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new IPAddressName(ipAddress))); + return new SubjectAlternativeNameExtension(critical, gns); + } + + public static void printCertificate(X509Certificate certificate, PrintStream ps) { + try { + Base64.Encoder encoder = Base64.getEncoder(); + ps.println("-----BEGIN CERTIFICATE-----"); + ps.println(encoder.encodeToString(certificate.getEncoded())); + ps.println("-----END CERTIFICATE-----"); + } catch (CertificateEncodingException exc) { + exc.printStackTrace(ps); + } + } + /** * Default constructor for a {@code CertificateBuilder} object. * @@ -177,6 +259,11 @@ public class CertificateBuilder { return setNotBefore(nbDate).setNotAfter(naDate); } + public CertificateBuilder setOneHourValidity() { + return setNotBefore(Date.from(Instant.now().minus(5, ChronoUnit.MINUTES))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))); + } + /** * Set the serial number on the certificate. * From eea50fbc1b24710b18eff4b59dc90dee3736cd95 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 2 Sep 2025 12:42:46 +0000 Subject: [PATCH 091/295] 8356439: Rename JavaLangAccess::*NoRepl methods Reviewed-by: alanb, liach, rriggs --- .../share/classes/java/lang/String.java | 332 ++++++++++++------ .../share/classes/java/lang/System.java | 16 +- .../share/classes/java/nio/file/Files.java | 4 +- .../share/classes/java/util/zip/ZipCoder.java | 12 +- .../jdk/internal/access/JavaLangAccess.java | 24 +- .../unix/classes/sun/nio/fs/UnixPath.java | 2 +- .../{NoReplTest.java => OrThrowTest.java} | 20 +- 7 files changed, 265 insertions(+), 145 deletions(-) rename test/jdk/java/lang/String/{NoReplTest.java => OrThrowTest.java} (79%) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 15b8e98369e..8acb8d8514b 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -604,14 +604,14 @@ public final class String } byte[] utf16 = StringUTF16.newBytesFor(length); StringLatin1.inflate(latin1, 0, utf16, 0, dp); - dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp, true); + dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp); if (dp != length) { utf16 = Arrays.copyOf(utf16, dp << 1); } return new String(utf16, UTF16); } else { // !COMPACT_STRINGS byte[] dst = StringUTF16.newBytesFor(length); - int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } @@ -689,12 +689,24 @@ public final class String } /* - * Throws iae, instead of replacing, if malformed or unmappable. - * The byte array can be exclusively used to construct - * the string and is not modified or used for any other purpose. + * {@return a new string by decoding from the given UTF-8 bytes array} + *

        + * WARNING: The caller of this method is assumed to have relinquished + * and transferred the ownership of the byte array. It can thus be + * exclusively used to construct the {@code String}. + * + * @param bytes byte array containing UTF-8 encoded characters + * @param offset the index of the first byte to decode + * @param length the number of bytes to decode + * @throws NullPointerException If {@code bytes} is null + * @throws StringIndexOutOfBoundsException If {@code offset} is negative, + * {@code length} is negative, or {@code offset} is greater than + * {@code bytes.length - length} + * @throws CharacterCodingException for malformed input or unmappable characters */ - private static String newStringUTF8NoRepl(byte[] bytes, int offset, int length) { - checkBoundsOffCount(offset, length, bytes.length); + private static String newStringUTF8OrThrow(byte[] bytes, int offset, int length) + throws CharacterCodingException { + checkBoundsOffCount(offset, length, bytes.length); // Implicit null check on `bytes` if (length == 0) { return ""; } @@ -745,10 +757,10 @@ public final class String StringLatin1.inflate(dst, 0, buf, 0, dp); dst = buf; } - dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, sl, dst, dp); } else { // !COMPACT_STRINGS dst = StringUTF16.newBytesFor(length); - dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, offset + length, dst, 0); } if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); @@ -784,26 +796,13 @@ public final class String * * @throws CharacterCodingException for malformed input or unmappable characters */ - static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { - try { - return newStringNoRepl1(src, cs); - } catch (IllegalArgumentException e) { - //newStringNoRepl1 throws IAE with MalformedInputException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof MalformedInputException mie) { - throw mie; - } - throw (CharacterCodingException)cause; - } - } - - private static String newStringNoRepl1(byte[] src, Charset cs) { + static String newStringOrThrow(byte[] src, Charset cs) throws CharacterCodingException { int len = src.length; if (len == 0) { return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8NoRepl(src, 0, src.length); + return newStringUTF8OrThrow(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -816,7 +815,7 @@ public final class String return new String(src, LATIN1); return new String(StringLatin1.inflate(src, 0, src.length), UTF16); } else { - throwMalformed(src); + throw malformedASCII(src); } } @@ -831,13 +830,7 @@ public final class String } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; - int caLen; - try { - caLen = decodeWithDecoder(cd, ca, src, 0, src.length); - } catch (CharacterCodingException x) { - // throw via IAE - throw new IllegalArgumentException(x); - } + int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); byte coder = StringUTF16.coderFromArrayLen(val, caLen); @@ -874,7 +867,7 @@ public final class String private static byte[] encode(Charset cs, byte coder, byte[] val) { if (cs == UTF_8.INSTANCE) { - return encodeUTF8(coder, val, true); + return encodeUTF8(coder, val); } if (cs == ISO_8859_1.INSTANCE) { return encode8859_1(coder, val); @@ -882,13 +875,30 @@ public final class String if (cs == US_ASCII.INSTANCE) { return encodeASCII(coder, val); } - return encodeWithEncoder(cs, coder, val, true); + return encodeWithEncoder(cs, coder, val, null); } - private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with the encoder of {@code + * cs}} + * + * @param cs a charset to obtain the encoder from + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeWithEncoder( + Charset cs, byte coder, byte[] val, Class exClass) + throws E { CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); + boolean doReplace = exClass == null; // fastpath with ArrayEncoder implies `doReplace`. if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible @@ -930,7 +940,9 @@ public final class String cr.throwException(); } catch (CharacterCodingException x) { if (!doReplace) { - throw new IllegalArgumentException(x); + @SuppressWarnings("unchecked") + E cce = (E) x; + throw cce; } else { throw new Error(x); } @@ -938,60 +950,69 @@ public final class String return trimArray(ba, bb.position()); } - /* - * Throws iae, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} + * + * @param s the string to encode + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesUTF8NoRepl(String s) { - return encodeUTF8(s.coder(), s.value(), false); + static byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return encodeUTF8OrThrow(s.coder(), s.value()); // Implicit null check on `s` } private static boolean isASCII(byte[] src) { return !StringCoding.hasNegatives(src, 0, src.length); } - /* - * Throws CCE, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} + *

        + * WARNING: This method returns the {@code byte[]} backing the provided + * {@code String}, if the input is ASCII. Hence, the returned byte array + * must not be modified. + * + * @param s the string to encode + * @param cs the charset + * @throws NullPointerException If {@code s} or {@code cs} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - try { - return getBytesNoRepl1(s, cs); - } catch (IllegalArgumentException e) { - //getBytesNoRepl1 throws IAE with UnmappableCharacterException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof UnmappableCharacterException) { - throw (UnmappableCharacterException)cause; - } - throw (CharacterCodingException)cause; - } - } - - private static byte[] getBytesNoRepl1(String s, Charset cs) { - byte[] val = s.value(); + static byte[] getBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + Objects.requireNonNull(cs); + byte[] val = s.value(); // Implicit null check on `s` byte coder = s.coder(); if (cs == UTF_8.INSTANCE) { if (coder == LATIN1 && isASCII(val)) { return val; } - return encodeUTF8(coder, val, false); + return encodeUTF8OrThrow(coder, val); } if (cs == ISO_8859_1.INSTANCE) { if (coder == LATIN1) { return val; } - return encode8859_1(coder, val, false); + return encode8859_1OrThrow(coder, val); } if (cs == US_ASCII.INSTANCE) { if (coder == LATIN1) { if (isASCII(val)) { return val; } else { - throwUnmappable(val); + throw unmappableASCII(val); } } } - return encodeWithEncoder(cs, coder, val, false); + return encodeWithEncoder(cs, coder, val, CharacterCodingException.class); } + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with US-ASCII} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + */ private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { int positives = StringCoding.countPositives(val, 0, val.length); @@ -1031,10 +1052,26 @@ public final class String } private static byte[] encode8859_1(byte coder, byte[] val) { - return encode8859_1(coder, val, true); + return encode8859_1(coder, val, null); } - private static byte[] encode8859_1(byte coder, byte[] val, boolean doReplace) { + private static byte[] encode8859_1OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encode8859_1(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with ISO-8859-1} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encode8859_1(byte coder, byte[] val, Class exClass) throws E { if (coder == LATIN1) { return val.clone(); } @@ -1048,8 +1085,8 @@ public final class String sp = sp + ret; dp = dp + ret; if (ret != len) { - if (!doReplace) { - throwUnmappable(sp); + if (exClass != null) { + throw String.unmappableCharacterException(sp); } char c = StringUTF16.getChar(val, sp++); if (Character.isHighSurrogate(c) && sp < sl && @@ -1143,7 +1180,26 @@ public final class String ((byte) 0x80 << 0)))); } - private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp, boolean doReplace) { + private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp) { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, null); + } + + private static int decodeUTF8_UTF16OrThrow( + byte[] src, int sp, int sl, byte[] dst, int dp) + throws MalformedInputException { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, MalformedInputException.class); + } + + /** + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static int decodeUTF8_UTF16( + byte[] src, int sp, int sl, byte[] dst, int dp, Class exClass) + throws E { while (sp < sl) { int b1 = src[sp++]; if (b1 >= 0) { @@ -1152,8 +1208,8 @@ public final class String if (sp < sl) { int b2 = src[sp++]; if (isNotContinuation(b2)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); sp--; @@ -1162,8 +1218,8 @@ public final class String } continue; } - if (!doReplace) { - throwMalformed(sp, 1); // underflow() + if (exClass != null) { + throw String.malformedInputException(sp, 1); // underflow() } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1172,8 +1228,8 @@ public final class String int b2 = src[sp++]; int b3 = src[sp++]; if (isMalformed3(b1, b2, b3)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); sp -= 3; @@ -1181,8 +1237,8 @@ public final class String } else { char c = decode3(b1, b2, b3); if (Character.isSurrogate(c)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); } else { @@ -1192,14 +1248,14 @@ public final class String continue; } if (sp < sl && isMalformed3_2(b1, src[sp])) { - if (!doReplace) { - throwMalformed(sp - 1, 2); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 2); } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp, 1); + if (exClass != null) { + throw String.malformedInputException(sp, 1); } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1211,8 +1267,8 @@ public final class String int uc = decode4(b1, b2, b3, b4); if (isMalformed4(b2, b3, b4) || !Character.isSupplementaryCodePoint(uc)) { // shortest form check - if (!doReplace) { - throwMalformed(sp - 4, 4); + if (exClass != null) { + throw String.malformedInputException(sp - 4, 4); } StringUTF16.putChar(dst, dp++, REPL); sp -= 4; @@ -1225,14 +1281,14 @@ public final class String } b1 &= 0xff; if (b1 > 0xf4 || sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); // or 2 + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); // or 2 } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } sp++; StringUTF16.putChar(dst, dp++, REPL); @@ -1241,8 +1297,8 @@ public final class String } break; } else { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); } @@ -1284,29 +1340,76 @@ public final class String return 3; } - private static void throwMalformed(int off, int nb) { - String msg = "malformed input off : " + off + ", length : " + nb; - throw new IllegalArgumentException(msg, new MalformedInputException(nb)); + /** + * {@return a new {@link MalformedInputException} for the sub-range denoted + * by specified {@code offset} and {@code length}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E malformedInputException(int offset, int length) throws E { + MalformedInputException mie = new MalformedInputException(length); + String msg = "malformed input offset : " + offset + ", length : " + length; + mie.initCause(new IllegalArgumentException(msg)); + return (E) mie; } - private static void throwMalformed(byte[] val) { + /** + * {@return a new {@link MalformedInputException} for the given malformed + * ASCII string} + */ + private static MalformedInputException malformedASCII(byte[] val) throws MalformedInputException { int dp = StringCoding.countPositives(val, 0, val.length); - throwMalformed(dp, 1); + return malformedInputException(dp, 1); } - private static void throwUnmappable(int off) { - String msg = "malformed input off : " + off + ", length : 1"; - throw new IllegalArgumentException(msg, new UnmappableCharacterException(1)); + /** + * {@return a new {@link UnmappableCharacterException} at given {@code offset}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E unmappableCharacterException(int offset) throws E { + UnmappableCharacterException uce = new UnmappableCharacterException(1); + String msg = "malformed input offset : " + offset + ", length : 1"; + uce.initCause(new IllegalArgumentException(msg, uce)); + return (E) uce; } - private static void throwUnmappable(byte[] val) { + /** + * {@return a new {@link UnmappableCharacterException} for the given + * malformed ASCII string} + */ + private static UnmappableCharacterException unmappableASCII(byte[] val) throws UnmappableCharacterException { int dp = StringCoding.countPositives(val, 0, val.length); - throwUnmappable(dp); + return unmappableCharacterException(dp); } - private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { + private static byte[] encodeUTF8(byte coder, byte[] val) { + return encodeUTF8(coder, val, null); + } + + private static byte[] encodeUTF8OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encodeUTF8(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with UTF-8} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8(byte coder, byte[] val, Class exClass) throws E { if (coder == UTF16) { - return encodeUTF8_UTF16(val, doReplace); + return encodeUTF8_UTF16(val, exClass); } int positives = StringCoding.countPositives(val, 0, val.length); @@ -1334,13 +1437,24 @@ public final class String return Arrays.copyOf(dst, dp); } - private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * UTF-16, and then encoding the result with UTF-8} + * + * @param val a string byte array encoded with UTF-16 + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8_UTF16(byte[] val, Class exClass) throws E { int dp = 0; int sp = 0; int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; if (allocLen > (long)Integer.MAX_VALUE) { throw new OutOfMemoryError("Required length exceeds implementation limit"); } @@ -1369,10 +1483,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dst[dp++] = '?'; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dst[dp++] = (byte)(0xf0 | ((uc >> 18))); @@ -1396,10 +1510,14 @@ public final class String /** * {@return the exact size required to UTF_8 encode this UTF16 string} - * @param val UTF16 encoded byte array - * @param doReplace true to replace unmappable characters + * + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting discarded. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception */ - private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { + private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { long dp = 0L; int sp = 0; int sl = val.length >> 1; @@ -1418,10 +1536,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dp++; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dp += 4; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index a40c27bbf47..bb1775fbc6b 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2124,6 +2124,7 @@ public final class System { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } + public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } @@ -2132,21 +2133,24 @@ public final class System { return String.newStringWithLatin1Bytes(bytes); } - public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { - return String.newStringNoRepl(bytes, cs); + public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException { + return String.newStringOrThrow(bytes, cs); } + public char uncheckedGetUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } + public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) { StringUTF16.putChar(bytes, index, ch); } - public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - return String.getBytesNoRepl(s, cs); + + public byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + return String.getBytesOrThrow(s, cs); } - public byte[] getBytesUTF8NoRepl(String s) { - return String.getBytesUTF8NoRepl(s); + public byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return String.getBytesUTF8OrThrow(s); } public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index f8278fa2642..80c771f5306 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public final class Files { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.uncheckedNewStringNoRepl(ba, cs); + return JLA.uncheckedNewStringOrThrow(ba, cs); } /** @@ -3362,7 +3362,7 @@ public final class Files { Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesOrThrow(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 8b812eba202..b9906d348e3 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -256,7 +256,7 @@ class ZipCoder { try { // Copy subrange for exclusive use by the string being created byte[] bytes = Arrays.copyOfRange(ba, off, off + length); - return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8); + return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8); } catch (CharacterCodingException cce) { throw new IllegalArgumentException(cce); } @@ -264,7 +264,11 @@ class ZipCoder { @Override byte[] getBytes(String s) { - return JLA.getBytesUTF8NoRepl(s); + try { + return JLA.getBytesUTF8OrThrow(s); + } catch (CharacterCodingException cce) { + throw new IllegalArgumentException(cce); + } } @Override @@ -278,8 +282,6 @@ class ZipCoder { // Non-ASCII, fall back to decoding a String // We avoid using decoder() here since the UTF8ZipCoder is // shared and that decoder is not thread safe. - // We use the JLA.newStringUTF8NoRepl variant to throw - // exceptions eagerly when opening ZipFiles return hash(toString(a, off, len)); } int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0); @@ -296,7 +298,7 @@ class ZipCoder { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index aa5b6e438f5..c7d7c86b932 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,7 +45,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; -import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -332,7 +331,7 @@ public interface JavaLangAccess { /** * Constructs a new {@code String} by decoding the specified byte array - * using the specified {@linkplain java.nio.charset.Charset charset}. + * using the specified {@code Charset}. *

        * WARNING: The caller of this method shall relinquish and transfer the * ownership of the byte array to the callee, since the latter will not @@ -343,25 +342,22 @@ public interface JavaLangAccess { * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes */ - String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * Encode the given string into a sequence of bytes using the specified - * {@linkplain java.nio.charset.Charset charset}. + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} *

        * WARNING: This method returns the {@code byte[]} backing the provided * {@code String}, if the input is ASCII. Hence, the returned byte array * must not be modified. - *

        - * This method throws {@code CharacterCodingException} instead of replacing - * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset - * @return the encoded bytes + * @throws NullPointerException If {@code s} or {@code cs} is null * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException; /** * Get the {@code char} at {@code index} in a {@code byte[]} in internal @@ -387,13 +383,13 @@ public interface JavaLangAccess { void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** - * Encode the given string into a sequence of bytes using utf8. + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} * * @param s the string to encode - * @return the encoded bytes in utf8 - * @throws IllegalArgumentException for malformed surrogates + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - byte[] getBytesUTF8NoRepl(String s); + byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException; /** * Inflated copy from {@code byte[]} to {@code char[]}, as defined by diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 5dfc73f57aa..5a77bb0b935 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -126,7 +126,7 @@ class UnixPath implements Path { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesOrThrow(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/test/jdk/java/lang/String/NoReplTest.java b/test/jdk/java/lang/String/OrThrowTest.java similarity index 79% rename from test/jdk/java/lang/String/NoReplTest.java rename to test/jdk/java/lang/String/OrThrowTest.java index 1817a1ffe73..340a190b4eb 100644 --- a/test/jdk/java/lang/String/NoReplTest.java +++ b/test/jdk/java/lang/String/OrThrowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +24,8 @@ /* * @test * @bug 8286287 8288589 - * @summary Tests for *NoRepl() shared secret methods. - * @run testng NoReplTest + * @summary Tests for *OrThrow() shared secret methods. + * @run testng OrThrowTest * @modules jdk.charsets */ @@ -39,17 +39,17 @@ import static java.nio.charset.StandardCharsets.UTF_16; import org.testng.annotations.Test; @Test -public class NoReplTest { +public class OrThrowTest { private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); /** - * Verifies newStringNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.readString()` method. + * Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.readString()} method. */ @Test - public void newStringNoReplTest() throws IOException { + public void uncheckedNewStringOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try (var fos = Files.newOutputStream(f)) { fos.write(MALFORMED_UTF16); @@ -67,11 +67,11 @@ public class NoReplTest { } /** - * Verifies getBytesNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.writeString()` method. + * Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.writeString()} method. */ @Test - public void getBytesNoReplTest() throws IOException { + public void uncheckedGetBytesOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try { Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); From 1feb9bd55946cad8a37745b0c9ceef16f408afd8 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Sep 2025 12:46:59 +0000 Subject: [PATCH 092/295] 8365557: Parallel: Refactor ParallelScavengeHeap::mem_allocate_work Reviewed-by: tschatzl, iwalulya --- .../gc/parallel/parallelScavengeHeap.cpp | 50 +++++++------------ src/hotspot/share/gc/parallel/psOldGen.hpp | 3 +- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 45c364ab35a..3b530895eb1 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -279,17 +279,23 @@ HeapWord* ParallelScavengeHeap::mem_allocate(size_t size, HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab, bool* gc_overhead_limit_was_exceeded) { - { + for (uint loop_count = 0; /* empty */; ++loop_count) { + // Try young-gen first. HeapWord* result = young_gen()->allocate(size); if (result != nullptr) { return result; } - } - uint loop_count = 0; - uint gc_count = 0; + // Try allocating from the old gen for non-TLAB in certain scenarios. + if (!is_tlab) { + if (!should_alloc_in_eden(size) || _is_heap_almost_full) { + result = old_gen()->cas_allocate_noexpand(size); + if (result != nullptr) { + return result; + } + } + } - while (true) { // We don't want to have multiple collections for a single filled generation. // To prevent this, each thread tracks the total_collections() value, and if // the count has changed, does not do a new collection. @@ -301,49 +307,31 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, // the collection count has already changed. To prevent duplicate collections, // The policy MUST attempt allocations during the same period it reads the // total_collections() value! + uint gc_count; { MutexLocker ml(Heap_lock); gc_count = total_collections(); - - HeapWord* result = young_gen()->allocate(size); - if (result != nullptr) { - return result; - } - - // Try allocating from the old gen for non-TLAB in certain scenarios. - if (!is_tlab) { - if (!should_alloc_in_eden(size) || _is_heap_almost_full) { - result = old_gen()->cas_allocate_noexpand(size); - if (result != nullptr) { - return result; - } - } - } } { VM_ParallelCollectForAllocation op(size, is_tlab, gc_count); VMThread::execute(&op); - // Did the VM operation execute? If so, return the result directly. - // This prevents us from looping until time out on requests that can - // not be satisfied. if (op.gc_succeeded()) { assert(is_in_or_null(op.result()), "result not in heap"); - return op.result(); } - // Was the gc-overhead reached inside the safepoint? If so, this mutator should return null as well for global consistency. - if (_gc_overhead_counter >= GCOverheadLimitThreshold) { - return nullptr; - } } - loop_count++; + // Was the gc-overhead reached inside the safepoint? If so, this mutator + // should return null as well for global consistency. + if (_gc_overhead_counter >= GCOverheadLimitThreshold) { + return nullptr; + } + if ((QueuedAllocationWarningCount > 0) && (loop_count % QueuedAllocationWarningCount == 0)) { - log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count); - log_warning(gc)("\tsize=%zu", size); + log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times, size=%zu", loop_count, size); } } } diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index 23fde1f2fe0..77ae5510b31 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -108,7 +108,7 @@ class PSOldGen : public CHeapObj { void shrink(size_t bytes); - // Invoked by mutators and GC-workers. + // Used by GC-workers during GC or for CDS at startup. HeapWord* allocate(size_t word_size) { HeapWord* res; do { @@ -120,7 +120,6 @@ class PSOldGen : public CHeapObj { // Invoked by mutators before attempting GC. HeapWord* cas_allocate_noexpand(size_t word_size) { - assert_locked_or_safepoint(Heap_lock); HeapWord* res = object_space()->cas_allocate(word_size); if (res != nullptr) { _start_array->update_for_block(res, res + word_size); From 710354369e0131e900afc4ced706a9ed0e23ab9c Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Sep 2025 13:09:33 +0000 Subject: [PATCH 093/295] 8366063: Parallel: Refactor copy_unmarked_to_survivor_space Reviewed-by: tschatzl, iwalulya --- .../share/gc/parallel/psPromotionManager.hpp | 7 + .../gc/parallel/psPromotionManager.inline.hpp | 148 ++++++++++-------- 2 files changed, 87 insertions(+), 68 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index 78bb7dde66a..f1169c8ad63 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -113,6 +113,13 @@ class PSPromotionManager { template oop copy_unmarked_to_survivor_space(oop o, markWord m); + inline HeapWord* allocate_in_young_gen(Klass* klass, + size_t obj_size, + uint age); + inline HeapWord* allocate_in_old_gen(Klass* klass, + size_t obj_size, + uint age); + public: // Static static void initialize(); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 451a7dae189..6154abf1b1c 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -153,6 +153,80 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { } } +inline HeapWord* PSPromotionManager::allocate_in_young_gen(Klass* klass, + size_t obj_size, + uint age) { + HeapWord* result = _young_lab.allocate(obj_size); + if (result != nullptr) { + return result; + } + if (_young_gen_is_full) { + return nullptr; + } + // Do we allocate directly, or flush and refill? + if (obj_size > (YoungPLABSize / 2)) { + // Allocate this object directly + result = young_space()->cas_allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, false, nullptr); + } else { + // Flush and fill + _young_lab.flush(); + + HeapWord* lab_base = young_space()->cas_allocate(YoungPLABSize); + if (lab_base != nullptr) { + _young_lab.initialize(MemRegion(lab_base, YoungPLABSize)); + // Try the young lab allocation again. + result = _young_lab.allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, false, &_young_lab); + } else { + _young_gen_is_full = true; + } + } + if (result == nullptr && !_young_gen_is_full && !_young_gen_has_alloc_failure) { + _young_gen_has_alloc_failure = true; + } + return result; +} + +inline HeapWord* PSPromotionManager::allocate_in_old_gen(Klass* klass, + size_t obj_size, + uint age) { +#ifndef PRODUCT + if (ParallelScavengeHeap::heap()->promotion_should_fail()) { + return nullptr; + } +#endif // #ifndef PRODUCT + + HeapWord* result = _old_lab.allocate(obj_size); + if (result != nullptr) { + return result; + } + if (_old_gen_is_full) { + return nullptr; + } + // Do we allocate directly, or flush and refill? + if (obj_size > (OldPLABSize / 2)) { + // Allocate this object directly + result = old_gen()->allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, true, nullptr); + } else { + // Flush and fill + _old_lab.flush(); + + HeapWord* lab_base = old_gen()->allocate(OldPLABSize); + if (lab_base != nullptr) { + _old_lab.initialize(MemRegion(lab_base, OldPLABSize)); + // Try the old lab allocation again. + result = _old_lab.allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, true, &_old_lab); + } + } + if (result == nullptr) { + _old_gen_is_full = true; + } + return result; +} + // // This method is pretty bulky. It would be nice to split it up // into smaller submethods, but we need to be careful not to hurt @@ -186,77 +260,17 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, if (!promote_immediately) { // Try allocating obj in to-space (unless too old) if (age < PSScavenge::tenuring_threshold()) { - new_obj = cast_to_oop(_young_lab.allocate(new_obj_size)); - if (new_obj == nullptr && !_young_gen_is_full) { - // Do we allocate directly, or flush and refill? - if (new_obj_size > (YoungPLABSize / 2)) { - // Allocate this object directly - new_obj = cast_to_oop(young_space()->cas_allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, false, nullptr); - } else { - // Flush and fill - _young_lab.flush(); - - HeapWord* lab_base = young_space()->cas_allocate(YoungPLABSize); - if (lab_base != nullptr) { - _young_lab.initialize(MemRegion(lab_base, YoungPLABSize)); - // Try the young lab allocation again. - new_obj = cast_to_oop(_young_lab.allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, false, &_young_lab); - } else { - _young_gen_is_full = true; - } - } - if (new_obj == nullptr && !_young_gen_is_full && !_young_gen_has_alloc_failure) { - _young_gen_has_alloc_failure = true; - } - } + new_obj = cast_to_oop(allocate_in_young_gen(klass, new_obj_size, age)); } } // Otherwise try allocating obj tenured if (new_obj == nullptr) { -#ifndef PRODUCT - if (ParallelScavengeHeap::heap()->promotion_should_fail()) { + new_obj = cast_to_oop(allocate_in_old_gen(klass, new_obj_size, age)); + if (new_obj == nullptr) { return oop_promotion_failed(o, test_mark); } -#endif // #ifndef PRODUCT - - new_obj = cast_to_oop(_old_lab.allocate(new_obj_size)); new_obj_is_tenured = true; - - if (new_obj == nullptr) { - if (!_old_gen_is_full) { - // Do we allocate directly, or flush and refill? - if (new_obj_size > (OldPLABSize / 2)) { - // Allocate this object directly - new_obj = cast_to_oop(old_gen()->allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, true, nullptr); - } else { - // Flush and fill - _old_lab.flush(); - - HeapWord* lab_base = old_gen()->allocate(OldPLABSize); - if(lab_base != nullptr) { - _old_lab.initialize(MemRegion(lab_base, OldPLABSize)); - // Try the old lab allocation again. - new_obj = cast_to_oop(_old_lab.allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, true, &_old_lab); - } - } - } - - // This is the promotion failed test, and code handling. - // The code belongs here for two reasons. It is slightly - // different than the code below, and cannot share the - // CAS testing code. Keeping the code here also minimizes - // the impact on the common case fast path code. - - if (new_obj == nullptr) { - _old_gen_is_full = true; - return oop_promotion_failed(o, test_mark); - } - } } assert(new_obj != nullptr, "allocation should have succeeded"); @@ -287,17 +301,16 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, // 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. - // So, the is->objArray() test would be very infrequent. + // So, the objArray test would be very infrequent. if (new_obj_size > _min_array_size_for_chunking && - new_obj->is_objArray() && + klass->is_objArray_klass() && PSChunkLargeArrays) { push_objArray(o, new_obj); } else { // we'll just push its contents push_contents(new_obj); - if (StringDedup::is_enabled() && - java_lang_String::is_instance(new_obj) && + if (StringDedup::is_enabled_string(klass) && psStringDedup::is_candidate_from_evacuation(new_obj, new_obj_is_tenured)) { _string_dedup_requests.add(o); } @@ -305,7 +318,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, return new_obj; } else { // We lost, someone else "owns" this object. - assert(o->is_forwarded(), "Object must be forwarded if the cas failed."); assert(o->forwardee() == forwardee, "invariant"); From a029245a4e1f04052fa0f0a5af16ae0e770bd822 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 2 Sep 2025 13:25:32 +0000 Subject: [PATCH 094/295] 8365983: Tests should throw SkippedException when SCTP not supported Reviewed-by: jpai --- test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java | 15 ++++++++------- .../nio/sctp/SctpChannel/CloseDescriptors.java | 6 ++++-- .../jdk/com/sun/nio/sctp/SctpChannel/CommUp.java | 15 ++++++++------- .../com/sun/nio/sctp/SctpChannel/Connect.java | 13 +++++++------ .../com/sun/nio/sctp/SctpChannel/Receive.java | 16 ++++++++-------- .../nio/sctp/SctpChannel/ReceiveIntoDirect.java | 15 ++++++++------- test/jdk/com/sun/nio/sctp/SctpChannel/Send.java | 15 ++++++++------- .../com/sun/nio/sctp/SctpChannel/Shutdown.java | 15 ++++++++------- .../nio/sctp/SctpChannel/SocketOptionTests.java | 15 ++++++++------- .../sun/nio/sctp/SctpMultiChannel/Branch.java | 15 ++++++++------- .../sctp/SctpMultiChannel/CloseDescriptors.java | 13 ++++++------- .../com/sun/nio/sctp/SctpMultiChannel/Send.java | 15 ++++++++------- .../nio/sctp/SctpMultiChannel/SendFailed.java | 15 ++++++++------- .../sctp/SctpMultiChannel/SocketOptionTests.java | 15 ++++++++------- .../sun/nio/sctp/SctpServerChannel/Accept.java | 15 ++++++++------- .../SctpServerChannel/NonBlockingAccept.java | 13 +++++++------ 16 files changed, 120 insertions(+), 106 deletions(-) diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java index 027f31695ae..ff5ca00846c 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,18 +49,14 @@ import com.sun.nio.sctp.SctpServerChannel; import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; +import jtreg.SkippedException; + /** * Tests bind, bindAddress, unbindAddress, getLocalAddress, and * getAllLocalAddresses. */ public class Bind { void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - /* Simply bind tests */ testBind(); @@ -341,6 +338,10 @@ public class Bind { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java index c68abd7a36c..5d62b88f23e 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java @@ -46,6 +46,8 @@ import java.util.Optional; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpServerChannel; +import jtreg.SkippedException; + public class CloseDescriptors { private static Selector selector; private static final int LOOP = 10; @@ -55,7 +57,7 @@ public class CloseDescriptors { public static void main(String[] args) throws Exception { if (!Util.isSCTPSupported()) { - throw new jtreg.SkippedException("SCTP protocol is not supported"); + throw new SkippedException("SCTP protocol is not supported"); } List lsofDirs = List.of("/usr/bin", "/usr/sbin"); @@ -64,7 +66,7 @@ public class CloseDescriptors { .filter(f -> Files.isExecutable(f)) .findFirst(); if (!lsof.isPresent()) { - throw new jtreg.SkippedException("Cannot locate lsof in " + lsofDirs); + throw new SkippedException("Cannot locate lsof in " + lsofDirs); } try (ServerSocket ss = new ServerSocket(0)) { diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java index 8cbe034b00d..320e556f800 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 6863110 + * @library /test/lib * @summary Newly connected/accepted SctpChannel should fire OP_READ if registered with a Selector * @author chegar */ @@ -49,6 +50,8 @@ import static java.lang.System.err; import static java.nio.channels.SelectionKey.OP_CONNECT; import static java.nio.channels.SelectionKey.OP_READ; +import jtreg.SkippedException; + public class CommUp { static CountDownLatch acceptLatch = new CountDownLatch(1); static final int TIMEOUT = 10000; @@ -61,12 +64,6 @@ public class CommUp { void test(String[] args) { SocketAddress address = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -355,6 +352,10 @@ public class CommUp { void sleep(long millis) { try { Thread.currentThread().sleep(millis); } catch(InterruptedException ie) { unexpected(ie); }} public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java index b73db200ee2..79b9453a595 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar * @run main/timeout=480 Connect @@ -44,6 +45,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + /** * Tests connect, finishConnect, isConnectionPending, * getRemoteAddresses and association. @@ -51,12 +54,6 @@ import static java.lang.System.err; public class Connect { void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - doTest(); } @@ -236,6 +233,10 @@ public class Connect { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java index 23005bbf849..48eb413a9ca 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,6 +49,8 @@ import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Receive { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -61,13 +64,6 @@ public class Receive { SocketAddress address = null; Server server; - - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -349,6 +345,10 @@ public class Receive { void debug(String message) {if(debug) { System.out.println(Thread.currentThread() + " " + message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java b/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java index e7b23d0aaed..48d89c34ca4 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 8034181 + * @library /test/lib * @summary SIGBUS in SctpChannelImpl receive * @author chegar */ @@ -45,6 +46,8 @@ import static java.lang.System.out; import static java.lang.System.err; import static java.nio.charset.StandardCharsets.US_ASCII; +import jtreg.SkippedException; + public class ReceiveIntoDirect { /* suitably small message to NOT overrun small buffers */ final byte[] msgBytes = "Hello".getBytes(US_ASCII); @@ -56,12 +59,6 @@ public class ReceiveIntoDirect { SocketAddress address = null; Server server; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -264,6 +261,10 @@ public class ReceiveIntoDirect { void debug(String message) {if(debug) { System.out.println(Thread.currentThread() + " " + message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java index 93e462a1820..35a28f4eb38 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,6 +49,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Send { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -60,12 +63,6 @@ public class Send { SocketAddress address = null; Server server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -451,6 +448,10 @@ public class Send { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java index 41ba744315c..0891851fe86 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -43,6 +44,8 @@ import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Shutdown { static CountDownLatch finishedLatch = new CountDownLatch(1); static CountDownLatch sentLatch = new CountDownLatch(1); @@ -51,12 +54,6 @@ public class Shutdown { SocketAddress address = null; ShutdownServer server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -272,6 +269,10 @@ public class Shutdown { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java b/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java index 052f9999e57..857efbb63f5 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -43,6 +44,8 @@ import java.security.PrivilegedAction; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; import static java.lang.System.out; +import jtreg.SkippedException; + public class SocketOptionTests { final String osName = AccessController.doPrivileged( (PrivilegedAction)() -> System.getProperty("os.name")); @@ -66,12 +69,6 @@ public class SocketOptionTests { } void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - try (SctpChannel sc = SctpChannel.open()) { /* check supported options */ @@ -190,6 +187,10 @@ public class SocketOptionTests { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java index ffd8eb361c3..9beb8c74c3e 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,6 +49,8 @@ import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Branch { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -58,12 +61,6 @@ public class Branch { SocketAddress address = null; Server server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -277,6 +274,10 @@ public class Branch { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java index 08340312532..fdafec80745 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 8269481 + * @library /test/lib * @summary Tests that file descriptors are closed * @requires (os.family == "linux") * @run main/othervm CloseDescriptors @@ -38,6 +39,8 @@ import java.util.Optional; import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.SctpMultiChannel; +import jtreg.SkippedException; + public class CloseDescriptors { private static final int NUM = 5; @@ -46,9 +49,7 @@ public class CloseDescriptors { public static void main(String[] args) throws Exception { if (!Util.isSCTPSupported()) { - System.out.println("SCTP protocol is not supported"); - System.out.println("Test cannot be run"); - return; + throw new SkippedException("SCTP protocol is not supported"); } List lsofDirs = List.of("/usr/bin", "/usr/sbin"); @@ -57,9 +58,7 @@ public class CloseDescriptors { .filter(f -> Files.isExecutable(f)) .findFirst(); if (!lsof.isPresent()) { - System.out.println("Cannot locate lsof in " + lsofDirs); - System.out.println("Test cannot be run"); - return; + throw new SkippedException("Cannot locate lsof in " + lsofDirs); } try (ServerSocket ss = new ServerSocket(0)) { diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java index feb914a410e..8fb551dd8f4 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -42,6 +43,8 @@ import com.sun.nio.sctp.SctpMultiChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Send { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -52,12 +55,6 @@ public class Send { SocketAddress address = null; Server server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -355,6 +352,10 @@ public class Send { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java index 7ebbcfb6079..a64d4d58270 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 8067846 + * @library /test/lib * @summary Test for send failed notification */ @@ -35,6 +36,8 @@ import java.nio.ByteBuffer; import static java.lang.System.out; import static java.nio.ByteBuffer.*; +import jtreg.SkippedException; + public class SendFailed { static final SocketAddress remoteAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 3000); @@ -45,12 +48,6 @@ public class SendFailed { void test(String[] args) throws IOException { SocketAddress address = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - System.out.println("remote address: " + remoteAddress); System.out.println("Note, remote address should not be up"); @@ -186,6 +183,10 @@ public class SendFailed { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message, Object... args) {if(debug) { out.printf(message, args); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java index 2da35d6eda5..3a681884b9a 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -51,6 +52,8 @@ import java.security.PrivilegedAction; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; import static java.lang.System.out; +import jtreg.SkippedException; + public class SocketOptionTests { final String osName = AccessController.doPrivileged( (PrivilegedAction)() -> System.getProperty("os.name")); @@ -74,12 +77,6 @@ public class SocketOptionTests { } void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - try { SctpMultiChannel smc = SctpMultiChannel.open(); @@ -244,6 +241,10 @@ public class SocketOptionTests { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java b/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java index 99d6e26c939..56522a85f6b 100644 --- a/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java +++ b/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -41,6 +42,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Accept { static CountDownLatch acceptLatch = new CountDownLatch(1); static CountDownLatch closeByIntLatch = new CountDownLatch(1); @@ -50,12 +53,6 @@ public class Accept { void test(String[] args) { SocketAddress address = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -262,6 +259,10 @@ public class Accept { void join(Thread thread, long millis) { try { thread.join(millis); } catch(InterruptedException ie) { unexpected(ie); }} public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java index 6d62aa6c154..abf35bf779d 100644 --- a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java +++ b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar * @run main/timeout=480 NonBlockingAccept @@ -43,6 +44,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class NonBlockingAccept { static CountDownLatch acceptLatch = new CountDownLatch(1); static final int SEL_TIMEOUT = 10000; @@ -52,12 +55,6 @@ public class NonBlockingAccept { SocketAddress address = null; NonblockingServer server; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -219,6 +216,10 @@ public class NonBlockingAccept { void sleep(long millis) { try { Thread.currentThread().sleep(millis); } catch(InterruptedException ie) { unexpected(ie); }} public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} From 444a8fa14e8ab016b8aae018054c5dc1eb843fee Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 2 Sep 2025 14:54:50 +0000 Subject: [PATCH 095/295] 8365501: Remove special AdapterHandlerEntry for abstract methods Reviewed-by: kvn, adinn --- src/hotspot/share/cds/archiveBuilder.cpp | 7 +---- src/hotspot/share/oops/method.cpp | 19 ++++++++++---- src/hotspot/share/runtime/javaCalls.cpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 29 +-------------------- src/hotspot/share/runtime/sharedRuntime.hpp | 4 --- 5 files changed, 17 insertions(+), 44 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 1c807776e3c..7ffbf0151d2 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -563,12 +563,7 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref ref->msotype() == MetaspaceObj::CompileTrainingDataType) { return (TrainingData::need_data() || TrainingData::assembling_data()) ? make_a_copy : set_to_null; } else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) { - if (CDSConfig::is_dumping_adapters()) { - AdapterHandlerEntry* entry = (AdapterHandlerEntry*)ref->obj(); - return AdapterHandlerLibrary::is_abstract_method_adapter(entry) ? set_to_null : make_a_copy; - } else { - return set_to_null; - } + return CDSConfig::is_dumping_adapters() ? make_a_copy : set_to_null; } else { if (ref->msotype() == MetaspaceObj::ClassType) { Klass* klass = (Klass*)ref->obj(); diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 595b4e52882..40c44e07e37 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -152,11 +152,17 @@ void Method::release_C_heap_structures() { } address Method::get_i2c_entry() { + if (is_abstract()) { + return SharedRuntime::throw_AbstractMethodError_entry(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_i2c_entry(); } address Method::get_c2i_entry() { + if (is_abstract()) { + return SharedRuntime::get_handle_wrong_method_abstract_stub(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_entry(); } @@ -1165,9 +1171,9 @@ void Method::clear_code() { // this may be null if c2i adapters have not been made yet // Only should happen at allocate time. if (adapter() == nullptr) { - _from_compiled_entry = nullptr; + _from_compiled_entry = nullptr; } else { - _from_compiled_entry = adapter()->get_c2i_entry(); + _from_compiled_entry = adapter()->get_c2i_entry(); } OrderAccess::storestore(); _from_interpreted_entry = _i2i_entry; @@ -1196,7 +1202,7 @@ void Method::unlink_code() { void Method::unlink_method() { assert(CDSConfig::is_dumping_archive(), "sanity"); _code = nullptr; - if (!CDSConfig::is_dumping_adapters() || AdapterHandlerLibrary::is_abstract_method_adapter(_adapter)) { + if (!CDSConfig::is_dumping_adapters()) { _adapter = nullptr; } _i2i_entry = nullptr; @@ -1277,9 +1283,12 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { // called from the vtable. We need adapters on such methods that get loaded // later. Ditto for mega-morphic itable calls. If this proves to be a // problem we'll make these lazily later. - if (_adapter == nullptr) { + if (is_abstract()) { + h_method->_from_compiled_entry = SharedRuntime::get_handle_wrong_method_abstract_stub(); + } else if (_adapter == nullptr) { (void) make_adapters(h_method, CHECK); assert(adapter()->is_linked(), "Adapter must have been linked"); + h_method->_from_compiled_entry = adapter()->get_c2i_entry(); } // ONLY USE the h_method now as make_adapter may have blocked @@ -1300,6 +1309,7 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { } address Method::make_adapters(const methodHandle& mh, TRAPS) { + assert(!mh->is_abstract(), "abstract methods do not have adapters"); PerfTraceTime timer(ClassLoader::perf_method_adapters_time()); // Adapters for compiled code are made eagerly here. They are fairly @@ -1318,7 +1328,6 @@ address Method::make_adapters(const methodHandle& mh, TRAPS) { } mh->set_adapter_entry(adapter); - mh->_from_compiled_entry = adapter->get_c2i_entry(); return adapter->get_c2i_entry(); } diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 04bd0871073..f237886c128 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -406,7 +406,7 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC address verified_entry_point = (address) HotSpotJVMCI::InstalledCode::entryPoint(nullptr, alternative_target()); if (verified_entry_point != nullptr) { thread->set_jvmci_alternate_call_target(verified_entry_point); - entry_point = method->adapter()->get_i2c_entry(); + entry_point = method->get_i2c_entry(); } } #endif diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 044359eba8d..dc25fec9de7 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2510,7 +2510,6 @@ static void print_table_statistics() { // --------------------------------------------------------------------------- // Implementation of AdapterHandlerLibrary -AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = nullptr; AdapterHandlerEntry* AdapterHandlerLibrary::_no_arg_handler = nullptr; AdapterHandlerEntry* AdapterHandlerLibrary::_int_arg_handler = nullptr; AdapterHandlerEntry* AdapterHandlerLibrary::_obj_arg_handler = nullptr; @@ -2546,28 +2545,11 @@ static void post_adapter_creation(const AdapterBlob* new_adapter, } } -void AdapterHandlerLibrary::create_abstract_method_handler() { - assert_lock_strong(AdapterHandlerLibrary_lock); - // Create a special handler for abstract methods. Abstract methods - // are never compiled so an i2c entry is somewhat meaningless, but - // throw AbstractMethodError just in case. - // Pass wrong_method_abstract for the c2i transitions to return - // AbstractMethodError for invalid invocations. - address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub(); - _abstract_method_handler = AdapterHandlerLibrary::new_entry(AdapterFingerPrint::allocate(0, nullptr)); - _abstract_method_handler->set_entry_points(SharedRuntime::throw_AbstractMethodError_entry(), - wrong_method_abstract, - wrong_method_abstract, - nullptr); -} - void AdapterHandlerLibrary::initialize() { { ResourceMark rm; - MutexLocker mu(AdapterHandlerLibrary_lock); _adapter_handler_table = new (mtCode) AdapterHandlerTable(); _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size); - create_abstract_method_handler(); } #if INCLUDE_CDS @@ -2627,9 +2609,6 @@ AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* finger } AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) { - if (method->is_abstract()) { - return _abstract_method_handler; - } int total_args_passed = method->size_of_parameters(); // All args on stack if (total_args_passed == 0) { return _no_arg_handler; @@ -2727,6 +2706,7 @@ void AdapterHandlerLibrary::verify_adapter_sharing(int total_args_passed, BasicT #endif /* ASSERT*/ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { + assert(!method->is_abstract(), "abstract methods do not have adapters"); // Use customized signature handler. Need to lock around updates to // the _adapter_handler_table (it is not safe for concurrent readers // and a single writer: this could be fixed if it becomes a @@ -3497,13 +3477,6 @@ void AdapterHandlerLibrary::print_statistics() { #endif /* PRODUCT */ -bool AdapterHandlerLibrary::is_abstract_method_adapter(AdapterHandlerEntry* entry) { - if (entry == _abstract_method_handler) { - return true; - } - return false; -} - JRT_LEAF(void, SharedRuntime::enable_stack_reserved_zone(JavaThread* current)) assert(current == JavaThread::current(), "pre-condition"); StackOverflow* overflow_state = current->stack_overflow_state(); diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 41e4fc1fb3f..288bc0adc52 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -783,7 +783,6 @@ class AdapterHandlerLibrary: public AllStatic { friend class SharedRuntime; private: static BufferBlob* _buffer; // the temporary code buffer in CodeCache - static AdapterHandlerEntry* _abstract_method_handler; static AdapterHandlerEntry* _no_arg_handler; static AdapterHandlerEntry* _int_arg_handler; static AdapterHandlerEntry* _obj_arg_handler; @@ -801,7 +800,6 @@ class AdapterHandlerLibrary: public AllStatic { int total_args_passed, BasicType* sig_bt, bool is_transient = false); - static void create_abstract_method_handler(); static void lookup_simple_adapters() NOT_CDS_RETURN; #ifndef PRODUCT static void print_adapter_handler_info(outputStream* st, AdapterHandlerEntry* handler, AdapterBlob* adapter_blob); @@ -831,8 +829,6 @@ class AdapterHandlerLibrary: public AllStatic { static void print_statistics(); #endif // PRODUCT - static bool is_abstract_method_adapter(AdapterHandlerEntry* adapter); - static AdapterBlob* link_aot_adapter_handler(AdapterHandlerEntry* handler) NOT_CDS_RETURN_(nullptr); static void dump_aot_adapter_table() NOT_CDS_RETURN; static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_RETURN; From ecf05ca541b32736ab8e8a38d4be4f037a56361d Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 2 Sep 2025 15:26:48 +0000 Subject: [PATCH 096/295] 8366693: Backout recent JavaLangAccess changes breaking the build Reviewed-by: jpai, serb, alanb, syan, rriggs, jwaters --- .../share/classes/java/lang/String.java | 332 ++++++------------ .../share/classes/java/lang/System.java | 16 +- .../share/classes/java/nio/file/Files.java | 4 +- .../share/classes/java/util/zip/ZipCoder.java | 12 +- .../jdk/internal/access/JavaLangAccess.java | 24 +- .../unix/classes/sun/nio/fs/UnixPath.java | 2 +- .../{OrThrowTest.java => NoReplTest.java} | 20 +- 7 files changed, 145 insertions(+), 265 deletions(-) rename test/jdk/java/lang/String/{OrThrowTest.java => NoReplTest.java} (79%) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 8acb8d8514b..15b8e98369e 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -604,14 +604,14 @@ public final class String } byte[] utf16 = StringUTF16.newBytesFor(length); StringLatin1.inflate(latin1, 0, utf16, 0, dp); - dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp); + dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp, true); if (dp != length) { utf16 = Arrays.copyOf(utf16, dp << 1); } return new String(utf16, UTF16); } else { // !COMPACT_STRINGS byte[] dst = StringUTF16.newBytesFor(length); - int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0); + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } @@ -689,24 +689,12 @@ public final class String } /* - * {@return a new string by decoding from the given UTF-8 bytes array} - *

        - * WARNING: The caller of this method is assumed to have relinquished - * and transferred the ownership of the byte array. It can thus be - * exclusively used to construct the {@code String}. - * - * @param bytes byte array containing UTF-8 encoded characters - * @param offset the index of the first byte to decode - * @param length the number of bytes to decode - * @throws NullPointerException If {@code bytes} is null - * @throws StringIndexOutOfBoundsException If {@code offset} is negative, - * {@code length} is negative, or {@code offset} is greater than - * {@code bytes.length - length} - * @throws CharacterCodingException for malformed input or unmappable characters + * Throws iae, instead of replacing, if malformed or unmappable. + * The byte array can be exclusively used to construct + * the string and is not modified or used for any other purpose. */ - private static String newStringUTF8OrThrow(byte[] bytes, int offset, int length) - throws CharacterCodingException { - checkBoundsOffCount(offset, length, bytes.length); // Implicit null check on `bytes` + private static String newStringUTF8NoRepl(byte[] bytes, int offset, int length) { + checkBoundsOffCount(offset, length, bytes.length); if (length == 0) { return ""; } @@ -757,10 +745,10 @@ public final class String StringLatin1.inflate(dst, 0, buf, 0, dp); dst = buf; } - dp = decodeUTF8_UTF16OrThrow(bytes, offset, sl, dst, dp); + dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); } else { // !COMPACT_STRINGS dst = StringUTF16.newBytesFor(length); - dp = decodeUTF8_UTF16OrThrow(bytes, offset, offset + length, dst, 0); + dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); } if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); @@ -796,13 +784,26 @@ public final class String * * @throws CharacterCodingException for malformed input or unmappable characters */ - static String newStringOrThrow(byte[] src, Charset cs) throws CharacterCodingException { + static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { + try { + return newStringNoRepl1(src, cs); + } catch (IllegalArgumentException e) { + //newStringNoRepl1 throws IAE with MalformedInputException or CCE as the cause + Throwable cause = e.getCause(); + if (cause instanceof MalformedInputException mie) { + throw mie; + } + throw (CharacterCodingException)cause; + } + } + + private static String newStringNoRepl1(byte[] src, Charset cs) { int len = src.length; if (len == 0) { return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8OrThrow(src, 0, src.length); + return newStringUTF8NoRepl(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -815,7 +816,7 @@ public final class String return new String(src, LATIN1); return new String(StringLatin1.inflate(src, 0, src.length), UTF16); } else { - throw malformedASCII(src); + throwMalformed(src); } } @@ -830,7 +831,13 @@ public final class String } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; - int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); + int caLen; + try { + caLen = decodeWithDecoder(cd, ca, src, 0, src.length); + } catch (CharacterCodingException x) { + // throw via IAE + throw new IllegalArgumentException(x); + } if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); byte coder = StringUTF16.coderFromArrayLen(val, caLen); @@ -867,7 +874,7 @@ public final class String private static byte[] encode(Charset cs, byte coder, byte[] val) { if (cs == UTF_8.INSTANCE) { - return encodeUTF8(coder, val); + return encodeUTF8(coder, val, true); } if (cs == ISO_8859_1.INSTANCE) { return encode8859_1(coder, val); @@ -875,30 +882,13 @@ public final class String if (cs == US_ASCII.INSTANCE) { return encodeASCII(coder, val); } - return encodeWithEncoder(cs, coder, val, null); + return encodeWithEncoder(cs, coder, val, true); } - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with the encoder of {@code - * cs}} - * - * @param cs a charset to obtain the encoder from - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encodeWithEncoder( - Charset cs, byte coder, byte[] val, Class exClass) - throws E { + private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, boolean doReplace) { CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); - boolean doReplace = exClass == null; // fastpath with ArrayEncoder implies `doReplace`. if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible @@ -940,9 +930,7 @@ public final class String cr.throwException(); } catch (CharacterCodingException x) { if (!doReplace) { - @SuppressWarnings("unchecked") - E cce = (E) x; - throw cce; + throw new IllegalArgumentException(x); } else { throw new Error(x); } @@ -950,69 +938,60 @@ public final class String return trimArray(ba, bb.position()); } - /** - * {@return the sequence of bytes obtained by encoding the given string in UTF-8} - * - * @param s the string to encode - * @throws NullPointerException If {@code s} is null - * @throws CharacterCodingException For malformed input or unmappable characters + /* + * Throws iae, instead of replacing, if unmappable. */ - static byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { - return encodeUTF8OrThrow(s.coder(), s.value()); // Implicit null check on `s` + static byte[] getBytesUTF8NoRepl(String s) { + return encodeUTF8(s.coder(), s.value(), false); } private static boolean isASCII(byte[] src) { return !StringCoding.hasNegatives(src, 0, src.length); } - /** - * {@return the sequence of bytes obtained by encoding the given string in - * the specified {@code Charset}} - *

        - * WARNING: This method returns the {@code byte[]} backing the provided - * {@code String}, if the input is ASCII. Hence, the returned byte array - * must not be modified. - * - * @param s the string to encode - * @param cs the charset - * @throws NullPointerException If {@code s} or {@code cs} is null - * @throws CharacterCodingException For malformed input or unmappable characters + /* + * Throws CCE, instead of replacing, if unmappable. */ - static byte[] getBytesOrThrow(String s, Charset cs) throws CharacterCodingException { - Objects.requireNonNull(cs); - byte[] val = s.value(); // Implicit null check on `s` + static byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { + try { + return getBytesNoRepl1(s, cs); + } catch (IllegalArgumentException e) { + //getBytesNoRepl1 throws IAE with UnmappableCharacterException or CCE as the cause + Throwable cause = e.getCause(); + if (cause instanceof UnmappableCharacterException) { + throw (UnmappableCharacterException)cause; + } + throw (CharacterCodingException)cause; + } + } + + private static byte[] getBytesNoRepl1(String s, Charset cs) { + byte[] val = s.value(); byte coder = s.coder(); if (cs == UTF_8.INSTANCE) { if (coder == LATIN1 && isASCII(val)) { return val; } - return encodeUTF8OrThrow(coder, val); + return encodeUTF8(coder, val, false); } if (cs == ISO_8859_1.INSTANCE) { if (coder == LATIN1) { return val; } - return encode8859_1OrThrow(coder, val); + return encode8859_1(coder, val, false); } if (cs == US_ASCII.INSTANCE) { if (coder == LATIN1) { if (isASCII(val)) { return val; } else { - throw unmappableASCII(val); + throwUnmappable(val); } } } - return encodeWithEncoder(cs, coder, val, CharacterCodingException.class); + return encodeWithEncoder(cs, coder, val, false); } - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with US-ASCII} - * - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - */ private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { int positives = StringCoding.countPositives(val, 0, val.length); @@ -1052,26 +1031,10 @@ public final class String } private static byte[] encode8859_1(byte coder, byte[] val) { - return encode8859_1(coder, val, null); + return encode8859_1(coder, val, true); } - private static byte[] encode8859_1OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { - return encode8859_1(coder, val, UnmappableCharacterException.class); - } - - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with ISO-8859-1} - * - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encode8859_1(byte coder, byte[] val, Class exClass) throws E { + private static byte[] encode8859_1(byte coder, byte[] val, boolean doReplace) { if (coder == LATIN1) { return val.clone(); } @@ -1085,8 +1048,8 @@ public final class String sp = sp + ret; dp = dp + ret; if (ret != len) { - if (exClass != null) { - throw String.unmappableCharacterException(sp); + if (!doReplace) { + throwUnmappable(sp); } char c = StringUTF16.getChar(val, sp++); if (Character.isHighSurrogate(c) && sp < sl && @@ -1180,26 +1143,7 @@ public final class String ((byte) 0x80 << 0)))); } - private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp) { - return decodeUTF8_UTF16(src, sp, sl, dst, dp, null); - } - - private static int decodeUTF8_UTF16OrThrow( - byte[] src, int sp, int sl, byte[] dst, int dp) - throws MalformedInputException { - return decodeUTF8_UTF16(src, sp, sl, dst, dp, MalformedInputException.class); - } - - /** - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static int decodeUTF8_UTF16( - byte[] src, int sp, int sl, byte[] dst, int dp, Class exClass) - throws E { + private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp, boolean doReplace) { while (sp < sl) { int b1 = src[sp++]; if (b1 >= 0) { @@ -1208,8 +1152,8 @@ public final class String if (sp < sl) { int b2 = src[sp++]; if (isNotContinuation(b2)) { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); + if (!doReplace) { + throwMalformed(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); sp--; @@ -1218,8 +1162,8 @@ public final class String } continue; } - if (exClass != null) { - throw String.malformedInputException(sp, 1); // underflow() + if (!doReplace) { + throwMalformed(sp, 1); // underflow() } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1228,8 +1172,8 @@ public final class String int b2 = src[sp++]; int b3 = src[sp++]; if (isMalformed3(b1, b2, b3)) { - if (exClass != null) { - throw String.malformedInputException(sp - 3, 3); + if (!doReplace) { + throwMalformed(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); sp -= 3; @@ -1237,8 +1181,8 @@ public final class String } else { char c = decode3(b1, b2, b3); if (Character.isSurrogate(c)) { - if (exClass != null) { - throw String.malformedInputException(sp - 3, 3); + if (!doReplace) { + throwMalformed(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); } else { @@ -1248,14 +1192,14 @@ public final class String continue; } if (sp < sl && isMalformed3_2(b1, src[sp])) { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 2); + if (!doReplace) { + throwMalformed(sp - 1, 2); } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (exClass != null) { - throw String.malformedInputException(sp, 1); + if (!doReplace) { + throwMalformed(sp, 1); } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1267,8 +1211,8 @@ public final class String int uc = decode4(b1, b2, b3, b4); if (isMalformed4(b2, b3, b4) || !Character.isSupplementaryCodePoint(uc)) { // shortest form check - if (exClass != null) { - throw String.malformedInputException(sp - 4, 4); + if (!doReplace) { + throwMalformed(sp - 4, 4); } StringUTF16.putChar(dst, dp++, REPL); sp -= 4; @@ -1281,14 +1225,14 @@ public final class String } b1 &= 0xff; if (b1 > 0xf4 || sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); // or 2 + if (!doReplace) { + throwMalformed(sp - 1, 1); // or 2 } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); + if (!doReplace) { + throwMalformed(sp - 1, 1); } sp++; StringUTF16.putChar(dst, dp++, REPL); @@ -1297,8 +1241,8 @@ public final class String } break; } else { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); + if (!doReplace) { + throwMalformed(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); } @@ -1340,76 +1284,29 @@ public final class String return 3; } - /** - * {@return a new {@link MalformedInputException} for the sub-range denoted - * by specified {@code offset} and {@code length}} - * - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - @SuppressWarnings("unchecked") - private static E malformedInputException(int offset, int length) throws E { - MalformedInputException mie = new MalformedInputException(length); - String msg = "malformed input offset : " + offset + ", length : " + length; - mie.initCause(new IllegalArgumentException(msg)); - return (E) mie; + private static void throwMalformed(int off, int nb) { + String msg = "malformed input off : " + off + ", length : " + nb; + throw new IllegalArgumentException(msg, new MalformedInputException(nb)); } - /** - * {@return a new {@link MalformedInputException} for the given malformed - * ASCII string} - */ - private static MalformedInputException malformedASCII(byte[] val) throws MalformedInputException { + private static void throwMalformed(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - return malformedInputException(dp, 1); + throwMalformed(dp, 1); } - /** - * {@return a new {@link UnmappableCharacterException} at given {@code offset}} - * - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - @SuppressWarnings("unchecked") - private static E unmappableCharacterException(int offset) throws E { - UnmappableCharacterException uce = new UnmappableCharacterException(1); - String msg = "malformed input offset : " + offset + ", length : 1"; - uce.initCause(new IllegalArgumentException(msg, uce)); - return (E) uce; + private static void throwUnmappable(int off) { + String msg = "malformed input off : " + off + ", length : 1"; + throw new IllegalArgumentException(msg, new UnmappableCharacterException(1)); } - /** - * {@return a new {@link UnmappableCharacterException} for the given - * malformed ASCII string} - */ - private static UnmappableCharacterException unmappableASCII(byte[] val) throws UnmappableCharacterException { + private static void throwUnmappable(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - return unmappableCharacterException(dp); + throwUnmappable(dp); } - private static byte[] encodeUTF8(byte coder, byte[] val) { - return encodeUTF8(coder, val, null); - } - - private static byte[] encodeUTF8OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { - return encodeUTF8(coder, val, UnmappableCharacterException.class); - } - - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with UTF-8} - * - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encodeUTF8(byte coder, byte[] val, Class exClass) throws E { + private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { if (coder == UTF16) { - return encodeUTF8_UTF16(val, exClass); + return encodeUTF8_UTF16(val, doReplace); } int positives = StringCoding.countPositives(val, 0, val.length); @@ -1437,24 +1334,13 @@ public final class String return Arrays.copyOf(dst, dp); } - /** - * {@return the byte array obtained by first decoding {@code val} with - * UTF-16, and then encoding the result with UTF-8} - * - * @param val a string byte array encoded with UTF-16 - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encodeUTF8_UTF16(byte[] val, Class exClass) throws E { + private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { int dp = 0; int sp = 0; int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; if (allocLen > (long)Integer.MAX_VALUE) { throw new OutOfMemoryError("Required length exceeds implementation limit"); } @@ -1483,10 +1369,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (exClass == null) { + if (doReplace) { dst[dp++] = '?'; } else { - throw String.unmappableCharacterException(sp - 1); + throwUnmappable(sp - 1); } } else { dst[dp++] = (byte)(0xf0 | ((uc >> 18))); @@ -1510,14 +1396,10 @@ public final class String /** * {@return the exact size required to UTF_8 encode this UTF16 string} - * - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting discarded. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception + * @param val UTF16 encoded byte array + * @param doReplace true to replace unmappable characters */ - private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { + private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { long dp = 0L; int sp = 0; int sl = val.length >> 1; @@ -1536,10 +1418,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (exClass == null) { + if (doReplace) { dp++; } else { - throw String.unmappableCharacterException(sp - 1); + throwUnmappable(sp - 1); } } else { dp += 4; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index bb1775fbc6b..a40c27bbf47 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2124,7 +2124,6 @@ public final class System { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } - public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } @@ -2133,24 +2132,21 @@ public final class System { return String.newStringWithLatin1Bytes(bytes); } - public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException { - return String.newStringOrThrow(bytes, cs); + public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { + return String.newStringNoRepl(bytes, cs); } - public char uncheckedGetUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } - public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) { StringUTF16.putChar(bytes, index, ch); } - - public byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException { - return String.getBytesOrThrow(s, cs); + public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException { + return String.getBytesNoRepl(s, cs); } - public byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { - return String.getBytesUTF8OrThrow(s); + public byte[] getBytesUTF8NoRepl(String s) { + return String.getBytesUTF8NoRepl(s); } public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index 80c771f5306..f8278fa2642 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public final class Files { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.uncheckedNewStringOrThrow(ba, cs); + return JLA.uncheckedNewStringNoRepl(ba, cs); } /** @@ -3362,7 +3362,7 @@ public final class Files { Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.uncheckedGetBytesOrThrow(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index b9906d348e3..8b812eba202 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -256,7 +256,7 @@ class ZipCoder { try { // Copy subrange for exclusive use by the string being created byte[] bytes = Arrays.copyOfRange(ba, off, off + length); - return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8); + return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8); } catch (CharacterCodingException cce) { throw new IllegalArgumentException(cce); } @@ -264,11 +264,7 @@ class ZipCoder { @Override byte[] getBytes(String s) { - try { - return JLA.getBytesUTF8OrThrow(s); - } catch (CharacterCodingException cce) { - throw new IllegalArgumentException(cce); - } + return JLA.getBytesUTF8NoRepl(s); } @Override @@ -282,6 +278,8 @@ class ZipCoder { // Non-ASCII, fall back to decoding a String // We avoid using decoder() here since the UTF8ZipCoder is // shared and that decoder is not thread safe. + // We use the JLA.newStringUTF8NoRepl variant to throw + // exceptions eagerly when opening ZipFiles return hash(toString(a, off, len)); } int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0); @@ -298,7 +296,7 @@ class ZipCoder { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index c7d7c86b932..aa5b6e438f5 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,6 +45,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; +import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -331,7 +332,7 @@ public interface JavaLangAccess { /** * Constructs a new {@code String} by decoding the specified byte array - * using the specified {@code Charset}. + * using the specified {@linkplain java.nio.charset.Charset charset}. *

        * WARNING: The caller of this method shall relinquish and transfer the * ownership of the byte array to the callee, since the latter will not @@ -342,22 +343,25 @@ public interface JavaLangAccess { * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes */ - String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * {@return the sequence of bytes obtained by encoding the given string in - * the specified {@code Charset}} + * Encode the given string into a sequence of bytes using the specified + * {@linkplain java.nio.charset.Charset charset}. *

        * WARNING: This method returns the {@code byte[]} backing the provided * {@code String}, if the input is ASCII. Hence, the returned byte array * must not be modified. + *

        + * This method throws {@code CharacterCodingException} instead of replacing + * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset - * @throws NullPointerException If {@code s} or {@code cs} is null + * @return the encoded bytes * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; /** * Get the {@code char} at {@code index} in a {@code byte[]} in internal @@ -383,13 +387,13 @@ public interface JavaLangAccess { void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** - * {@return the sequence of bytes obtained by encoding the given string in UTF-8} + * Encode the given string into a sequence of bytes using utf8. * * @param s the string to encode - * @throws NullPointerException If {@code s} is null - * @throws CharacterCodingException For malformed input or unmappable characters + * @return the encoded bytes in utf8 + * @throws IllegalArgumentException for malformed surrogates */ - byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException; + byte[] getBytesUTF8NoRepl(String s); /** * Inflated copy from {@code byte[]} to {@code char[]}, as defined by diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 5a77bb0b935..5dfc73f57aa 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -126,7 +126,7 @@ class UnixPath implements Path { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.uncheckedGetBytesOrThrow(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/test/jdk/java/lang/String/OrThrowTest.java b/test/jdk/java/lang/String/NoReplTest.java similarity index 79% rename from test/jdk/java/lang/String/OrThrowTest.java rename to test/jdk/java/lang/String/NoReplTest.java index 340a190b4eb..1817a1ffe73 100644 --- a/test/jdk/java/lang/String/OrThrowTest.java +++ b/test/jdk/java/lang/String/NoReplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,8 +24,8 @@ /* * @test * @bug 8286287 8288589 - * @summary Tests for *OrThrow() shared secret methods. - * @run testng OrThrowTest + * @summary Tests for *NoRepl() shared secret methods. + * @run testng NoReplTest * @modules jdk.charsets */ @@ -39,17 +39,17 @@ import static java.nio.charset.StandardCharsets.UTF_16; import org.testng.annotations.Test; @Test -public class OrThrowTest { +public class NoReplTest { private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); /** - * Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}. - * The method is invoked by {@code Files.readString()} method. + * Verifies newStringNoRepl() throws a CharacterCodingException. + * The method is invoked by `Files.readString()` method. */ @Test - public void uncheckedNewStringOrThrowTest() throws IOException { + public void newStringNoReplTest() throws IOException { var f = Files.createTempFile(null, null); try (var fos = Files.newOutputStream(f)) { fos.write(MALFORMED_UTF16); @@ -67,11 +67,11 @@ public class OrThrowTest { } /** - * Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}. - * The method is invoked by {@code Files.writeString()} method. + * Verifies getBytesNoRepl() throws a CharacterCodingException. + * The method is invoked by `Files.writeString()` method. */ @Test - public void uncheckedGetBytesOrThrowTest() throws IOException { + public void getBytesNoReplTest() throws IOException { var f = Files.createTempFile(null, null); try { Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); From 48ba8ed2439f9a4a5cdca8715ffddad377366347 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 2 Sep 2025 17:00:33 +0000 Subject: [PATCH 097/295] 8366704: Bump timeout on TestInheritFD Reviewed-by: lmesnik --- test/hotspot/jtreg/runtime/8176717/TestInheritFD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java index 8130ff65792..7cb0efac897 100644 --- a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java +++ b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java @@ -92,7 +92,7 @@ public class TestInheritFD { public static final String THIRD_VM_PID_PREFIX = "Third VM pid="; public static final String THIRD_VM_WAITING_PREFIX = "Third VM waiting for second VM pid="; - public static long subProcessTimeout = (long)(15L * Utils.TIMEOUT_FACTOR); + public static long subProcessTimeout = (long)(60L * Utils.TIMEOUT_FACTOR); // Extract a pid from the specified String at the specified start offset. private static long extractPidFromStringOffset(String str, int start) { From c935d1ce1c42ce98cc6ceffaa4f47eb2dba24dfd Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 2 Sep 2025 17:11:34 +0000 Subject: [PATCH 098/295] 8366375: Collator example for SECONDARY uses wrong code point Reviewed-by: jlu, joehw, smarks --- src/java.base/share/classes/java/text/Collator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/text/Collator.java b/src/java.base/share/classes/java/text/Collator.java index 7f6db310366..276a66cdc07 100644 --- a/src/java.base/share/classes/java/text/Collator.java +++ b/src/java.base/share/classes/java/text/Collator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,7 @@ public abstract class Collator * Collator strength value. When set, only SECONDARY and above differences are * considered significant during comparison. The assignment of strengths * to language features is locale dependent. A common example is for - * different accented forms of the same base letter ("a" vs "ä" (U+00E9)) to be + * different accented forms of the same base letter ("a" vs "ä" (U+00E4)) to be * considered a SECONDARY difference. * @see java.text.Collator#setStrength * @see java.text.Collator#getStrength @@ -161,8 +161,8 @@ public abstract class Collator * characters ("\u0001" vs "\u0002") to be considered equal at the * PRIMARY, SECONDARY, and TERTIARY levels but different at the IDENTICAL * level. Additionally, differences between pre-composed accents such as - * "\u00C0" (A-grave) and combining accents such as "A\u0300" - * (A, combining-grave) will be considered significant at the IDENTICAL + * "\u00E4" (a-diaeresis) and combining accents such as "a\u0308" + * (a, combining-diaeresis) will be considered significant at the IDENTICAL * level if decomposition is set to NO_DECOMPOSITION. */ public static final int IDENTICAL = 3; From 0d85f076cc32494c1162baea3ea6b0db67136d41 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Tue, 2 Sep 2025 18:03:09 +0000 Subject: [PATCH 099/295] 8359174: tools/jlink/JLink20000Packages.java timed out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vicente Romero Co-authored-by: Eirik Bjørsnøs Reviewed-by: jpai, liach --- test/jdk/tools/jlink/JLink20000Packages.java | 135 ++++++++++-------- test/jdk/tools/lib/tests/JImageGenerator.java | 6 +- 2 files changed, 76 insertions(+), 65 deletions(-) diff --git a/test/jdk/tools/jlink/JLink20000Packages.java b/test/jdk/tools/jlink/JLink20000Packages.java index d592cbc112b..08e6141a267 100644 --- a/test/jdk/tools/jlink/JLink20000Packages.java +++ b/test/jdk/tools/jlink/JLink20000Packages.java @@ -21,14 +21,28 @@ * questions. */ +import tests.JImageGenerator; + +import java.io.BufferedOutputStream; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.StringJoiner; -import java.util.spi.ToolProvider; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; -import tests.JImageGenerator; +import static java.lang.classfile.ClassFile.ACC_MANDATED; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_void; /* * @test @@ -36,79 +50,57 @@ import tests.JImageGenerator; * pagination is in place, the limitation is on the constant pool size, not number * of packages. * @bug 8321413 - * @library ../lib - * @enablePreview + * @library ../lib /test/lib * @modules java.base/jdk.internal.jimage - * jdk.jlink/jdk.tools.jlink.internal - * jdk.jlink/jdk.tools.jlink.plugin - * jdk.jlink/jdk.tools.jmod * jdk.jlink/jdk.tools.jimage - * jdk.compiler * @build tests.* - * @run main/othervm/timeout=1920 -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages + * @run main/othervm -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages */ public class JLink20000Packages { - private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") - .orElseThrow(() -> new RuntimeException("javac tool not found")); - - static void report(String command, String[] args) { - System.out.println(command + " " + String.join(" ", Arrays.asList(args))); - } - - static void javac(String[] args) { - report("javac", args); - JAVAC_TOOL.run(System.out, System.err, args); - } + private static final ClassDesc CD_System = ClassDesc.of("java.lang.System"); + private static final ClassDesc CD_PrintStream = ClassDesc.of("java.io.PrintStream"); + private static final MethodTypeDesc MTD_void_String = MethodTypeDesc.of(CD_void, CD_String); public static void main(String[] args) throws Exception { - Path src = Paths.get("bug8321413"); + String moduleName = "bug8321413x"; + Path src = Paths.get(moduleName); + Files.createDirectories(src); + Path jarPath = src.resolve(moduleName +".jar"); Path imageDir = src.resolve("out-jlink"); - Path mainModulePath = src.resolve("bug8321413x"); - StringJoiner mainModuleInfoContent = new StringJoiner(";\n exports ", "module bug8321413x {\n exports ", ";\n}"); + // Generate module with 20000 classes in unique packages + try (JarOutputStream out = new JarOutputStream(new BufferedOutputStream(Files.newOutputStream(jarPath)))) { + Set packageNames = new HashSet<>(); + for (int i = 0; i < 20_000; i++) { + String packageName = "p" + i; + packageNames.add(packageName); - for (int i = 0; i < 20000; i++) { - String packageName = "p" + i; - String className = "C" + i; + // Generate a class file for this package + String className = "C" + i; + byte[] classData = ClassFile.of().build(ClassDesc.of(packageName, className), cb -> {}); + out.putNextEntry(new JarEntry(packageName + "/" + className +".class")); + out.write(classData); + } - Path packagePath = Files.createDirectories(mainModulePath.resolve(packageName)); + // Write the main class + out.putNextEntry(new JarEntry("testpackage/JLink20000PackagesTest.class")); + out.write(generateMainClass()); + packageNames.add("testpackage"); - StringBuilder classContent = new StringBuilder("package "); - classContent.append(packageName).append(";\n"); - classContent.append("class ").append(className).append(" {}\n"); - Files.writeString(packagePath.resolve(className + ".java"), classContent.toString()); - - mainModuleInfoContent.add(packageName); + // Write the module descriptor + byte[] moduleInfo = ClassFile.of().buildModule(ModuleAttribute.of( + ModuleDesc.of(moduleName), mab -> { + mab.requires(ModuleDesc.of("java.base"), ACC_MANDATED, null); + packageNames.forEach(pkgName -> mab.exports(PackageDesc.of(pkgName), 0)); + })); + out.putNextEntry(new JarEntry("module-info.class")); + out.write(moduleInfo); } - // create module reading the generated modules - Path mainModuleInfo = mainModulePath.resolve("module-info.java"); - Files.writeString(mainModuleInfo, mainModuleInfoContent.toString()); - - Path mainClassDir = mainModulePath.resolve("testpackage"); - Files.createDirectories(mainClassDir); - - Files.writeString(mainClassDir.resolve("JLink20000PackagesTest.java"), """ - package testpackage; - - public class JLink20000PackagesTest { - public static void main(String[] args) throws Exception { - System.out.println("JLink20000PackagesTest started."); - } - } - """); - - String out = src.resolve("out").toString(); - javac(new String[]{ - "-d", out, - "--module-source-path", src.toString(), - "--module", "bug8321413x" - }); - JImageGenerator.getJLinkTask() - .modulePath(out) .output(imageDir) - .addMods("bug8321413x") + .addJars(jarPath) + .addMods(moduleName) .call() .assertSuccess(); @@ -117,8 +109,9 @@ public class JLink20000Packages { ProcessBuilder processBuilder = new ProcessBuilder(bin.toString(), "-XX:+UnlockDiagnosticVMOptions", + // Option is useful to verify build image "-XX:+BytecodeVerificationLocal", - "-m", "bug8321413x/testpackage.JLink20000PackagesTest"); + "-m", moduleName + "/testpackage.JLink20000PackagesTest"); processBuilder.inheritIO(); processBuilder.directory(binDir.toFile()); Process process = processBuilder.start(); @@ -126,4 +119,22 @@ public class JLink20000Packages { if (exitCode != 0) throw new AssertionError("JLink20000PackagesTest failed to launch"); } + + /** + * Generate test class with main() does + * System.out.println("JLink20000PackagesTest started."); + */ + private static byte[] generateMainClass() { + return ClassFile.of().build(ClassDesc.of("testpackage", "JLink20000PackagesTest"), + cb -> { + cb.withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), + ACC_PUBLIC | ACC_STATIC, mb -> { + mb.withCode(cob -> cob.getstatic(CD_System, "out", CD_PrintStream) + .ldc("JLink20000PackagesTest started.") + .invokevirtual(CD_PrintStream, "println", MTD_void_String) + .return_() + ); + }); + }); + } } diff --git a/test/jdk/tools/lib/tests/JImageGenerator.java b/test/jdk/tools/lib/tests/JImageGenerator.java index b872ca4f584..5e006459101 100644 --- a/test/jdk/tools/lib/tests/JImageGenerator.java +++ b/test/jdk/tools/lib/tests/JImageGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -423,7 +423,7 @@ public class JImageGenerator { // This is expect FIRST jmods THEN jars, if you change this, some tests could fail String jmods = toPath(this.jmods); String jars = toPath(this.jars); - return linkableRuntime ? jars : jmods + File.pathSeparator + jars; + return (linkableRuntime || jmods.isEmpty()) ? jars : jmods + File.pathSeparator + jars; } private String toPath(List paths) { @@ -654,7 +654,7 @@ public class JImageGenerator { // This is expect FIRST jmods THEN jars, if you change this, some tests could fail String jmods = toPath(this.jmods); String jars = toPath(this.jars); - return jmods + File.pathSeparator + jars; + return jmods.isEmpty() ? jars : jmods + File.pathSeparator + jars; } private String toPath(List paths) { From 80fb7088a10136080d23ea93b4840f17d738500c Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 2 Sep 2025 20:43:38 +0000 Subject: [PATCH 100/295] 8365175: Replace Unicode extension anchor elements with link tag Reviewed-by: liach, iris, naoto --- .../share/classes/java/text/DateFormat.java | 4 ++-- .../classes/java/text/DateFormatSymbols.java | 4 ++-- .../java/text/DecimalFormatSymbols.java | 4 ++-- .../share/classes/java/text/NumberFormat.java | 6 +++--- .../text/spi/DecimalFormatSymbolsProvider.java | 6 +++--- .../java/time/format/DateTimeFormatter.java | 8 ++++---- .../time/format/DateTimeFormatterBuilder.java | 4 ++-- .../classes/java/time/format/DecimalStyle.java | 4 ++-- .../classes/java/time/temporal/WeekFields.java | 4 ++-- .../share/classes/java/util/Calendar.java | 18 +++++++++--------- .../classes/java/util/ResourceBundle.java | 4 ++-- .../java/util/spi/LocaleNameProvider.java | 6 +++--- 12 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/java/text/DateFormat.java b/src/java.base/share/classes/java/text/DateFormat.java index af756289086..19835dff7c4 100644 --- a/src/java.base/share/classes/java/text/DateFormat.java +++ b/src/java.base/share/classes/java/text/DateFormat.java @@ -101,8 +101,8 @@ import sun.util.locale.provider.LocaleServiceProviderPool; * * *

        If the specified locale contains "ca" (calendar), "rg" (region override), - * and/or "tz" (timezone) Unicode - * extensions, the calendar, the country and/or the time zone for formatting + * and/or "tz" (timezone) {@linkplain Locale##def_locale_extension Unicode + * extensions}, the calendar, the country and/or the time zone for formatting * are overridden. If both "ca" and "rg" are specified, the calendar from the "ca" * extension supersedes the implicit one from the "rg" extension. * diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index f08f5e78338..9fff6a7c4d4 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ import sun.util.locale.provider.TimeZoneNameUtility; * * *

        If the locale contains "rg" (region override) - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * the symbols are overridden for the designated region. * *

        diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index dfb344f26a7..ccb6c02535c 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -60,8 +60,8 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * your {@code DecimalFormat} and modify it. * *

        The "rg" (region override), "nu" (numbering system), and "cu" (currency) - * {@code Locale} Unicode - * extensions are supported which may override values within the symbols. + * {@code Locale} {@linkplain Locale##def_locale_extension Unicode + * extensions} are supported which may override values within the symbols. * For both "nu" and "cu", if they are specified in addition to "rg" by the * backing {@code Locale}, the respective values from the "nu" and "cu" extension * supersede the implicit ones from the "rg" extension. diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 759ed7ae5ea..afdba76d1ed 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -92,7 +92,7 @@ import sun.util.locale.provider.LocaleServiceProviderPool; * *

        Locale Extensions

        * Formatting behavior can be changed when using a locale that contains any of the following - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, *
          *
        • "nu" * ( @@ -110,7 +110,7 @@ import sun.util.locale.provider.LocaleServiceProviderPool; *

          * For both "nu" and "cu", if they are specified in addition to "rg", the respective * values from the "nu" and "cu" extension supersede the implicit ones from the "rg" extension. - * Although Unicode extensions + * Although {@linkplain Locale##def_locale_extension Unicode extensions} * defines various keys and values, actual locale-sensitive service implementations * in a Java Runtime Environment might not support any particular Unicode locale * attributes or key/type pairs. @@ -691,7 +691,7 @@ public abstract class NumberFormat extends Format { *

          If the specified locale contains the "{@code cf}" ( * * currency format style) - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * the returned currency format uses the style if it is available. * Otherwise, the style uses the default "{@code standard}" currency format. * For example, if the style designates "{@code account}", negative diff --git a/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java b/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java index ffb149bcb8a..2524cc3aa61 100644 --- a/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java +++ b/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +34,8 @@ import java.util.spi.LocaleServiceProvider; * provide instances of the * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} class. * - *

          The requested {@code Locale} may contain an extension for + *

          The requested {@code Locale} may contain an {@linkplain + * Locale##def_locale_extension extension} for * specifying the desired numbering system. For example, {@code "ar-u-nu-arab"} * (in the BCP 47 language tag form) specifies Arabic with the Arabic-Indic * digits and symbols, while {@code "ar-u-nu-latn"} specifies Arabic with the diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 108f1e1eef8..26192b8e178 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1508,9 +1508,9 @@ public final class DateTimeFormatter { * localization, such as the text or localized pattern. *

          * The locale is stored as passed in, without further processing. - * If the locale has - * Unicode extensions, they may be used later in text - * processing. To set the chronology, time-zone and decimal style from + * If the locale has {@linkplain Locale##def_locale_extension Unicode extensions}, + * they may be used later in text processing. + * To set the chronology, time-zone and decimal style from * unicode extensions, see {@link #localizedBy localizedBy()}. *

          * This instance is immutable and unaffected by this method call. @@ -1535,7 +1535,7 @@ public final class DateTimeFormatter { * localization, such as the text or localized pattern. If the locale contains the * "ca" (calendar), "nu" (numbering system), "rg" (region override), and/or * "tz" (timezone) - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, * the chronology, numbering system and/or the zone are overridden. If both "ca" * and "rg" are specified, the chronology from the "ca" extension supersedes the * implicit one from the "rg" extension. Same is true for the "nu" extension. diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 43a79cd85ee..7a2142e5113 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -205,7 +205,7 @@ public final class DateTimeFormatterBuilder { * for the requested dateStyle and/or timeStyle. *

          * If the locale contains the "rg" (region override) - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, * the formatting pattern is overridden with the one appropriate for the region. * * @param dateStyle the FormatStyle for the date, null for time-only pattern @@ -235,7 +235,7 @@ public final class DateTimeFormatterBuilder { * for the requested template. *

          * If the locale contains the "rg" (region override) - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, * the formatting pattern is overridden with the one appropriate for the region. *

          * Refer to {@link #appendLocalized(String)} for the detail of {@code requestedTemplate} diff --git a/src/java.base/share/classes/java/time/format/DecimalStyle.java b/src/java.base/share/classes/java/time/format/DecimalStyle.java index a9ad8a4e273..94d6a700ce3 100644 --- a/src/java.base/share/classes/java/time/format/DecimalStyle.java +++ b/src/java.base/share/classes/java/time/format/DecimalStyle.java @@ -150,8 +150,8 @@ public final class DecimalStyle { *

          * This method provides access to locale sensitive decimal style symbols. * If the locale contains "nu" (Numbering System) and/or "rg" - * (Region Override) - * Unicode extensions, returned instance will reflect the values specified with + * (Region Override) {@linkplain Locale##def_locale_extension Unicode extensions}, + * returned instance will reflect the values specified with * those extensions. If both "nu" and "rg" are specified, the value from * the "nu" extension supersedes the implicit one from the "rg" extension. * diff --git a/src/java.base/share/classes/java/time/temporal/WeekFields.java b/src/java.base/share/classes/java/time/temporal/WeekFields.java index bbad365553d..fc72b806601 100644 --- a/src/java.base/share/classes/java/time/temporal/WeekFields.java +++ b/src/java.base/share/classes/java/time/temporal/WeekFields.java @@ -289,8 +289,8 @@ public final class WeekFields implements Serializable { *

          * This will look up appropriate values from the provider of localization data. * If the locale contains "fw" (First day of week) and/or "rg" - * (Region Override) - * Unicode extensions, returned instance will reflect the values specified with + * (Region Override) {@linkplain Locale##def_locale_extension Unicode extensions}, + * returned instance will reflect the values specified with * those extensions. If both "fw" and "rg" are specified, the value from * the "fw" extension supersedes the implicit one from the "rg" extension. * diff --git a/src/java.base/share/classes/java/util/Calendar.java b/src/java.base/share/classes/java/util/Calendar.java index 7cf389df42b..e9183ae17da 100644 --- a/src/java.base/share/classes/java/util/Calendar.java +++ b/src/java.base/share/classes/java/util/Calendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +129,8 @@ import sun.util.spi.CalendarProvider; * parameters: the first day of the week and the minimal days in first week * (from 1 to 7). These numbers are taken from the locale resource data or the * locale itself when a {@code Calendar} is constructed. If the designated - * locale contains "fw" and/or "rg" - * Unicode extensions, the first day of the week will be obtained according to + * locale contains "fw" and/or "rg" {@linkplain Locale##def_locale_extension + * Unicode extensions}, the first day of the week will be obtained according to * those extensions. If both "fw" and "rg" are specified, the value from the "fw" * extension supersedes the implicit one from the "rg" extension. * They may also be specified explicitly through the methods for setting their @@ -1454,7 +1454,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable * If the locale contains the time zone with "tz" - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * and time zone hasn't been given explicitly, time zone in the locale * is used. * @@ -1615,7 +1615,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable * If the locale contains the time zone with "tz" - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * that time zone is used instead. * * @return a Calendar. @@ -1647,7 +1647,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable * If the locale contains the time zone with "tz" - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * that time zone is used instead. * * @param aLocale the locale for the week data @@ -2632,8 +2632,8 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableUnicode locale extensions. + * calendar types can be used for the {@linkplain Locale##def_locale_extension + * Unicode locale extensions}. * The {@code Set} returned contains at least {@code "gregory"}. The * calendar types don't include aliases, such as {@code "gregorian"} for * {@code "gregory"}. @@ -2667,7 +2667,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableLocale extensions + * @see Locale##def_locale_extension Locale extensions * @see Locale.Builder#setLocale(Locale) * @see Locale.Builder#setUnicodeLocaleKeyword(String, String) */ diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java index b3807ac770a..b375a8ba941 100644 --- a/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/src/java.base/share/classes/java/util/ResourceBundle.java @@ -3052,8 +3052,8 @@ public abstract class ResourceBundle { * {@code IllegalArgumentException} is thrown.

        • * *
        • If the {@code locale}'s language is one of the - * Legacy language - * codes, either old or new, then repeat the loading process + * {@linkplain Locale##legacy_language_codes Legacy language + * codes}, either old or new, then repeat the loading process * if needed, with the bundle name with the other language. * For example, "iw" for "he" and vice versa. * diff --git a/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java b/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java index 76712257117..2109a4cead1 100644 --- a/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java +++ b/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,7 +145,7 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { /** * Returns a localized name for the given - * Unicode extension key, + * {@linkplain Locale##def_locale_extension Unicode extension} key, * and the given locale that is appropriate for display to the user. * If the name returned cannot be localized according to {@code locale}, * this method returns null. @@ -169,7 +169,7 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { /** * Returns a localized name for the given - * Unicode extension type, + * {@linkplain Locale##def_locale_extension Unicode extension} type, * and the given locale that is appropriate for display to the user. * If the name returned cannot be localized according to {@code locale}, * this method returns null. From 991ac9e6168b2573f78772e2d7936792a43fe336 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Tue, 2 Sep 2025 21:28:22 +0000 Subject: [PATCH 101/295] 8365407: Race condition in MethodTrainingData::verify() Reviewed-by: kvn, vlivanov, iklam --- .../share/compiler/compilationPolicy.cpp | 24 ++++---- .../share/compiler/compilationPolicy.hpp | 26 ++++---- src/hotspot/share/oops/trainingData.cpp | 59 ++++++++++++------- src/hotspot/share/oops/trainingData.hpp | 10 ++-- src/hotspot/share/runtime/init.cpp | 5 +- src/hotspot/share/runtime/java.cpp | 7 +++ 6 files changed, 73 insertions(+), 58 deletions(-) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 9c49d941bbc..80223a4e5cb 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -138,7 +138,7 @@ void CompilationPolicy::compile_if_required(const methodHandle& m, TRAPS) { } } -void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS) { +void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, JavaThread* current) { if (!klass->has_init_deps_processed()) { ResourceMark rm; log_debug(training)("Replay training: %s", klass->external_name()); @@ -150,11 +150,11 @@ void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS assert(klass->has_init_deps_processed(), ""); if (AOTCompileEagerly) { ktd->iterate_comp_deps([&](CompileTrainingData* ctd) { - if (ctd->init_deps_left() == 0) { + if (ctd->init_deps_left_acquire() == 0) { MethodTrainingData* mtd = ctd->method(); if (mtd->has_holder()) { - const methodHandle mh(THREAD, const_cast(mtd->holder())); - CompilationPolicy::maybe_compile_early(mh, THREAD); + const methodHandle mh(current, const_cast(mtd->holder())); + CompilationPolicy::maybe_compile_early(mh, current); } } }); @@ -163,10 +163,10 @@ void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS } } -void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, TRAPS) { +void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, JavaThread* current) { assert(klass->is_initialized(), ""); if (TrainingData::have_data() && klass->is_shared()) { - _training_replay_queue.push(klass, TrainingReplayQueue_lock, THREAD); + _training_replay_queue.push(klass, TrainingReplayQueue_lock, current); } } @@ -181,11 +181,11 @@ void CompilationPolicyUtils::Queue::print_on(outputStream* st) { } } -void CompilationPolicy::replay_training_at_init_loop(TRAPS) { +void CompilationPolicy::replay_training_at_init_loop(JavaThread* current) { while (!CompileBroker::is_compilation_disabled_forever()) { - InstanceKlass* ik = _training_replay_queue.pop(TrainingReplayQueue_lock, THREAD); + InstanceKlass* ik = _training_replay_queue.pop(TrainingReplayQueue_lock, current); if (ik != nullptr) { - replay_training_at_init_impl(ik, THREAD); + replay_training_at_init_impl(ik, current); } } } @@ -446,7 +446,7 @@ void CompilationPolicy::print_training_data_on(outputStream* st, const char* pr if (ctd == nullptr) { st->print("null"); } else { - st->print("%d", ctd->init_deps_left()); + st->print("%d", ctd->init_deps_left_acquire()); } } } @@ -1172,7 +1172,7 @@ CompLevel CompilationPolicy::trained_transition_from_none(const methodHandle& me CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); assert(ctd != nullptr, "Should have CTD for CompLevel_full_optimization"); // With SkipTier2IfPossible and all deps satisfied, go to level 4 immediately - if (SkipTier2IfPossible && ctd->init_deps_left() == 0) { + if (SkipTier2IfPossible && ctd->init_deps_left_acquire() == 0) { if (method->method_data() == nullptr) { create_mdo(method, THREAD); } @@ -1200,7 +1200,7 @@ CompLevel CompilationPolicy::trained_transition_from_limited_profile(const metho assert(training_has_profile, "Have to have a profile to be here"); // Check if the method is ready CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); - if (ctd != nullptr && ctd->init_deps_left() == 0) { + if (ctd != nullptr && ctd->init_deps_left_acquire() == 0) { if (method->method_data() == nullptr) { create_mdo(method, THREAD); } diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index f4a7c4c249b..d950ba418f9 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -74,32 +74,28 @@ class Queue { } public: Queue() : _head(nullptr), _tail(nullptr) { } - void push(T* value, Monitor* lock, TRAPS) { - MonitorLocker locker(THREAD, lock); + void push(T* value, Monitor* lock, JavaThread* current) { + MonitorLocker locker(current, lock); push_unlocked(value); locker.notify_all(); } bool is_empty_unlocked() const { return _head == nullptr; } - T* pop(Monitor* lock, TRAPS) { - MonitorLocker locker(THREAD, lock); - while(is_empty_unlocked() && !CompileBroker::is_compilation_disabled_forever()) { + T* pop(Monitor* lock, JavaThread* current) { + MonitorLocker locker(current, lock); + while (is_empty_unlocked() && !CompileBroker::is_compilation_disabled_forever()) { locker.wait(); } T* value = pop_unlocked(); return value; } - T* try_pop(Monitor* lock, TRAPS) { - MonitorLocker locker(THREAD, lock); - T* value = nullptr; - if (!is_empty_unlocked()) { - value = pop_unlocked(); - } + T* try_pop(Monitor* lock, JavaThread* current) { + MonitorLocker locker(current, lock); + T* value = pop_unlocked(); return value; } - void print_on(outputStream* st); }; } // namespace CompilationPolicyUtils @@ -342,7 +338,7 @@ class CompilationPolicy : AllStatic { // m must be compiled before executing it static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_any); static void maybe_compile_early(const methodHandle& m, TRAPS); - static void replay_training_at_init_impl(InstanceKlass* klass, TRAPS); + static void replay_training_at_init_impl(InstanceKlass* klass, JavaThread* current); public: static int min_invocations() { return Tier4MinInvocationThreshold; } static int c1_count() { return _c1_count; } @@ -352,8 +348,8 @@ class CompilationPolicy : AllStatic { // This supports the -Xcomp option. static void compile_if_required(const methodHandle& m, TRAPS); - static void replay_training_at_init(InstanceKlass* klass, TRAPS); - static void replay_training_at_init_loop(TRAPS); + static void replay_training_at_init(InstanceKlass* klass, JavaThread* current); + static void replay_training_at_init_loop(JavaThread* current); // m is allowed to be compiled static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_any); diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 70e8f2437c1..4797eed0a31 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -83,7 +83,7 @@ static void verify_archived_entry(TrainingData* td, const TrainingData::Key* k) } void TrainingData::verify() { - if (TrainingData::have_data()) { + if (TrainingData::have_data() && !TrainingData::assembling_data()) { archived_training_data_dictionary()->iterate([&](TrainingData* td) { if (td->is_KlassTrainingData()) { KlassTrainingData* ktd = td->as_KlassTrainingData(); @@ -98,9 +98,21 @@ void TrainingData::verify() { Key k(mtd->holder()); verify_archived_entry(td, &k); } - mtd->verify(); - } else if (td->is_CompileTrainingData()) { - td->as_CompileTrainingData()->verify(); + mtd->verify(/*verify_dep_counter*/true); + } + }); + } + if (TrainingData::need_data()) { + TrainingDataLocker l; + training_data_set()->iterate([&](TrainingData* td) { + if (td->is_KlassTrainingData()) { + KlassTrainingData* ktd = td->as_KlassTrainingData(); + ktd->verify(); + } else if (td->is_MethodTrainingData()) { + MethodTrainingData* mtd = td->as_MethodTrainingData(); + // During the training run init deps tracking is not setup yet, + // don't verify it. + mtd->verify(/*verify_dep_counter*/false); } }); } @@ -229,7 +241,7 @@ CompileTrainingData* CompileTrainingData::make(CompileTask* task) { } -void CompileTrainingData::dec_init_deps_left(KlassTrainingData* ktd) { +void CompileTrainingData::dec_init_deps_left_release(KlassTrainingData* ktd) { LogStreamHandle(Trace, training) log; if (log.is_enabled()) { log.print("CTD "); print_on(&log); log.cr(); @@ -450,7 +462,7 @@ void KlassTrainingData::notice_fully_initialized() { TrainingDataLocker l; // Not a real lock if we don't collect the data, // that's why we need the atomic decrement below. for (int i = 0; i < comp_dep_count(); i++) { - comp_dep(i)->dec_init_deps_left(this); + comp_dep(i)->dec_init_deps_left_release(this); } holder()->set_has_init_deps_processed(); } @@ -476,10 +488,10 @@ void TrainingData::init_dumptime_table(TRAPS) { _dumptime_training_data_dictionary->append(td); } }); + } - if (AOTVerifyTrainingData) { - training_data_set()->verify(); - } + if (AOTVerifyTrainingData) { + TrainingData::verify(); } } @@ -592,22 +604,13 @@ void KlassTrainingData::verify() { } } -void MethodTrainingData::verify() { - iterate_compiles([](CompileTrainingData* ctd) { - ctd->verify(); - - int init_deps_left1 = ctd->init_deps_left(); - int init_deps_left2 = ctd->compute_init_deps_left(); - - if (init_deps_left1 != init_deps_left2) { - ctd->print_on(tty); tty->cr(); - } - guarantee(init_deps_left1 == init_deps_left2, "mismatch: %d %d %d", - init_deps_left1, init_deps_left2, ctd->init_deps_left()); +void MethodTrainingData::verify(bool verify_dep_counter) { + iterate_compiles([&](CompileTrainingData* ctd) { + ctd->verify(verify_dep_counter); }); } -void CompileTrainingData::verify() { +void CompileTrainingData::verify(bool verify_dep_counter) { for (int i = 0; i < init_dep_count(); i++) { KlassTrainingData* ktd = init_dep(i); if (ktd->has_holder() && ktd->holder()->defined_by_other_loaders()) { @@ -624,6 +627,18 @@ void CompileTrainingData::verify() { } guarantee(ktd->_comp_deps.contains(this), ""); } + + if (verify_dep_counter) { + int init_deps_left1 = init_deps_left_acquire(); + int init_deps_left2 = compute_init_deps_left(); + + bool invariant = (init_deps_left1 >= init_deps_left2); + if (!invariant) { + print_on(tty); + tty->cr(); + } + guarantee(invariant, "init deps invariant violation: %d >= %d", init_deps_left1, init_deps_left2); + } } void CompileTrainingData::cleanup(Visitor& visitor) { diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index c47d0a0f66e..b909be12324 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -673,9 +673,9 @@ public: } _init_deps.clear(); } - void dec_init_deps_left(KlassTrainingData* ktd); - int init_deps_left() const { - return Atomic::load(&_init_deps_left); + void dec_init_deps_left_release(KlassTrainingData* ktd); + int init_deps_left_acquire() const { + return Atomic::load_acquire(&_init_deps_left); } uint compute_init_deps_left(bool count_initialized = false); @@ -707,7 +707,7 @@ public: return (int)align_metadata_size(align_up(sizeof(CompileTrainingData), BytesPerWord)/BytesPerWord); } - void verify(); + void verify(bool verify_dep_counter); static CompileTrainingData* allocate(MethodTrainingData* mtd, int level, int compile_id) { return TrainingData::allocate(mtd, level, compile_id); @@ -828,7 +828,7 @@ class MethodTrainingData : public TrainingData { return "{ method training data }"; }; - void verify(); + void verify(bool verify_dep_counter); static MethodTrainingData* allocate(Method* m, KlassTrainingData* ktd) { return TrainingData::allocate(m, ktd); diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 73292a7b6d9..56e6ea30c0a 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -195,10 +195,7 @@ jint init_globals2() { } #endif - // Initialize TrainingData only we're recording/replaying - if (TrainingData::have_data() || TrainingData::need_data()) { - TrainingData::initialize(); - } + TrainingData::initialize(); if (!universe_post_init()) { return JNI_ERR; diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index b3b46e5a9ab..351fd1ebb89 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -34,6 +34,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "compiler/compilationMemoryStatistic.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compilerOracle.hpp" #include "gc/shared/collectedHeap.hpp" @@ -503,6 +504,12 @@ void before_exit(JavaThread* thread, bool halt) { // Note: we don't wait until it actually dies. os::terminate_signal_thread(); + #if INCLUDE_CDS + if (AOTVerifyTrainingData) { + TrainingData::verify(); + } + #endif + print_statistics(); { MutexLocker ml(BeforeExit_lock); From b50c11f9077f071cf5639de7e82ec261e0338532 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 2 Sep 2025 23:04:52 +0000 Subject: [PATCH 102/295] 8366195: Remove unnecessary quotes around -Ta ml64 assembler argument Reviewed-by: erikj --- make/autoconf/flags.m4 | 4 ++++ make/autoconf/spec.gmk.template | 1 + make/common/native/CompileFile.gmk | 8 +------- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index d50538108a4..c810d15ebbc 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -320,12 +320,16 @@ AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL], [ if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then CC_OUT_OPTION=-Fo + if test "x$OPENJDK_TARGET_CPU" != xaarch64; then + AS_NON_ASM_EXTENSION_OPTION=-Ta + fi else # The option used to specify the target .o,.a or .so file. # When compiling, how to specify the to be created object file. CC_OUT_OPTION='-o$(SPACE)' fi AC_SUBST(CC_OUT_OPTION) + AC_SUBST(AS_NON_ASM_EXTENSION_OPTION) # Generate make dependency files if test "x$TOOLCHAIN_TYPE" = xgcc; then diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index c96b730c6fa..e3345940101 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -492,6 +492,7 @@ CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@ HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@ CC_OUT_OPTION := @CC_OUT_OPTION@ +AS_NON_ASM_EXTENSION_OPTION := @AS_NON_ASM_EXTENSION_OPTION@ # Flags used for overriding the default opt setting for a C/C++ source file. C_O_FLAG_HIGHEST_JVM := @C_O_FLAG_HIGHEST_JVM@ diff --git a/make/common/native/CompileFile.gmk b/make/common/native/CompileFile.gmk index 39b5f34a4c5..a8d46949788 100644 --- a/make/common/native/CompileFile.gmk +++ b/make/common/native/CompileFile.gmk @@ -155,12 +155,6 @@ define CreateCompiledNativeFileBody endif $1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \ -include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h - else ifeq ($(TOOLCHAIN_TYPE), microsoft) - ifeq ($(OPENJDK_TARGET_CPU), aarch64) - $1_NON_ASM_EXTENSION_FLAG := - else - $1_NON_ASM_EXTENSION_FLAG := "-Ta" - endif endif else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), ) # Compile as a C++ or Objective-C++ file @@ -242,7 +236,7 @@ define CreateCompiledNativeFileBody # For assembler calls just create empty dependency lists $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ $$($1_COMPILER) $$($1_FLAGS) \ - $(CC_OUT_OPTION)$$($1_OBJ) $$($1_NON_ASM_EXTENSION_FLAG) $$($1_SRC_FILE))) \ + $(CC_OUT_OPTION)$$($1_OBJ) $(AS_NON_ASM_EXTENSION_OPTION) $$($1_SRC_FILE))) \ | $(TR) -d '\r' | $(GREP) -v -e "Assembling:" || test "$$$$?" = "1" ; \ $(ECHO) > $$($1_DEPS_FILE) ; \ $(ECHO) > $$($1_DEPS_TARGETS_FILE) From 5052a7eee57e9d145950a0ab1ca71edc02bfe0be Mon Sep 17 00:00:00 2001 From: Rui Li Date: Tue, 2 Sep 2025 23:49:23 +0000 Subject: [PATCH 103/295] 8246037: Shenandoah: update man pages to mention -XX:+UseShenandoahGC Reviewed-by: ysr, wkemper, cslucas --- .../gc/shenandoah/shenandoah_globals.hpp | 6 ++- src/java.base/share/man/java.md | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index c51f4f16489..026f352701d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -141,10 +141,12 @@ "GC heuristics to use. This fine-tunes the GC mode selected, " \ "by choosing when to start the GC, how much to process on each " \ "cycle, and what other features to automatically enable. " \ - "Possible values are:" \ + "When -XX:ShenandoahGCMode is generational, the only supported " \ + "option is the default, adaptive. Possible values are:" \ " adaptive - adapt to maintain the given amount of free heap " \ "at all times, even during the GC cycle;" \ - " static - trigger GC when free heap falls below the threshold;" \ + " static - trigger GC when free heap falls below a specified " \ + "threshold;" \ " aggressive - run GC continuously, try to evacuate everything;" \ " compact - run GC more frequently and with deeper targets to " \ "free up more memory.") \ diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 9a750f8cf1f..1a6a944594f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2882,6 +2882,46 @@ Java HotSpot VM. expensive operations. Using a lower value will cause heap memory to be uncommitted earlier, at the risk of soon having to commit it again. +`-XX:+UseShenandoahGC` +: Enables the use of the Shenandoah garbage collector. This is a low pause + time, concurrent garbage collector. Its pause times are not proportional to + the size of the heap. Shenandoah garbage collector can work with compressed + pointers. See `-XX:UseCompressedOops` for further information about + compressed pointers. + +`-XX:ShenandoahGCMode=`*mode* +: Sets the GC mode for Shenandoah GC to use. By default, this option is set + to `satb`. Among other things, this defines which barriers are in use. + Possible mode values include the following: + + `satb` + : Snapshot-at-the-beginning concurrent GC (three pass mark-evac-update). + It is a single generation GC. + + `generational` + : It is also a snapshot-at-the-beginning and concurrent GC, but it is + generational. Please see [JEP 404](https://openjdk.org/jeps/404) and + [JEP 521](https://openjdk.org/jeps/521) for its advantages and risks. + +`-XX:ShenandoahGCHeuristics=`*heuristics* +: Sets the heuristics for Shenandoah GC to use. By default, this option is + set to `adaptive`. This fine-tunes the GC mode selected, by choosing when + to start the GC, how much to process on each cycle, and what other features + to automatically enable. When `-XX:ShenandoahGCMode` is `generational`, the + only supported option is the default, `adaptive`. + + Possible heuristics are the following: + + `adaptive` + : To maintain the given amount of free heap at all times, even during + the GC cycle. + + `static` + : Trigger GC when free heap falls below a specified threshold. + + `compact` + : Run GC more frequently and with deeper targets to free up more memory. + ## Deprecated Java Options These `java` options are deprecated and might be removed in a future JDK From e268563a10b67bdcb3c030743ed3e2b3b7dfd0f7 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 3 Sep 2025 00:57:52 +0000 Subject: [PATCH 104/295] 8366476: Test gc/z/TestSmallHeap.java fails OOM with many NUMA nodes Reviewed-by: jsikstro, aboldtch --- test/hotspot/jtreg/gc/z/TestSmallHeap.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/z/TestSmallHeap.java b/test/hotspot/jtreg/gc/z/TestSmallHeap.java index c3c0dddd8e8..9a65227a10b 100644 --- a/test/hotspot/jtreg/gc/z/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/z/TestSmallHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,8 @@ public class TestSmallHeap { public static void main(String[] args) throws Exception { for (var maxCapacity: args) { ProcessTools.executeTestJava( + // Disable NUMA to avoid potential OOM after JDK-8359683 + "-XX:-UseNUMA", "-XX:+UseZGC", "-Xlog:gc,gc+init,gc+reloc,gc+heap", "-Xmx" + maxCapacity, From 8c4090c2cfa00f9c3550669a0726a785b30ac1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 3 Sep 2025 06:38:27 +0000 Subject: [PATCH 105/295] 8329077: C2 SuperWord: Add MoveD2L, MoveL2D, MoveF2I, MoveI2F Reviewed-by: epeter, qamai --- src/hotspot/share/opto/superword.cpp | 2 + src/hotspot/share/opto/vectornode.cpp | 4 ++ .../TestCompatibleUseDefTypeSize.java | 24 ++++++----- .../vm/compiler/TypeVectorOperations.java | 43 +++++++++++++++++++ 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 7b47992e77e..2b3928781b8 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -1648,6 +1648,8 @@ bool SuperWord::implemented(const Node_List* pack, const uint size) const { retValue = ReductionNode::implemented(opc, size, arith_type->basic_type()); } else if (VectorNode::is_convert_opcode(opc)) { retValue = VectorCastNode::implemented(opc, size, velt_basic_type(p0->in(1)), velt_basic_type(p0)); + } else if (VectorNode::is_reinterpret_opcode(opc)) { + retValue = Matcher::match_rule_supported_auto_vectorization(Op_VectorReinterpret, size, velt_basic_type(p0)); } else if (VectorNode::is_minmax_opcode(opc) && is_subword_type(velt_basic_type(p0))) { // Java API for Math.min/max operations supports only int, long, float // and double types. Thus, avoid generating vector min/max nodes for diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index c126c91da1b..2153a12c402 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -992,6 +992,10 @@ bool VectorNode::is_vector_bitwise_not_pattern(Node* n) { bool VectorNode::is_reinterpret_opcode(int opc) { switch (opc) { + case Op_MoveF2I: + case Op_MoveD2L: + case Op_MoveL2D: + case Op_MoveI2F: case Op_ReinterpretHF2S: case Op_ReinterpretS2HF: return true; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java index f5445f3106b..e6c373c4c87 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java @@ -395,7 +395,7 @@ public class TestCompatibleUseDefTypeSize { // In theory, one would expect this to be a simple 4byte -> 4byte conversion. // But there is a CmpF and CMove here because we check for isNaN. Plus a MoveF2I. // - // Would be nice to vectorize: Missing support for CmpF, CMove and MoveF2I. + // Would be nice to vectorize: Missing support for CmpF and CMove. static Object[] test5(int[] a, float[] b) { for (int i = 0; i < a.length; i++) { a[i] = Float.floatToIntBits(b[i]); @@ -404,10 +404,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveF2I static Object[] test6(int[] a, float[] b) { for (int i = 0; i < a.length; i++) { a[i] = Float.floatToRawIntBits(b[i]); @@ -416,10 +417,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveI2F static Object[] test7(int[] a, float[] b) { for (int i = 0; i < a.length; i++) { b[i] = Float.intBitsToFloat(a[i]); @@ -431,7 +433,7 @@ public class TestCompatibleUseDefTypeSize { @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for Needs CmpD, CMove and MoveD2L + // Missing support to vectorize CmpD and CMove static Object[] test8(long[] a, double[] b) { for (int i = 0; i < a.length; i++) { a[i] = Double.doubleToLongBits(b[i]); @@ -440,10 +442,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveD2L static Object[] test9(long[] a, double[] b) { for (int i = 0; i < a.length; i++) { a[i] = Double.doubleToRawLongBits(b[i]); @@ -452,10 +455,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveL2D static Object[] test10(long[] a, double[] b) { for (int i = 0; i < a.length; i++) { b[i] = Double.longBitsToDouble(a[i]); diff --git a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java index c39107fdd00..fcdbb9356e0 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java +++ b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025 IBM Corporation. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -262,6 +263,20 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertD2LBits() { + for (int i = 0; i < COUNT; i++) { + resL[i] = Double.doubleToLongBits(doubles[i]); + } + } + + @Benchmark + public void convertD2LBitsRaw() { + for (int i = 0; i < COUNT; i++) { + resL[i] = Double.doubleToRawLongBits(doubles[i]); + } + } + @Benchmark public void convertF2I() { for (int i = 0; i < COUNT; i++) { @@ -269,6 +284,20 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertF2IBits() { + for (int i = 0; i < COUNT; i++) { + resI[i] = Float.floatToIntBits(floats[i]); + } + } + + @Benchmark + public void convertF2IBitsRaw() { + for (int i = 0; i < COUNT; i++) { + resI[i] = (int) Float.floatToRawIntBits(floats[i]); + } + } + @Benchmark public void convertF2B() { for (int i = 0; i < COUNT; i++) { @@ -304,6 +333,13 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertIBits2F() { + for (int i = 0; i < COUNT; i++) { + resF[i] = Float.intBitsToFloat(ints[i]); + } + } + @Benchmark public void convertI2D() { for (int i = 0; i < COUNT; i++) { @@ -325,6 +361,13 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertLBits2D() { + for (int i = 0; i < COUNT; i++) { + resD[i] = Double.longBitsToDouble(longs[i]); + } + } + @Benchmark public void convertL2B() { for (int i = 0; i < COUNT; i++) { From 7c70e7341438ce8a420021005a0f03fe917e5a26 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 3 Sep 2025 06:45:02 +0000 Subject: [PATCH 106/295] 8366660: Sort share/nmt includes Reviewed-by: ayang, shade --- src/hotspot/share/nmt/arrayWithFreeList.hpp | 1 + src/hotspot/share/nmt/mallocLimit.cpp | 4 ++-- src/hotspot/share/nmt/mallocTracker.cpp | 2 +- src/hotspot/share/nmt/mallocTracker.inline.hpp | 3 ++- src/hotspot/share/nmt/memMapPrinter.cpp | 4 ++-- src/hotspot/share/nmt/memReporter.cpp | 7 +++---- src/hotspot/share/nmt/memTracker.hpp | 2 +- src/hotspot/share/nmt/memoryFileTracker.cpp | 2 +- src/hotspot/share/nmt/memoryFileTracker.hpp | 2 +- src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp | 1 + src/hotspot/share/nmt/regionsTree.inline.hpp | 1 + src/hotspot/share/nmt/virtualMemoryTracker.cpp | 3 +-- src/hotspot/share/nmt/virtualMemoryTracker.hpp | 2 +- src/hotspot/share/nmt/vmatree.hpp | 2 +- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 15 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/nmt/arrayWithFreeList.hpp b/src/hotspot/share/nmt/arrayWithFreeList.hpp index 2c1812dcc52..03a44f8c20b 100644 --- a/src/hotspot/share/nmt/arrayWithFreeList.hpp +++ b/src/hotspot/share/nmt/arrayWithFreeList.hpp @@ -26,6 +26,7 @@ #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 diff --git a/src/hotspot/share/nmt/mallocLimit.cpp b/src/hotspot/share/nmt/mallocLimit.cpp index 2bce2e459e0..1751cb59ae7 100644 --- a/src/hotspot/share/nmt/mallocLimit.cpp +++ b/src/hotspot/share/nmt/mallocLimit.cpp @@ -26,11 +26,11 @@ #include "nmt/mallocLimit.hpp" #include "nmt/memTag.hpp" #include "nmt/nmtCommon.hpp" -#include "runtime/java.hpp" #include "runtime/globals.hpp" +#include "runtime/java.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/parseInteger.hpp" #include "utilities/ostream.hpp" +#include "utilities/parseInteger.hpp" MallocLimitSet MallocLimitHandler::_limits; bool MallocLimitHandler::_have_limit = false; diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp index d919f3ce873..ab3cb322107 100644 --- a/src/hotspot/share/nmt/mallocTracker.cpp +++ b/src/hotspot/share/nmt/mallocTracker.cpp @@ -40,10 +40,10 @@ #include "runtime/os.hpp" #include "runtime/safefetch.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/vmError.hpp" -#include "utilities/globalDefinitions.hpp" MallocMemorySnapshot MallocMemorySummary::_snapshot; diff --git a/src/hotspot/share/nmt/mallocTracker.inline.hpp b/src/hotspot/share/nmt/mallocTracker.inline.hpp index 51a7f28cf99..abf0a499a9d 100644 --- a/src/hotspot/share/nmt/mallocTracker.inline.hpp +++ b/src/hotspot/share/nmt/mallocTracker.inline.hpp @@ -26,8 +26,9 @@ #ifndef SHARE_NMT_MALLOCTRACKER_INLINE_HPP #define SHARE_NMT_MALLOCTRACKER_INLINE_HPP -#include "nmt/mallocLimit.hpp" #include "nmt/mallocTracker.hpp" + +#include "nmt/mallocLimit.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp index 41d977e9639..6086b1a6fd1 100644 --- a/src/hotspot/share/nmt/memMapPrinter.cpp +++ b/src/hotspot/share/nmt/memMapPrinter.cpp @@ -28,11 +28,11 @@ #include "gc/shared/collectedHeap.hpp" #include "logging/logAsyncWriter.hpp" #include "memory/allocation.hpp" -#include "memory/universe.hpp" #include "memory/resourceArea.hpp" +#include "memory/universe.hpp" +#include "nmt/memMapPrinter.hpp" #include "nmt/memTag.hpp" #include "nmt/memTagBitmap.hpp" -#include "nmt/memMapPrinter.hpp" #include "nmt/memTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/nonJavaThread.hpp" diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index a7c564eff53..65d4d76942b 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -26,11 +26,10 @@ #include "memory/metaspace.hpp" #include "memory/metaspaceUtils.hpp" #include "nmt/mallocTracker.hpp" -#include "nmt/memTag.hpp" -#include "nmt/memReporter.hpp" -#include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" -#include "nmt/regionsTree.hpp" +#include "nmt/memReporter.hpp" +#include "nmt/memTag.hpp" +#include "nmt/memTracker.hpp" #include "nmt/regionsTree.inline.hpp" #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 124c6163d76..b6a9ed261de 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -28,8 +28,8 @@ #include "memory/reservedSpace.hpp" #include "nmt/mallocTracker.hpp" #include "nmt/memBaseline.hpp" -#include "nmt/nmtCommon.hpp" #include "nmt/memoryFileTracker.hpp" +#include "nmt/nmtCommon.hpp" #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/nmt/memoryFileTracker.cpp b/src/hotspot/share/nmt/memoryFileTracker.cpp index 55f1cb64626..2f3f4f1973a 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.cpp +++ b/src/hotspot/share/nmt/memoryFileTracker.cpp @@ -23,8 +23,8 @@ */ #include "memory/allocation.hpp" -#include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" +#include "nmt/memTracker.hpp" #include "nmt/nmtCommon.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" #include "nmt/vmatree.hpp" diff --git a/src/hotspot/share/nmt/memoryFileTracker.hpp b/src/hotspot/share/nmt/memoryFileTracker.hpp index 1b23dacab81..1e8bd40ed50 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.hpp +++ b/src/hotspot/share/nmt/memoryFileTracker.hpp @@ -28,8 +28,8 @@ #include "memory/allocation.hpp" #include "nmt/nmtCommon.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" -#include "nmt/vmatree.hpp" #include "nmt/virtualMemoryTracker.hpp" +#include "nmt/vmatree.hpp" #include "runtime/os.inline.hpp" #include "utilities/deferredStatic.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 85e044c1a45..6f194cfa5a1 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -28,6 +28,7 @@ #include "nmt/arrayWithFreeList.hpp" #include "utilities/growableArray.hpp" #include "utilities/nativeCallStack.hpp" + #include // Virtual memory regions that are tracked by NMT also have their NativeCallStack (NCS) tracked. diff --git a/src/hotspot/share/nmt/regionsTree.inline.hpp b/src/hotspot/share/nmt/regionsTree.inline.hpp index 665f4a93c88..98cfa0e7f2c 100644 --- a/src/hotspot/share/nmt/regionsTree.inline.hpp +++ b/src/hotspot/share/nmt/regionsTree.inline.hpp @@ -25,6 +25,7 @@ #define SHARE_NMT_REGIONSTREE_INLINE_HPP #include "nmt/regionsTree.hpp" + #include "nmt/virtualMemoryTracker.hpp" template diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index 8a97253860c..bdb31d5c992 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -24,9 +24,8 @@ #include "logging/log.hpp" #include "nmt/memTracker.hpp" -#include "nmt/virtualMemoryTracker.hpp" -#include "nmt/regionsTree.hpp" #include "nmt/regionsTree.inline.hpp" +#include "nmt/virtualMemoryTracker.hpp" #include "runtime/os.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.hpp b/src/hotspot/share/nmt/virtualMemoryTracker.hpp index 3c6c1efd6a2..121fcbbda4b 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.hpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.hpp @@ -26,8 +26,8 @@ #define SHARE_NMT_VIRTUALMEMORYTRACKER_HPP #include "nmt/allocationSite.hpp" -#include "nmt/vmatree.hpp" #include "nmt/regionsTree.hpp" +#include "nmt/vmatree.hpp" #include "runtime/atomic.hpp" #include "utilities/nativeCallStack.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index d2acabdae07..01f0e107a56 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -26,12 +26,12 @@ #ifndef SHARE_NMT_VMATREE_HPP #define SHARE_NMT_VMATREE_HPP -#include "nmt/memTag.hpp" #include "nmt/memTag.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" #include "utilities/rbTree.inline.hpp" + #include // A VMATree stores a sequence of points on the natural number line. diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index be35f8fa2b2..695b300f3fd 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -57,6 +57,7 @@ public class TestIncludesAreSorted { "share/logging", "share/memory", "share/metaprogramming", + "share/nmt", "share/oops", "share/opto", "share/precompiled", From 6dda2f6fad5cae95057fbdfa672e3b51aff61af7 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Sep 2025 07:52:28 +0000 Subject: [PATCH 107/295] 8366543: Clean up include headers in numberSeq Reviewed-by: tschatzl --- src/hotspot/share/utilities/numberSeq.cpp | 1 - src/hotspot/share/utilities/numberSeq.hpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/numberSeq.cpp b/src/hotspot/share/utilities/numberSeq.cpp index 276c5cb01ff..536f6563866 100644 --- a/src/hotspot/share/utilities/numberSeq.cpp +++ b/src/hotspot/share/utilities/numberSeq.cpp @@ -22,7 +22,6 @@ * */ -#include "memory/allocation.inline.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/numberSeq.hpp" diff --git a/src/hotspot/share/utilities/numberSeq.hpp b/src/hotspot/share/utilities/numberSeq.hpp index b57fdf45576..fff4b416745 100644 --- a/src/hotspot/share/utilities/numberSeq.hpp +++ b/src/hotspot/share/utilities/numberSeq.hpp @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_NUMBERSEQ_HPP #include "memory/allocation.hpp" +#include "utilities/ostream.hpp" /** ** This file contains a few classes that represent number sequence, From 3b2f3e53d7f27653c3d4608b141aed6a84829aa8 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Wed, 3 Sep 2025 12:36:36 +0000 Subject: [PATCH 108/295] 8366803: Bump timeout on sun/tools/jhsdb/BasicLauncherTest.java Reviewed-by: stefank --- test/jdk/sun/tools/jhsdb/BasicLauncherTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java b/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java index d2ca78f044a..75f2af6db5a 100644 --- a/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java +++ b/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @requires vm.hasSA * @build jdk.test.lib.apps.* - * @run main BasicLauncherTest + * @run main/timeout=480 BasicLauncherTest */ import java.io.BufferedReader; From 2a5f149bb8e26277778465fff670591c929842de Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Sep 2025 12:41:24 +0000 Subject: [PATCH 109/295] 8363966: GHA: Switch cross-compiling sysroots to Debian trixie Reviewed-by: ayang, fyang, erikj --- .github/workflows/build-cross-compile.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index 351d087ef7d..b3c63f488a0 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -64,33 +64,33 @@ jobs: gnu-arch: aarch64 debian-arch: arm64 debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false - target-cpu: arm gnu-arch: arm debian-arch: armhf debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false gnu-abi: eabihf - target-cpu: s390x gnu-arch: s390x debian-arch: s390x debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false - target-cpu: ppc64le gnu-arch: powerpc64le debian-arch: ppc64el debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false - target-cpu: riscv64 gnu-arch: riscv64 debian-arch: riscv64 debian-repository: https://httpredir.debian.org/debian/ - debian-version: sid - tolerate-sysroot-errors: true + debian-version: trixie + tolerate-sysroot-errors: false steps: - name: 'Checkout the JDK source' From 3abaa83610efb5c8e9b86c6f895d6b58d21e1fa2 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 3 Sep 2025 13:51:17 +0000 Subject: [PATCH 110/295] 8366298: FDLeakTest sometimes takes minutes to complete on Linux Reviewed-by: lkorinth, rriggs, stuefe --- .../ProcessBuilder/FDLeakTest/FDLeakTest.java | 6 +-- .../ProcessBuilder/FDLeakTest/libFDLeaker.c | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java index 02f3583f0b3..146c2be563f 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java @@ -27,7 +27,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest */ /** @@ -35,7 +35,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest */ /** @@ -43,7 +43,7 @@ * @summary Check that we don't leak FDs * @requires os.family == "linux" * @library /test/lib - * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest */ import jdk.test.lib.process.ProcessTools; diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c index b3fa296cae2..afec94f65c7 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c @@ -21,16 +21,55 @@ * questions. */ +#include #include +#include +#include +#include #include "jvmti.h" +static jint limit_num_fds(); + JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + // Lower the number of possible open files to make the test go faster + jint ret = limit_num_fds(); + if (ret != 0) { + fprintf(stderr, "Failed to limit number of fds: %s", strerror(errno)); + return ret; + } + const char* filename = "./testfile_FDLeaker.txt"; FILE* f = fopen(filename, "w"); if (f == NULL) { + fprintf(stderr, "Failed to open file: %s", strerror(errno)); return JNI_ERR; } + printf("Opened and leaked %s (%d)", filename, fileno(f)); return JNI_OK; } + +static jint limit_num_fds() { + struct rlimit rl; + + // Fetch the current limit + int ret = getrlimit(RLIMIT_NOFILE, &rl); + if (ret != 0) { + return JNI_ERR; + } + + // Use a lower value unless it is already low + rlim_t limit = 100; + if (limit < rl.rlim_cur) { + rl.rlim_cur = limit; + } + + // Lower the value + int ret2 = setrlimit(RLIMIT_NOFILE, &rl); + if (ret2 != 0) { + return JNI_ERR; + } + + return JNI_OK; +} From d5935af228d7129d75d6987767de50b019ec30c7 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 3 Sep 2025 14:40:23 +0000 Subject: [PATCH 111/295] 8366768: Problemlist jdk/jshell/ToolSimpleTest.java Reviewed-by: jlahoda --- test/langtools/ProblemList.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 1d8df78266a..e1124f4784a 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. # 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,6 +52,8 @@ jdk/jshell/UserJdiUserRemoteTest.java jdk/jshell/UserInputTest.java 8169536 generic-all jdk/jshell/ToolBasicTest.java 8265357 macosx-aarch64 jdk/jshell/HighlightUITest.java 8284144 generic-all +jdk/jshell/ToolSimpleTest.java 8366582 windows-x64 +jdk/jshell/ToolLocalSimpleTest.java 8366582 windows-x64 ########################################################################### # From a40afdd08f366afcefb1ac9d5fb184c8e803707e Mon Sep 17 00:00:00 2001 From: Vanitha B P Date: Wed, 3 Sep 2025 15:31:15 +0000 Subject: [PATCH 112/295] 8366537: Test "java/util/TimeZone/DefaultTimeZoneTest.java" is not updating the zone ID as expected Reviewed-by: naoto, jlu --- .../util/TimeZone/DefaultTimeZoneTest.java | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java index 4dd644d58b5..b386d39d499 100644 --- a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,11 @@ import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.BoxLayout; +import javax.swing.Box; +import java.awt.Dimension; +import java.awt.Component; import java.awt.BorderLayout; import java.awt.Window; import java.lang.reflect.InvocationTargetException; @@ -98,17 +103,36 @@ public class DefaultTimeZoneTest { private static Window createTest() { var contents = new JFrame("DefaultTimeZoneTest"); - var label = new JLabel(SDF.format(new Date())); - var panel = new JPanel(); - var button = new JButton("Update Time Zone"); - panel.add(button); contents.setSize(350, 250); - contents.add(label, BorderLayout.NORTH); - contents.add(panel, BorderLayout.CENTER); + // Panel with vertical layout + var panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); + // Time zone ID label + var timeZoneID = new JLabel("Time zone ID: " + SDF.getTimeZone().getID(), SwingConstants.CENTER); + timeZoneID.setAlignmentX(Component.CENTER_ALIGNMENT); + // Time label + var label = new JLabel(SDF.format(new Date()), SwingConstants.CENTER); + label.setAlignmentX(Component.CENTER_ALIGNMENT); + // Update button + var button = new JButton("Update Time Zone"); + button.setAlignmentX(Component.CENTER_ALIGNMENT); + // Add components with spacing + panel.add(Box.createRigidArea(new Dimension(0, 10))); + panel.add(timeZoneID); + panel.add(Box.createRigidArea(new Dimension(0, 5))); + panel.add(label); + panel.add(Box.createRigidArea(new Dimension(0, 10))); + panel.add(button); + contents.add(panel); + // Update default time zone on button click button.addActionListener(e -> { + // Clear JVM cached timezone and force reload from OS + TimeZone.setDefault(null); + System.setProperty("user.timezone", ""); TimeZone tz = TimeZone.getDefault(); SDF.setTimeZone(tz); + timeZoneID.setText("Time zone ID: " + tz.getID()); label.setText(SDF.format(new Date())); contents.repaint(); }); From e3b36e3babb860d9d24a610160f47d42cfaafaa3 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Sep 2025 18:00:13 +0000 Subject: [PATCH 113/295] 8366401: JCK test api/java_text/DecimalFormatSymbols/serial/InputTests.html fails after JDK-8363972 Reviewed-by: naoto --- .../java/text/DecimalFormatSymbols.java | 3 +- .../DecimalFormat/DFSSerializationTest.java | 264 ++++++++++++++++++ 2 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index ccb6c02535c..c255b93bd98 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -1015,7 +1015,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { currencyInitialized = true; } - if (loadNumberData(locale) instanceof Object[] d && + // `locale` was once nullable, need to check before loading locale data + if (locale != null && loadNumberData(locale) instanceof Object[] d && d[0] instanceof String[] numberElements && numberElements.length >= 14) { lenientMinusSigns = numberElements[13]; diff --git a/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java new file mode 100644 index 00000000000..9e875e851c8 --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8366401 + * @summary Check serialization of DecimalFormatSymbols. That is, ensure the + * behavior for each stream version is correct during de-serialization. + * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED DFSSerializationTest + */ + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.text.DecimalFormatSymbols; +import java.util.Currency; +import java.util.Locale; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class DFSSerializationTest { + + @Nested + class VersionTests { + + // Ensure correct monetarySeparator and exponential field defaults + // Reads monetary from decimal, and sets exponential to 'E' + @Test + public void version0Test() { + var crafted = new DFSBuilder() + .setVer(0) + .set("monetarySeparator", '~') + .set("exponential", 'Z') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + // Check exponential is set to proper default 'E', not 'Z' + assertEquals('E', readField(dfs, "exponential")); + // Ensure that mSep is based on dSep, and is not '~' + assertNotEquals('~', dfs.getMonetaryDecimalSeparator()); + assertEquals(dfs.getDecimalSeparator(), dfs.getMonetaryDecimalSeparator()); + } + + // Version 1 did not have a locale field, and it defaulted to Locale.ROOT. + // Note that other versions did allow a locale field, which was nullable. + // E.g. see nullableLocaleTest which does not set locale when it is `null` + @Test + public void version1Test() { + var crafted = new DFSBuilder() + .setVer(1) + .set("locale", null) + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(Locale.ROOT, dfs.getLocale()); + } + + // Version 2 did not have an exponential separator, and created it via exponent + // char field. + @Test + public void version2Test() { + var crafted = new DFSBuilder() + .setVer(2) + .set("exponentialSeparator", null) + .set("exponential", '~') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals("~", dfs.getExponentSeparator()); + } + + // Version 3 didn't have perMillText, percentText, and minusSignText. + // These were created from the corresponding char equivalents. + @Test + public void version3Test() { + var crafted = new DFSBuilder() + .setVer(3) + .set("perMillText", null) + .set("percentText", null) + .set("minusSignText", null) + .set("perMill", '~') + .set("percent", '~') + .set("minusSign", '~') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + // Need to check these String fields using reflection, since they + // are not exposed via the public API + assertEquals("~", readField(dfs, "perMillText")); + assertEquals("~", readField(dfs, "percentText")); + assertEquals("~", readField(dfs, "minusSignText")); + } + + // Version 4 did not have monetaryGroupingSeparator. It should be based + // off of groupingSeparator. + @Test + public void version4Test() { + var crafted = new DFSBuilder() + .setVer(4) + .set("monetaryGroupingSeparator", 'Z') + .set("groupingSeparator", '~') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(dfs.getGroupingSeparator(), dfs.getMonetaryGroupingSeparator()); + } + } + + // Up-to-date DFS stream versions do not expect a null locale since the + // standard DecimalFormatSymbols API forbids it. However, this was not always + // the case and previous stream versions can contain a null locale. Thus, + // ensure that a null locale does not cause number data loading to fail. + @Test + public void nullableLocaleTest() { + var bytes = ser(new DFSBuilder() + .set("locale", null) + .set("minusSignText", "zFoo") + .set("minusSign", 'z') // Set so that char/String forms agree + .build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertNull(dfs.getLocale()); + // LMS should be based off of minusSignText when locale is null + assertEquals("zFoo", readField(dfs, "lenientMinusSigns")); + } + + // readObject fails when the {@code char} and {@code String} representations + // of percent, per mille, and/or minus sign disagree. + @Test + public void disagreeingTextTest() { + var expected = "'char' and 'String' representations of either percent, " + + "per mille, and/or minus sign disagree."; + assertEquals(expected, assertThrows(InvalidObjectException.class, () -> + deSer(ser(new DFSBuilder() + .set("minusSignText", "Z") + .set("minusSign", 'X') + .build()))).getMessage()); + assertEquals(expected, assertThrows(InvalidObjectException.class, () -> + deSer(ser(new DFSBuilder() + .set("perMillText", "Z") + .set("perMill", 'X') + .build()))).getMessage()); + assertEquals(expected, assertThrows(InvalidObjectException.class, () -> + deSer(ser(new DFSBuilder() + .set("percentText", "Z") + .set("percent", 'X') + .build()))).getMessage()); + } + + // Ensure the serial version is updated to the current after de-serialization. + @Test + public void updatedVersionTest() { + var bytes = ser(new DFSBuilder().setVer(-25).build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(5, readField(dfs, "serialVersionOnStream")); + } + + // Should set currency from 4217 code when it is valid. + @Test + public void validIntlCurrencyTest() { + var bytes = ser(new DFSBuilder().set("intlCurrencySymbol", "JPY").build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(Currency.getInstance("JPY"), dfs.getCurrency()); + } + + // Should not set currency when 4217 code is invalid, it remains null. + @Test + public void invalidIntlCurrencyTest() { + var bytes = ser(new DFSBuilder() + .set("intlCurrencySymbol", ">.,") + .set("locale", Locale.JAPAN) + .build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + // Can not init off invalid 4217 code, remains null + assertNull(dfs.getCurrency()); + } + +// Utilities ---- + + // Utility to serialize + private static byte[] ser(Object obj) { + return assertDoesNotThrow(() -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) { + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); + } + }, "Unexpected error during serialization"); + } + + // Utility to deserialize + private static DecimalFormatSymbols deSer(byte[] bytes) throws IOException, ClassNotFoundException { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { + return (DecimalFormatSymbols) ois.readObject(); + } + } + + // Utility to read a private field + private static Object readField(DecimalFormatSymbols dfs, String name) { + return assertDoesNotThrow(() -> { + var field = DecimalFormatSymbols.class.getDeclaredField(name); + field.setAccessible(true); + return field.get(dfs); + }, "Unexpected error during field reading"); + } + + // Utility class to build instances of DFS via reflection + private static class DFSBuilder { + + private final DecimalFormatSymbols dfs; + + private DFSBuilder() { + dfs = new DecimalFormatSymbols(); + } + + private DFSBuilder setVer(Object value) { + return set("serialVersionOnStream", value); + } + + private DFSBuilder set(String field, Object value) { + return assertDoesNotThrow(() -> { + Field f = dfs.getClass().getDeclaredField(field); + f.setAccessible(true); + f.set(dfs, value); + return this; + }, "Unexpected error during reflection setting"); + } + + private DecimalFormatSymbols build() { + return dfs; + } + } +} From 8d236615b7db2bd5a2a59002b79e59cf4e6a308a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Sep 2025 18:47:58 +0000 Subject: [PATCH 114/295] 8366155: Serial: Obsolete PretenureSizeThreshold Reviewed-by: tschatzl --- .../share/gc/serial/defNewGeneration.cpp | 1 - .../share/gc/serial/defNewGeneration.hpp | 20 ------- src/hotspot/share/gc/serial/serialHeap.cpp | 52 ++++--------------- src/hotspot/share/gc/serial/serialHeap.hpp | 5 -- .../share/gc/serial/tenuredGeneration.hpp | 9 ---- src/hotspot/share/gc/shared/gc_globals.hpp | 5 -- src/hotspot/share/runtime/arguments.cpp | 2 + 7 files changed, 11 insertions(+), 83 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index a3d45a98354..3eab4a2e5fe 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -267,7 +267,6 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, update_counters(); _old_gen = nullptr; _tenuring_threshold = MaxTenuringThreshold; - _pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize; _ref_processor = nullptr; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index c5e1c2b152e..7f4077873b2 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -55,8 +55,6 @@ class DefNewGeneration: public Generation { uint _tenuring_threshold; // Tenuring threshold for next collection. AgeTable _age_table; - // Size of object to pretenure in words; command line provides bytes - size_t _pretenure_size_threshold_words; // ("Weak") Reference processing support SpanSubjectToDiscoveryClosure _span_based_discoverer; @@ -185,24 +183,6 @@ class DefNewGeneration: public Generation { HeapWord* block_start(const void* p) const; - // Allocation support - bool should_allocate(size_t word_size, bool is_tlab) { - assert(UseTLAB || !is_tlab, "Should not allocate tlab"); - assert(word_size != 0, "precondition"); - - size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize); - - const bool overflows = word_size >= overflow_limit; - const bool check_too_big = _pretenure_size_threshold_words > 0; - const bool not_too_big = word_size < _pretenure_size_threshold_words; - const bool size_ok = is_tlab || !check_too_big || not_too_big; - - bool result = !overflows && - size_ok; - - return result; - } - // Allocate requested size or return null; single-threaded and lock-free versions. HeapWord* allocate(size_t word_size); HeapWord* par_allocate(size_t word_size); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 72f8ad85a4e..6bb1183aa56 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -283,16 +283,12 @@ size_t SerialHeap::max_capacity() const { } HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { - HeapWord* result = nullptr; - if (_old_gen->should_allocate(size, is_tlab)) { + HeapWord* result = _young_gen->allocate(size); + + if (result == nullptr) { result = _old_gen->expand_and_allocate(size); } - if (result == nullptr) { - if (_young_gen->should_allocate(size, is_tlab)) { - // Young-gen is not expanded. - result = _young_gen->allocate(size); - } - } + assert(result == nullptr || is_in_reserved(result), "result not in heap"); return result; } @@ -301,11 +297,9 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { HeapWord* result = nullptr; for (uint try_count = 1; /* break */; try_count++) { - if (_young_gen->should_allocate(size, is_tlab)) { - result = _young_gen->par_allocate(size); - if (result != nullptr) { - break; - } + result = _young_gen->par_allocate(size); + if (result != nullptr) { + break; } // Try old-gen allocation for non-TLAB. if (!is_tlab) { @@ -342,25 +336,6 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { return result; } -HeapWord* SerialHeap::attempt_allocation(size_t size, - bool is_tlab, - bool first_only) { - HeapWord* res = nullptr; - - if (_young_gen->should_allocate(size, is_tlab)) { - res = _young_gen->allocate(size); - if (res != nullptr || first_only) { - return res; - } - } - - if (_old_gen->should_allocate(size, is_tlab)) { - res = _old_gen->allocate(size); - } - - return res; -} - HeapWord* SerialHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) { return mem_allocate_work(size, @@ -459,15 +434,10 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { HeapWord* result = nullptr; // If young-gen can handle this allocation, attempt young-gc firstly. - bool should_run_young_gc = _young_gen->should_allocate(size, is_tlab); + bool should_run_young_gc = is_tlab || size <= _young_gen->eden()->capacity(); collect_at_safepoint(!should_run_young_gc); - result = attempt_allocation(size, is_tlab, false /*first_only*/); - if (result != nullptr) { - return result; - } - - // OK, collection failed, try expansion. + // Just finished a GC, try to satisfy this allocation, using expansion if needed. result = expand_heap_and_allocate(size, is_tlab); if (result != nullptr) { return result; @@ -484,10 +454,6 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { do_full_collection(clear_all_soft_refs); } - result = attempt_allocation(size, is_tlab, false /* first_only */); - if (result != nullptr) { - return result; - } // The previous full-gc can shrink the heap, so re-expand it. result = expand_heap_and_allocate(size, is_tlab); if (result != nullptr) { diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index b89edb33307..f0194f1a4a2 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -102,11 +102,6 @@ private: // old-gen. bool _is_heap_almost_full; - // Helper functions for allocation - HeapWord* attempt_allocation(size_t size, - bool is_tlab, - bool first_only); - void do_full_collection(bool clear_all_soft_refs) override; // Does the "cause" of GC indicate that diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 1225005aff4..038038f6808 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -135,15 +135,6 @@ public: void gc_prologue(); void gc_epilogue(); - bool should_allocate(size_t word_size, bool is_tlab) { - bool result = false; - size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize); - if (!is_tlab) { - result = (word_size > 0) && (word_size < overflow_limit); - } - return result; - } - // Performance Counter support void update_counters(); diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 7f46f449085..240068f10c0 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -484,11 +484,6 @@ "OS specific low limit for heap base address") \ constraint(HeapBaseMinAddressConstraintFunc,AfterErgo) \ \ - product(size_t, PretenureSizeThreshold, 0, \ - "Maximum size in bytes of objects allocated in DefNew " \ - "generation; zero means no maximum") \ - range(0, max_uintx) \ - \ product(uintx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ range(1, max_uintx-2) \ diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 063090b93c9..0d4adc7f587 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -567,6 +567,8 @@ static SpecialFlag const special_jvm_flags[] = { { "UseAdaptiveSizePolicyWithSystemGC", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, { "UsePSAdaptiveSurvivorSizePolicy", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, + { "PretenureSizeThreshold", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, + #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif From 431f46724658b703e995e518cb7a2149c50d6a9d Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Sep 2025 19:21:38 +0000 Subject: [PATCH 115/295] 8361635: Missing List length validation in the Class-File API Reviewed-by: asotona --- .../java/lang/classfile/Annotation.java | 8 + .../lang/classfile/AnnotationElement.java | 2 + .../java/lang/classfile/AnnotationValue.java | 7 +- .../java/lang/classfile/ClassBuilder.java | 12 +- .../java/lang/classfile/CodeBuilder.java | 4 +- .../java/lang/classfile/Interfaces.java | 12 +- .../java/lang/classfile/TypeAnnotation.java | 9 +- .../CharacterRangeTableAttribute.java | 2 + .../attribute/ExceptionsAttribute.java | 8 + .../attribute/InnerClassesAttribute.java | 4 + .../attribute/LineNumberTableAttribute.java | 2 + .../LocalVariableTableAttribute.java | 2 + .../LocalVariableTypeTableAttribute.java | 2 + .../attribute/MethodParametersAttribute.java | 4 + .../classfile/attribute/ModuleAttribute.java | 23 +- .../classfile/attribute/ModuleExportInfo.java | 28 +- .../attribute/ModuleHashesAttribute.java | 8 + .../classfile/attribute/ModuleOpenInfo.java | 24 +- .../attribute/ModulePackagesAttribute.java | 8 + .../attribute/ModuleProvideInfo.java | 10 +- .../attribute/NestMembersAttribute.java | 12 +- .../PermittedSubclassesAttribute.java | 12 +- .../classfile/attribute/RecordAttribute.java | 4 + .../attribute/RecordComponentInfo.java | 8 + .../RuntimeInvisibleAnnotationsAttribute.java | 4 + ...nvisibleParameterAnnotationsAttribute.java | 4 + ...timeInvisibleTypeAnnotationsAttribute.java | 4 + .../RuntimeVisibleAnnotationsAttribute.java | 4 + ...eVisibleParameterAnnotationsAttribute.java | 4 + ...untimeVisibleTypeAnnotationsAttribute.java | 4 + .../attribute/StackMapFrameInfo.java | 2 + .../attribute/StackMapTableAttribute.java | 2 + .../constantpool/ConstantPoolBuilder.java | 4 + .../classfile/constantpool/Utf8Entry.java | 3 +- .../java/lang/classfile/package-info.java | 2 +- .../classfile/impl/AnnotationImpl.java | 6 +- .../classfile/impl/AttributeHolder.java | 3 +- .../impl/BootstrapMethodEntryImpl.java | 8 +- .../classfile/impl/BufWriterImpl.java | 4 +- .../classfile/impl/DirectCodeBuilder.java | 11 +- .../classfile/impl/InterfacesImpl.java | 4 +- .../classfile/impl/SplitConstantPool.java | 10 +- .../classfile/impl/StackMapDecoder.java | 6 +- .../classfile/impl/TargetInfoImpl.java | 2 +- .../classfile/impl/UnboundAttribute.java | 74 ++-- .../jdk/internal/classfile/impl/Util.java | 29 ++ test/jdk/jdk/classfile/LimitsTest.java | 220 ++++++++++- .../jdk/jdk/classfile/ListValidationTest.java | 348 ++++++++++++++++++ 48 files changed, 866 insertions(+), 111 deletions(-) create mode 100644 test/jdk/jdk/classfile/ListValidationTest.java diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java index 5c4ee630b08..5a9aeaccfc4 100644 --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java @@ -95,6 +95,8 @@ public sealed interface Annotation * @param annotationClass the constant pool entry holding the descriptor string * of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(Utf8Entry annotationClass, List elements) { @@ -106,6 +108,8 @@ public sealed interface Annotation * @param annotationClass the constant pool entry holding the descriptor string * of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(Utf8Entry annotationClass, AnnotationElement... elements) { @@ -116,6 +120,8 @@ public sealed interface Annotation * {@return an annotation} * @param annotationClass the descriptor of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(ClassDesc annotationClass, List elements) { @@ -126,6 +132,8 @@ public sealed interface Annotation * {@return an annotation} * @param annotationClass the descriptor of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(ClassDesc annotationClass, AnnotationElement... elements) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java index 23f830f1512..aed9a358535 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java @@ -209,6 +209,8 @@ public sealed interface AnnotationElement * @param name the name of the key * @param values the associated values * @see AnnotationValue#ofArray(AnnotationValue...) AnnotationValue::ofArray + * @throws IllegalArgumentException if the number of associated values + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static AnnotationElement ofArray(String name, AnnotationValue... values) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index ae31fdf3967..623cb5a771f 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -673,6 +673,8 @@ public sealed interface AnnotationValue { * on array values derived from Java source code. * * @param values the array elements + * @throws IllegalArgumentException if the length of array exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static OfArray ofArray(List values) { return new AnnotationImpl.OfArrayImpl(values); @@ -686,6 +688,8 @@ public sealed interface AnnotationValue { * on array values derived from Java source code. * * @param values the array elements + * @throws IllegalArgumentException if the length of array exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static OfArray ofArray(AnnotationValue... values) { return ofArray(List.of(values)); @@ -699,7 +703,8 @@ public sealed interface AnnotationValue { * @param value the annotation value * @throws IllegalArgumentException when the {@code value} parameter is not * a primitive, a wrapper of primitive, a String, a ClassDesc, - * an enum constant, or an array of one of these. + * an enum constant, or an array of one of these; or any array has + * length over the limit of {@link java.lang.classfile##u2 u2} */ static AnnotationValue of(Object value) { if (value instanceof String s) { diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 86cdb298d9e..7fd10b9dab1 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -131,6 +131,8 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder + * @throws IllegalArgumentException if the number of interfaces exceeds the + * limit of {@link java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaces(List interfaces) { @@ -142,6 +144,8 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder + * @throws IllegalArgumentException if the number of interfaces exceeds the + * limit of {@link java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaces(ClassEntry... interfaces) { @@ -153,7 +157,9 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder - * @throws IllegalArgumentException if any element of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaceSymbols(List interfaces) { @@ -165,7 +171,9 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder - * @throws IllegalArgumentException if any element of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaceSymbols(ClassDesc... interfaces) { 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 656e84adf58..b4d3e427e91 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -2402,8 +2402,8 @@ public sealed interface CodeBuilder * variable by a constant. *

          * This may also generate {@link Opcode#IINC_W wide iinc} instructions if - * {@code slot} exceeds {@code 255} or {@code val} exceeds the range of - * {@link TypeKind#BYTE byte}. + * {@code slot} exceeds the limit of {@link java.lang.classfile##u1 u1} or + * {@code val} exceeds the range of {@link TypeKind#BYTE byte}. * * @param slot the local variable slot * @param val the increment value diff --git a/src/java.base/share/classes/java/lang/classfile/Interfaces.java b/src/java.base/share/classes/java/lang/classfile/Interfaces.java index bd89c494f24..d4fac8e310a 100644 --- a/src/java.base/share/classes/java/lang/classfile/Interfaces.java +++ b/src/java.base/share/classes/java/lang/classfile/Interfaces.java @@ -54,6 +54,8 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces + * @throws IllegalArgumentException if the number of interfaces + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static Interfaces of(List interfaces) { return new InterfacesImpl(interfaces); @@ -62,6 +64,8 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces + * @throws IllegalArgumentException if the number of interfaces + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static Interfaces of(ClassEntry... interfaces) { return of(List.of(interfaces)); @@ -70,7 +74,9 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces - * @throws IllegalArgumentException if any of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static Interfaces ofSymbols(List interfaces) { return of(Util.entryList(interfaces)); @@ -79,7 +85,9 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces - * @throws IllegalArgumentException if any of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static Interfaces ofSymbols(ClassDesc... interfaces) { return ofSymbols(Arrays.asList(interfaces)); diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 09dc3b59098..23c735257ae 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -182,6 +182,8 @@ public sealed interface TypeAnnotation * @param targetInfo which type in a declaration or expression is annotated * @param targetPath which part of the type is annotated * @param annotation the annotation + * @throws IllegalArgumentException if the size of {@code targetPath} + * exceeds the limit of {@link java.lang.classfile##u1 u1} */ static TypeAnnotation of(TargetInfo targetInfo, List targetPath, Annotation annotation) { @@ -486,6 +488,8 @@ public sealed interface TypeAnnotation * including a variable declared as a resource in a try-with-resources statement} * @param targetType {@link TargetType#LOCAL_VARIABLE} or {@link TargetType#RESOURCE_VARIABLE} * @param table the list of local variable targets + * @throws IllegalArgumentException if the size of the list of targets + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static LocalVarTarget ofVariable(TargetType targetType, List table) { return new TargetInfoImpl.LocalVarTargetImpl(targetType, table); @@ -494,6 +498,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on the type in a local variable declaration} * @param table the list of local variable targets + * @throws IllegalArgumentException if the size of the list of targets + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static LocalVarTarget ofLocalVariable(List table) { return ofVariable(TargetType.LOCAL_VARIABLE, table); @@ -503,6 +509,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on the type in a local variable declared * as a resource in a try-with-resources statement} * @param table the list of local variable targets + * @throws IllegalArgumentException if the size of the list of targets + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static LocalVarTarget ofResourceVariable(List table) { return ofVariable(TargetType.RESOURCE_VARIABLE, table); @@ -802,7 +810,6 @@ public sealed interface TypeAnnotation */ Label startLabel(); - /** * The given local variable has a value at indices into the code array in the interval * [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java index 49168ed99f8..45af5c20c0c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java @@ -88,6 +88,8 @@ public sealed interface CharacterRangeTableAttribute * {@link CodeBuilder#characterRange CodeBuilder::characterRange} instead. * * @param ranges the descriptions of the character ranges + * @throws IllegalArgumentException if the number of ranges exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static CharacterRangeTableAttribute of(List ranges) { return new UnboundAttribute.UnboundCharacterRangeTableAttribute(ranges); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java index acfd8bcca94..260cbe223e2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java @@ -77,6 +77,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute of(List exceptions) { return new UnboundAttribute.UnboundExceptionsAttribute(exceptions); @@ -85,6 +87,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute of(ClassEntry... exceptions) { return of(List.of(exceptions)); @@ -93,6 +97,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute ofSymbols(List exceptions) { return of(Util.entryList(exceptions)); @@ -101,6 +107,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute ofSymbols(ClassDesc... exceptions) { return ofSymbols(Arrays.asList(exceptions)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java index b50b38d0a00..a9e8e67805d 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java @@ -65,6 +65,8 @@ public sealed interface InnerClassesAttribute /** * {@return an {@code InnerClasses} attribute} * @param innerClasses descriptions of the nested classes + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static InnerClassesAttribute of(List innerClasses) { return new UnboundAttribute.UnboundInnerClassesAttribute(innerClasses); @@ -73,6 +75,8 @@ public sealed interface InnerClassesAttribute /** * {@return an {@code InnerClasses} attribute} * @param innerClasses descriptions of the nested classes + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static InnerClassesAttribute of(InnerClassInfo... innerClasses) { return new UnboundAttribute.UnboundInnerClassesAttribute(List.of(innerClasses)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java index bb08beacaa2..0bcac754677 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java @@ -79,6 +79,8 @@ public sealed interface LineNumberTableAttribute * order instead. * * @param lines the line number descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static LineNumberTableAttribute of(List lines) { return new UnboundAttribute.UnboundLineNumberTableAttribute(lines); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java index 6c1795e17bf..ad01a5c13ac 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java @@ -83,6 +83,8 @@ public sealed interface LocalVariableTableAttribute * {@link CodeBuilder#localVariable CodeBuilder::localVariable} instead. * * @param locals the local variable descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static LocalVariableTableAttribute of(List locals) { return new UnboundAttribute.UnboundLocalVariableTableAttribute(locals); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java index b4bc80cdca1..180d30c321e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java @@ -79,6 +79,8 @@ public sealed interface LocalVariableTypeTableAttribute /** * {@return a {@code LocalVariableTypeTable} attribute} * @param locals the local variable descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static LocalVariableTypeTableAttribute of(List locals) { return new UnboundAttribute.UnboundLocalVariableTypeTableAttribute(locals); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java index 8cf6d7b6319..c86a0700204 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java @@ -68,6 +68,8 @@ public sealed interface MethodParametersAttribute /** * {@return a {@code MethodParameters} attribute} * @param parameters the method parameter descriptions + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1} */ static MethodParametersAttribute of(List parameters) { return new UnboundAttribute.UnboundMethodParametersAttribute(parameters); @@ -76,6 +78,8 @@ public sealed interface MethodParametersAttribute /** * {@return a {@code MethodParameters} attribute} * @param parameters the method parameter descriptions + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1} */ static MethodParametersAttribute of(MethodParameterInfo... parameters) { return of(List.of(parameters)); 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 678c0f29714..874a3eae4f2 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 @@ -171,7 +171,8 @@ public sealed interface ModuleAttribute * @param uses the consumed services * @param provides the provided services * @throws IllegalArgumentException if {@code moduleFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or any of the collections has a size + * over the limit of {@link java.lang.classfile##u2 u2} */ static ModuleAttribute of(ModuleEntry moduleName, int moduleFlags, Utf8Entry moduleVersion, @@ -188,6 +189,9 @@ public sealed interface ModuleAttribute * * @param moduleName the module name * @param attrHandler a handler that receives a {@link ModuleAttributeBuilder} + * @throws IllegalArgumentException if the information from the handler exceeds + * the {@code class} file format limit, such as a list with size + * over the limit of {@link java.lang.classfile##u2 u2} */ static ModuleAttribute of(ModuleDesc moduleName, Consumer attrHandler) { @@ -296,6 +300,8 @@ public sealed interface ModuleAttribute * @param exportsFlagsMask the export flags * @param exportsToModules the modules to export to, or empty for an unqualified export * @return this builder + * @throws IllegalArgumentException if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ ModuleAttributeBuilder exports(PackageDesc pkge, int exportsFlagsMask, ModuleDesc... exportsToModules); @@ -307,7 +313,9 @@ public sealed interface ModuleAttribute * @param exportsToModules the modules to export to, or empty for an unqualified export * @return this builder * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location or the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ default ModuleAttributeBuilder exports(PackageDesc pkge, Collection exportsFlags, ModuleDesc... exportsToModules) { return exports(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules); @@ -333,6 +341,8 @@ public sealed interface ModuleAttribute * @param opensFlagsMask the open package flags * @param opensToModules the modules to open to, or empty for an unqualified open * @return this builder + * @throws IllegalArgumentException if the number of modules exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ ModuleAttributeBuilder opens(PackageDesc pkge, int opensFlagsMask, ModuleDesc... opensToModules); @@ -349,7 +359,9 @@ public sealed interface ModuleAttribute * @param opensToModules the modules to open to, or empty for an unqualified open * @return this builder * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ default ModuleAttributeBuilder opens(PackageDesc pkge, Collection opensFlags, ModuleDesc... opensToModules) { return opens(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules); @@ -391,7 +403,10 @@ public sealed interface ModuleAttribute * @param service the service class provided * @param implClasses the implementation classes * @return this builder - * @throws IllegalArgumentException if {@code service} or any of the {@code implClasses} represents a primitive type + * @throws IllegalArgumentException if {@code service} or any of the + * {@code implClasses} represents a primitive type, or the + * number of implementations exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ ModuleAttributeBuilder provides(ClassDesc service, ClassDesc... implClasses); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java index af04c83d260..09751817316 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java @@ -104,7 +104,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, List exportsTo) { @@ -119,7 +120,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, Collection exportFlags, List exportsTo) { @@ -134,7 +137,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, @@ -150,7 +154,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, Collection exportFlags, @@ -166,7 +172,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, List exportsTo) { @@ -183,7 +190,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, Collection exportFlags, List exportsTo) { @@ -198,7 +207,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, @@ -214,7 +224,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, Collection exportFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java index 11c016aa9e1..30951753529 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java @@ -96,6 +96,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(String algorithm, List hashes) { @@ -106,6 +108,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(String algorithm, ModuleHashInfo... hashes) { @@ -116,6 +120,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(Utf8Entry algorithm, List hashes) { @@ -126,6 +132,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(Utf8Entry algorithm, ModuleHashInfo... hashes) { diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java index 40a9b929776..3bccabcc907 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java @@ -110,7 +110,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, List opensTo) { @@ -125,7 +126,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, Collection opensFlags, List opensTo) { @@ -140,7 +142,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, @@ -156,7 +159,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, Collection opensFlags, @@ -171,7 +175,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, if it is a * qualified open, or empty * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, List opensTo) { @@ -187,7 +192,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, if it is a * qualified open, or empty * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, Collection opensFlags, List opensTo) { @@ -201,7 +207,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the packages to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, @@ -216,7 +223,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the packages to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, Collection opensFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java index 24a9218c9fd..147e3ec9d1f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java @@ -74,6 +74,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute of(List packages) { return new UnboundAttribute.UnboundModulePackagesAttribute(packages); @@ -82,6 +84,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute of(PackageEntry... packages) { return of(List.of(packages)); @@ -90,6 +94,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute ofNames(List packages) { var p = new PackageEntry[packages.size()]; @@ -102,6 +108,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute ofNames(PackageDesc... packages) { // List view, since ref to packages is temporary diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java index 76dc88c50f7..c3707597b53 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java @@ -64,6 +64,8 @@ public sealed interface ModuleProvideInfo * {@return a service provision description} * @param provides the service class interface * @param providesWith the service class implementations, must not be empty + * @throws IllegalArgumentException if the number of implementations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassEntry provides, List providesWith) { @@ -74,6 +76,8 @@ public sealed interface ModuleProvideInfo * {@return a service provision description} * @param provides the service class interface * @param providesWith the service class implementations, must not be empty + * @throws IllegalArgumentException if the number of implementations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassEntry provides, ClassEntry... providesWith) { @@ -85,7 +89,8 @@ public sealed interface ModuleProvideInfo * @param provides the service class interface * @param providesWith the service class implementations, must not be empty * @throws IllegalArgumentException if {@code provides} or any of {@code - * providesWith} represents a primitive type + * providesWith} represents a primitive type, or the number of + * implementations exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassDesc provides, List providesWith) { @@ -97,7 +102,8 @@ public sealed interface ModuleProvideInfo * @param provides the service class interface * @param providesWith the service class implementations, must not be empty * @throws IllegalArgumentException if {@code provides} or any of {@code - * providesWith} represents a primitive type + * providesWith} represents a primitive type, or the number of + * implementations exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassDesc provides, ClassDesc... providesWith) { diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java index baab955221c..244b7e67bcd 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java @@ -72,6 +72,8 @@ public sealed interface NestMembersAttribute extends Attribute nestMembers) { return new UnboundAttribute.UnboundNestMembersAttribute(nestMembers); @@ -81,6 +83,8 @@ public sealed interface NestMembersAttribute extends Attribute nestMembers) { return of(Util.entryList(nestMembers)); @@ -100,7 +106,9 @@ public sealed interface NestMembersAttribute extends Attribute permittedSubclasses) { return new UnboundAttribute.UnboundPermittedSubclassesAttribute(permittedSubclasses); @@ -86,6 +88,8 @@ public sealed interface PermittedSubclassesAttribute * {@return a {@code PermittedSubclasses} attribute} * * @param permittedSubclasses the permitted subclasses or subinterfaces + * @throws IllegalArgumentException if the number of permitted subclasses + * or subinterfaces exceeds the limit of {@link java.lang.classfile##u2 u2} */ static PermittedSubclassesAttribute of(ClassEntry... permittedSubclasses) { return of(List.of(permittedSubclasses)); @@ -95,7 +99,9 @@ public sealed interface PermittedSubclassesAttribute * {@return a {@code PermittedSubclasses} attribute} * * @param permittedSubclasses the permitted subclasses or subinterfaces - * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive + * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive, + * or if the number of permitted subclasses or subinterfaces exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static PermittedSubclassesAttribute ofSymbols(List permittedSubclasses) { return of(Util.entryList(permittedSubclasses)); @@ -105,7 +111,9 @@ public sealed interface PermittedSubclassesAttribute * {@return a {@code PermittedSubclasses} attribute} * * @param permittedSubclasses the permitted subclasses or subinterfaces - * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive + * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive, + * or if the number of permitted subclasses or subinterfaces exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static PermittedSubclassesAttribute ofSymbols(ClassDesc... permittedSubclasses) { // List version does defensive copy diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java index 8f55b3a1cf9..f01765991d2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java @@ -68,6 +68,8 @@ public sealed interface RecordAttribute extends Attribute, Clas * {@return a {@code Record} attribute} * * @param components the record components + * @throws IllegalArgumentException if the number of record components + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static RecordAttribute of(List components) { return new UnboundAttribute.UnboundRecordAttribute(components); @@ -77,6 +79,8 @@ public sealed interface RecordAttribute extends Attribute, Clas * {@return a {@code Record} attribute} * * @param components the record components + * @throws IllegalArgumentException if the number of record components + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static RecordAttribute of(RecordComponentInfo... components) { return of(List.of(components)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java index f3c74f066cf..23fb229ffd0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java @@ -90,6 +90,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component field descriptor string * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(Utf8Entry name, Utf8Entry descriptor, @@ -103,6 +105,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component field descriptor sting * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(Utf8Entry name, Utf8Entry descriptor, @@ -116,6 +120,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component symbolic field descriptor * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(String name, ClassDesc descriptor, @@ -131,6 +137,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component symbolic field descriptor * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(String name, ClassDesc descriptor, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java index da453ad4f5e..8a1e14280d3 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java @@ -73,6 +73,8 @@ public sealed interface RuntimeInvisibleAnnotationsAttribute * {@return a {@code RuntimeInvisibleAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeInvisibleAnnotationsAttribute(annotations); @@ -82,6 +84,8 @@ public sealed interface RuntimeInvisibleAnnotationsAttribute * {@return a {@code RuntimeInvisibleAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleAnnotationsAttribute of(Annotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java index 2051cd5dcdf..a721b9c1f9f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java @@ -86,6 +86,10 @@ public sealed interface RuntimeInvisibleParameterAnnotationsAttribute * some synthetic or implicit parameters. * * @param parameterAnnotations a list of run-time invisible annotations for each parameter + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1}, or the number of + * annotations on any parameter exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static RuntimeInvisibleParameterAnnotationsAttribute of(List> parameterAnnotations) { return new UnboundAttribute.UnboundRuntimeInvisibleParameterAnnotationsAttribute(parameterAnnotations); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java index 3ff1a643a82..15c90527c6a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java @@ -79,6 +79,8 @@ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute * {@return a {@code RuntimeInvisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleTypeAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeInvisibleTypeAnnotationsAttribute(annotations); @@ -88,6 +90,8 @@ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute * {@return a {@code RuntimeInvisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleTypeAnnotationsAttribute of(TypeAnnotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java index ceabe2131af..db9cb96f4e0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java @@ -72,6 +72,8 @@ public sealed interface RuntimeVisibleAnnotationsAttribute /** * {@return a {@code RuntimeVisibleAnnotations} attribute} * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeVisibleAnnotationsAttribute(annotations); @@ -80,6 +82,8 @@ public sealed interface RuntimeVisibleAnnotationsAttribute /** * {@return a {@code RuntimeVisibleAnnotations} attribute} * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleAnnotationsAttribute of(Annotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java index 2cf462d246c..4585efe5c65 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java @@ -88,6 +88,10 @@ public sealed interface RuntimeVisibleParameterAnnotationsAttribute * some synthetic or implicit parameters. * * @param parameterAnnotations a list of run-time visible annotations for each parameter + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1}, or the number of + * annotations on any parameter exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static RuntimeVisibleParameterAnnotationsAttribute of(List> parameterAnnotations) { return new UnboundAttribute.UnboundRuntimeVisibleParameterAnnotationsAttribute(parameterAnnotations); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java index ad4595ffb6b..0476dc60b82 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java @@ -79,6 +79,8 @@ public sealed interface RuntimeVisibleTypeAnnotationsAttribute * {@return a {@code RuntimeVisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleTypeAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeVisibleTypeAnnotationsAttribute(annotations); @@ -88,6 +90,8 @@ public sealed interface RuntimeVisibleTypeAnnotationsAttribute * {@return a {@code RuntimeVisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleTypeAnnotationsAttribute of(TypeAnnotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 71d5ccc79a4..06e9e6d585e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -83,6 +83,8 @@ public sealed interface StackMapFrameInfo * @param target the location of the frame * @param locals the complete list of frame locals * @param stack the complete frame stack + * @throws IllegalArgumentException if the number of types in {@code locals} + * or {@code stack} exceeds the limit of {@link java.lang.classfile##u2 u2} */ public static StackMapFrameInfo of(Label target, List locals, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java index e9b3acbff5b..f30e8cb01a7 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java @@ -75,6 +75,8 @@ public sealed interface StackMapTableAttribute * {@return a stack map table attribute} * * @param entries the stack map frames + * @throws IllegalArgumentException if the number of frames exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ public static StackMapTableAttribute of(List entries) { return new UnboundAttribute.UnboundStackMapTableAttribute(entries); 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 7d3f3c546a7..d10ff70120c 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 @@ -571,6 +571,8 @@ public sealed interface ConstantPoolBuilder * * @param methodReference the bootstrap method * @param arguments the arguments + * @throws IllegalArgumentException if the number of arguments exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ default BootstrapMethodEntry bsmEntry(DirectMethodHandleDesc methodReference, List arguments) { @@ -586,6 +588,8 @@ public sealed interface ConstantPoolBuilder * * @param methodReference the {@code MethodHandleEntry} * @param arguments the list of {@code LoadableConstantEntry} + * @throws IllegalArgumentException if the number of arguments exceeds the + * limit of {@link java.lang.classfile##u2 u2} * @see BootstrapMethodEntry#bootstrapMethod() * BootstrapMethodEntry::bootstrapMethod * @see BootstrapMethodEntry#arguments() BootstrapMethodEntry::arguments diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java index 81a4e973d3f..1c87ff87a4d 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java @@ -54,7 +54,8 @@ import jdk.internal.classfile.impl.AbstractPoolEntry; * Unlike most constant pool entries, a UTF-8 entry is of flexible length: it is * represented as an array structure, with an {@code u2} for the data length in * bytes, followed by that number of bytes of Modified UTF-8 data. It can - * represent at most 65535 bytes of data due to the physical restrictions. + * represent at most 65535 bytes of data due to the physical restrictions of + * {@link java.lang.classfile##u2 u2}. * * @jvms 4.4.7 The {@code CONSTANT_Utf8_info} Structure * @see DataInput##modified-utf-8 Modified UTF-8 diff --git a/src/java.base/share/classes/java/lang/classfile/package-info.java b/src/java.base/share/classes/java/lang/classfile/package-info.java index 5d905aace65..da9ad7fbf0d 100644 --- a/src/java.base/share/classes/java/lang/classfile/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/package-info.java @@ -255,7 +255,7 @@ * or method of any Class-File API class or interface will cause a {@link * NullPointerException} to be thrown. Additionally, * invoking a method with an array or collection containing a {@code null} element - * will cause a {@code NullPointerException}, unless otherwise specified.

          + * will cause a {@code NullPointerException}, unless otherwise specified. * *

          Symbolic information

          * To describe symbolic information for classes and types, the API uses the diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index b75cf100a1b..6543b4e5079 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ public record AnnotationImpl(Utf8Entry className, List elemen implements Annotation { public AnnotationImpl { requireNonNull(className); - elements = List.copyOf(elements); + elements = Util.sanitizeU2List(elements); } @Override @@ -189,7 +189,7 @@ public record AnnotationImpl(Utf8Entry className, List elemen public record OfArrayImpl(List values) implements AnnotationValue.OfArray { public OfArrayImpl { - values = List.copyOf(values); + values = Util.sanitizeU2List(values); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java index fffb963eab3..d5437bc3a2c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,6 +66,7 @@ public class AttributeHolder { public void writeTo(BufWriterImpl buf) { int attributesCount = this.attributesCount; + Util.checkU2(attributesCount, "attributes count"); buf.writeU2(attributesCount); for (int i = 0; i < attributesCount; i++) { Util.writeAttribute(buf, attributes[i]); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java index ed36b5ce172..9919d8a1697 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 +41,13 @@ public final class BootstrapMethodEntryImpl implements BootstrapMethodEntry { private final List arguments; BootstrapMethodEntryImpl(ConstantPool constantPool, int bsmIndex, int hash, - MethodHandleEntryImpl handle, - List arguments) { + MethodHandleEntryImpl handle, + List arguments) { this.index = bsmIndex; this.hash = hash; this.constantPool = constantPool; this.handle = handle; - this.arguments = List.copyOf(arguments); + this.arguments = Util.sanitizeU2List(arguments); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 40c5b1172b5..dda9accd8b9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -276,9 +276,7 @@ public final class BufWriterImpl implements BufWriter { int strlen = str.length(); int countNonZeroAscii = JLA.countNonZeroAscii(str); int utflen = utfLen(str, countNonZeroAscii); - if (utflen > 65535) { - throw new IllegalArgumentException("string too long"); - } + Util.checkU2(utflen, "utf8 length"); reserveSpace(utflen + 3); int offset = this.offset; 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 0ed4a3a9418..5bdbb571b68 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 @@ -185,14 +185,14 @@ public final class DirectCodeBuilder private void writeExceptionHandlers(BufWriterImpl buf) { int pos = buf.size(); int handlersSize = handlers.size(); + Util.checkU2(handlersSize, "exception handlers"); buf.writeU2(handlersSize); if (handlersSize > 0) { - writeExceptionHandlers(buf, pos); + writeExceptionHandlers(buf, pos, handlersSize); } } - private void writeExceptionHandlers(BufWriterImpl buf, int pos) { - int handlersSize = handlers.size(); + private void writeExceptionHandlers(BufWriterImpl buf, int pos, int handlersSize) { for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) { int startPc = labelToBci(h.tryStart()); int endPc = labelToBci(h.tryEnd()); @@ -227,6 +227,7 @@ public final class DirectCodeBuilder public void writeBody(BufWriterImpl b) { int pos = b.size(); int crSize = characterRangesCount; + Util.checkU2(crSize, "character range count"); b.writeU2(crSize); for (int i = 0; i < characterRangesCount; i++) { CharacterRange cr = characterRanges[i]; @@ -262,6 +263,7 @@ public final class DirectCodeBuilder public void writeBody(BufWriterImpl b) { int pos = b.size(); int lvSize = localVariablesCount; + Util.checkU2(lvSize, "local variable count"); b.writeU2(lvSize); for (int i = 0; i < localVariablesCount; i++) { LocalVariable l = localVariables[i]; @@ -291,6 +293,7 @@ public final class DirectCodeBuilder public void writeBody(BufWriterImpl b) { int pos = b.size(); int lvtSize = localVariableTypesCount; + Util.checkU2(lvtSize, "local variable type count"); b.writeU2(lvtSize); for (int i = 0; i < localVariableTypesCount; i++) { LocalVariableType l = localVariableTypes[i]; @@ -441,7 +444,7 @@ public final class DirectCodeBuilder b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE)); push(); b.writeInt(buf.size() + 2); - b.writeU2(buf.size() / 4); + b.writeU2(Util.checkU2(buf.size() / 4, "line number count")); b.writeBytes(buf); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java index d27b5e20ab4..79c84e4e66f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ public final class InterfacesImpl private final List interfaces; public InterfacesImpl(List interfaces) { - this.interfaces = List.copyOf(interfaces); + this.interfaces = Util.sanitizeU2List(interfaces); } @Override 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 d9ca3ff61bc..a82a9577225 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 @@ -129,6 +129,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder { if (bsmSize == 0) return false; int pos = buf.size(); + Util.checkU2(bsmSize, "num bootstrap methods"); if (parent != null && parentBsmSize != 0) { parent.writeBootstrapMethods(buf); for (int i = parentBsmSize; i < bsmSize; i++) @@ -160,15 +161,14 @@ public final class SplitConstantPool implements ConstantPoolBuilder { void writeTo(BufWriterImpl buf) { int writeFrom = 1; - if (size() >= 65536) { - throw new IllegalArgumentException(String.format("Constant pool is too large %d", size())); - } - buf.writeU2(size()); + int mySize = size(); + Util.checkU2(mySize, "constant pool count"); + buf.writeU2(mySize); if (parent != null && buf.constantPool().canWriteDirect(this)) { parent.writeConstantPoolEntries(buf); writeFrom = parent.size(); } - for (int i = writeFrom; i < size(); ) { + for (int i = writeFrom; i < mySize; ) { var info = (AbstractPoolEntry) entryByIndex(i); info.writeTo(buf); i += info.width(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index f8e58ed2242..c5ce2204c09 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -303,8 +303,8 @@ public class StackMapDecoder { implements StackMapFrameInfo { public StackMapFrameImpl { requireNonNull(target); - locals = List.copyOf(locals); - stack = List.copyOf(stack); + locals = Util.sanitizeU2List(locals); + stack = Util.sanitizeU2List(stack); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index a0afb5efae1..62f0e2eab16 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -108,7 +108,7 @@ public final class TargetInfoImpl { public LocalVarTargetImpl(TargetType targetType, List table) { this.targetType = checkValid(targetType, TARGET_LOCAL_VARIABLE, TARGET_RESOURCE_VARIABLE); - this.table = List.copyOf(table); + this.table = Util.sanitizeU2List(table); } @Override public int size() { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 347b0c12657..94ba782d808 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -174,7 +174,7 @@ public abstract sealed class UnboundAttribute> public UnboundExceptionsAttribute(List exceptions) { super(Attributes.exceptions()); - this.exceptions = List.copyOf(exceptions); + this.exceptions = Util.sanitizeU2List(exceptions); } @Override @@ -244,7 +244,7 @@ public abstract sealed class UnboundAttribute> public UnboundStackMapTableAttribute(List entries) { super(Attributes.stackMapTable()); - this.entries = List.copyOf(entries); + this.entries = Util.sanitizeU2List(entries); } @Override @@ -268,7 +268,7 @@ public abstract sealed class UnboundAttribute> public UnboundInnerClassesAttribute(List innerClasses) { super(Attributes.innerClasses()); - this.innerClasses = List.copyOf(innerClasses); + this.innerClasses = Util.sanitizeU2List(innerClasses); } @Override @@ -292,7 +292,7 @@ public abstract sealed class UnboundAttribute> public UnboundRecordAttribute(List components) { super(Attributes.record()); - this.components = List.copyOf(components); + this.components = Util.sanitizeU2List(components); } @Override @@ -347,7 +347,7 @@ public abstract sealed class UnboundAttribute> public UnboundMethodParametersAttribute(List parameters) { super(Attributes.methodParameters()); - this.parameters = List.copyOf(parameters); + this.parameters = Util.sanitizeU1List(parameters); } @Override @@ -421,7 +421,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleHashesAttribute(Utf8Entry algorithm, List hashes) { super(Attributes.moduleHashes()); this.algorithm = requireNonNull(algorithm); - this.hashes = List.copyOf(hashes); + this.hashes = Util.sanitizeU2List(hashes); } @Override @@ -446,16 +446,16 @@ public abstract sealed class UnboundAttribute> private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_PACKAGES); - private final Collection packages; + private final List packages; public UnboundModulePackagesAttribute(Collection packages) { super(Attributes.modulePackages()); - this.packages = List.copyOf(packages); + this.packages = Util.sanitizeU2List(packages); } @Override public List packages() { - return List.copyOf(packages); + return packages; } @Override @@ -498,7 +498,7 @@ public abstract sealed class UnboundAttribute> public UnboundPermittedSubclassesAttribute(List permittedSubclasses) { super(Attributes.permittedSubclasses()); - this.permittedSubclasses = List.copyOf(permittedSubclasses); + this.permittedSubclasses = Util.sanitizeU2List(permittedSubclasses); } @Override @@ -522,7 +522,7 @@ public abstract sealed class UnboundAttribute> public UnboundNestMembersAttribute(List memberEntries) { super(Attributes.nestMembers()); - this.memberEntries = List.copyOf(memberEntries); + this.memberEntries = Util.sanitizeU2List(memberEntries); } @Override @@ -642,7 +642,7 @@ public abstract sealed class UnboundAttribute> public UnboundCharacterRangeTableAttribute(List ranges) { super(Attributes.characterRangeTable()); - this.ranges = List.copyOf(ranges); + this.ranges = Util.sanitizeU2List(ranges); } @Override @@ -666,7 +666,7 @@ public abstract sealed class UnboundAttribute> public UnboundLineNumberTableAttribute(List lines) { super(Attributes.lineNumberTable()); - this.lines = List.copyOf(lines); + this.lines = Util.sanitizeU2List(lines); } @Override @@ -690,7 +690,7 @@ public abstract sealed class UnboundAttribute> public UnboundLocalVariableTableAttribute(List locals) { super(Attributes.localVariableTable()); - this.locals = List.copyOf(locals); + this.locals = Util.sanitizeU2List(locals); } @Override @@ -714,7 +714,7 @@ public abstract sealed class UnboundAttribute> public UnboundLocalVariableTypeTableAttribute(List locals) { super(Attributes.localVariableTypeTable()); - this.locals = List.copyOf(locals); + this.locals = Util.sanitizeU2List(locals); } @Override @@ -738,7 +738,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeVisibleAnnotationsAttribute(List elements) { super(Attributes.runtimeVisibleAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -762,7 +762,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeInvisibleAnnotationsAttribute(List elements) { super(Attributes.runtimeInvisibleAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -786,13 +786,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeVisibleParameterAnnotations()); - // deep copy - var array = elements.toArray().clone(); - for (int i = 0; i < array.length; i++) { - array[i] = List.copyOf((List) array[i]); - } - - this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); + this.elements = Util.sanitizeParameterAnnotations(elements); } @Override @@ -816,13 +810,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeInvisibleParameterAnnotations()); - // deep copy - var array = elements.toArray().clone(); - for (int i = 0; i < array.length; i++) { - array[i] = List.copyOf((List) array[i]); - } - - this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); + this.elements = Util.sanitizeParameterAnnotations(elements); } @Override @@ -846,7 +834,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeVisibleTypeAnnotationsAttribute(List elements) { super(Attributes.runtimeVisibleTypeAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -870,7 +858,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List elements) { super(Attributes.runtimeInvisibleTypeAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -955,7 +943,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleExportInfo { requireNonNull(exportedPackage); Util.checkFlags(exportsFlagsMask); - exportsTo = List.copyOf(exportsTo); + exportsTo = Util.sanitizeU2List(exportsTo); } } @@ -973,7 +961,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleOpenInfo { requireNonNull(openedPackage); Util.checkFlags(opensFlagsMask); - opensTo = List.copyOf(opensTo); + opensTo = Util.sanitizeU2List(opensTo); } } @@ -982,7 +970,7 @@ public abstract sealed class UnboundAttribute> implements ModuleProvideInfo { public UnboundModuleProvideInfo { requireNonNull(provides); - providesWith = List.copyOf(providesWith); + providesWith = Util.sanitizeU2List(providesWith); } } @@ -1003,7 +991,7 @@ public abstract sealed class UnboundAttribute> public UnboundRecordComponentInfo { requireNonNull(name); requireNonNull(descriptor); - attributes = List.copyOf(attributes); + attributes = Util.sanitizeU2List(attributes); } } @@ -1013,7 +1001,7 @@ public abstract sealed class UnboundAttribute> public UnboundTypeAnnotation { requireNonNull(targetInfo); - targetPath = List.copyOf(targetPath); + targetPath = Util.sanitizeU1List(targetPath); requireNonNull(annotation); } } @@ -1047,11 +1035,11 @@ public abstract sealed class UnboundAttribute> this.moduleName = requireNonNull(moduleName); this.moduleFlags = Util.checkFlags(moduleFlags); this.moduleVersion = moduleVersion; - this.requires = List.copyOf(requires); - this.exports = List.copyOf(exports); - this.opens = List.copyOf(opens); - this.uses = List.copyOf(uses); - this.provides = List.copyOf(provides); + this.requires = Util.sanitizeU2List(requires); + this.exports = Util.sanitizeU2List(exports); + this.opens = Util.sanitizeU2List(opens); + this.uses = Util.sanitizeU2List(uses); + this.provides = Util.sanitizeU2List(provides); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 0eea2bffd22..7e6384dd1a4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -146,6 +146,33 @@ public final class Util { : ClassDesc.ofInternalName(classInternalNameOrArrayDesc); } + /// Sanitizes an input list to make it immutable, and verify its size can + /// be represented with U1, throwing IAE otherwise. + public static List sanitizeU1List(List input) { + var copy = List.copyOf(input); + checkU1(copy.size(), "list size"); + return copy; + } + + /// Sanitizes an input list to make it immutable, and verify its size can + /// be represented with U2, throwing IAE otherwise. + public static List sanitizeU2List(Collection input) { + var copy = List.copyOf(input); + checkU2(copy.size(), "list size"); + return copy; + } + + /// Sanitizes an input nested list of parameter annotations. + public static List> sanitizeParameterAnnotations(List> input) { + var array = input.toArray().clone(); + checkU1(array.length, "parameter count"); + for (int i = 0; i < array.length; i++) { + array[i] = sanitizeU2List((List) array[i]); + } + + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); + } + public static List mappedList(List list, Function mapper) { return new AbstractList<>() { @Override @@ -259,6 +286,7 @@ public final class Util { @ForceInline public static void writeAttributes(BufWriterImpl buf, List> list) { int size = list.size(); + Util.checkU2(size, "attributes count"); buf.writeU2(size); for (int i = 0; i < size; i++) { writeAttribute(buf, list.get(i)); @@ -267,6 +295,7 @@ public final class Util { @ForceInline static void writeList(BufWriterImpl buf, Writable[] array, int size) { + Util.checkU2(size, "member count"); buf.writeU2(size); for (int i = 0; i < size; i++) { array[i].writeTo(buf); diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index 6f3dc04c665..0b347c835db 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,17 +23,22 @@ /* * @test - * @bug 8320360 8330684 8331320 8331655 8331940 8332486 8335820 8336833 + * @bug 8320360 8330684 8331320 8331655 8331940 8332486 8335820 8336833 8361635 * @summary Testing ClassFile limits. * @run junit LimitsTest */ + +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.AttributedElement; import java.lang.classfile.Attributes; -import java.lang.classfile.constantpool.PoolEntry; -import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; -import java.lang.constant.MethodTypeDesc; +import java.lang.classfile.BufWriter; import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassReader; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.Label; import java.lang.classfile.Opcode; +import java.lang.classfile.Signature; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.attribute.LineNumberTableAttribute; @@ -41,8 +46,16 @@ import java.lang.classfile.attribute.LocalVariableTableAttribute; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.ConstantPoolException; import java.lang.classfile.constantpool.IntegerEntry; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.classfile.impl.DirectCodeBuilder; @@ -51,6 +64,8 @@ import jdk.internal.classfile.impl.LabelContext; import jdk.internal.classfile.impl.UnboundAttribute; import org.junit.jupiter.api.Test; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.*; import static org.junit.jupiter.api.Assertions.*; class LimitsTest { @@ -73,6 +88,114 @@ class LimitsTest { })); } + @Test + void testBsmOverLimit() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + var cp = clb.constantPool(); + var mhe = cp.methodHandleEntry(BSM_GET_STATIC_FINAL); + var digits = new IntegerEntry[10]; + for (int i = 0; i < 10; i++) { + digits[i] = cp.intEntry(i); + } + int lastIndex = -1; + for (int i = 0; i < 66000; i++) { + lastIndex = cp.bsmEntry(mhe, List.of( + digits[i / 10000 % 10], + digits[i / 1000 % 10], + digits[i / 100 % 10], + digits[i / 10 % 10], + digits[i / 1 % 10])).bsmIndex(); + } + assertEquals(65999, lastIndex); + reached.set(true); + })); + assertTrue(reached.get()); + } + + @Test + void testTooManyFields() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + for (int i = 1; i < 66000; i++) { + clb.withField("f", CD_int, 0); + } + reached.set(true); + })); + assertTrue(reached.get()); + } + + @Test + void testTooManyMethods() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + for (int i = 1; i < 66000; i++) { + clb.withMethodBody("m", MTD_void, 0, CodeBuilder::return_); + } + reached.set(true); + })); + assertTrue(reached.get()); + } + + static final class MyAttribute extends CustomAttribute { + static final MyAttribute INSTANCE = new MyAttribute(); + + private enum Mapper implements AttributeMapper { + INSTANCE; + + @Override + public MyAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + throw new UnsupportedOperationException(); + } + + @Override + public void writeAttribute(BufWriter buf, MyAttribute attr) { + buf.writeIndex(buf.constantPool().utf8Entry("MyAttribute")); + buf.writeInt(0); + } + + @Override + public boolean allowMultiple() { + return true; + } + + @Override + public AttributeStability stability() { + return AttributeStability.STATELESS; + } + + + } + + private MyAttribute() { + super(Mapper.INSTANCE); + } + } + + @Test + void testTooManyClassAttributes() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + for (int i = 1; i < 66000; i++) { + clb.with(MyAttribute.INSTANCE); + } + reached.set(true); + })); + assertTrue(reached.get()); + } + + @Test + void testTooManyFieldAttributes() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withField("f", CD_int, fb -> { + for (int i = 1; i < 66000; i++) { + fb.with(MyAttribute.INSTANCE); + } + reached.set(true); + }))); + assertTrue(reached.get()); + } + @Test void testCodeOverLimit() { assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(ClassDesc.of("BigClass"), cb -> cb.withMethodBody( @@ -99,6 +222,91 @@ class LimitsTest { assertThrows(IllegalArgumentException.class, () -> lc.getLabel(10)); } + private static void testPseudoOverflow(BiConsumer handler) { + ClassFile cf = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS); + AtomicBoolean reached = new AtomicBoolean(false); + assertDoesNotThrow(() -> cf.build(CD_Void, cb -> cb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + cob.nop(); + var label = cob.newLabel(); + for (int i = 0; i < 65535; i++) { + handler.accept(cob, label); + } + cob.labelBinding(label); + cob.return_(); + reached.set(true); + }))); + assertTrue(reached.get()); + + reached.set(false); + assertThrows(IllegalArgumentException.class, () -> cf.build(CD_Void, cb -> cb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + cob.nop(); + var label = cob.newLabel(); + for (int i = 0; i < 65536; i++) { + handler.accept(cob, label); + } + cob.labelBinding(label); + cob.return_(); + reached.set(true); + }))); + assertTrue(reached.get()); + } + + @Test + void testExceptionCatchOverflow() { + testPseudoOverflow((cob, label) -> cob.exceptionCatch(cob.startLabel(), label, label, CD_Throwable)); + } + + @Test + void testLocalVariableOverflow() { + testPseudoOverflow((cob, label) -> cob.localVariable(0, "fake", CD_int, cob.startLabel(), label)); + } + + @Test + void testLocalVariableTypeOverflow() { + testPseudoOverflow((cob, label) -> cob.localVariableType(0, "fake", Signature.of(CD_int), cob.startLabel(), label)); + } + + @Test + void testCharacterRangeOverflow() { + testPseudoOverflow((cob, label) -> cob.characterRange(cob.startLabel(), label, 0, 0, 0)); + } + + // LineNumber deduplicates so cannot really overflow + + @Test + void testHugeLookupswitch() { + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + var l = cob.newLabel(); + // 10000 * 8 > 65535 + var cases = new ArrayList(10000); + for (int i = 0; i < 10000; i++) { + cases.add(SwitchCase.of(i, l)); + } + cob.lookupswitch(l, cases); + cob.labelBinding(l); + cob.return_(); + }))); + } + + @Test + void testHugeTableswitch() { + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + var l = cob.newLabel(); + // 20000 * 4 > 65535 + cob.tableswitch(-10000, 10000, l, List.of()); + cob.labelBinding(l); + cob.return_(); + }))); + } + + @Test + void testHugeUtf8Entry() { + var longString = String.valueOf((char) 0x800).repeat(22000); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + clb.constantPool().utf8Entry(longString); + })); + } + @Test void testSupportedClassVersion() { var cf = ClassFile.of(); diff --git a/test/jdk/jdk/classfile/ListValidationTest.java b/test/jdk/jdk/classfile/ListValidationTest.java new file mode 100644 index 00000000000..831bff3a7b4 --- /dev/null +++ b/test/jdk/jdk/classfile/ListValidationTest.java @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8361635 + * @summary Testing list size validation in class file format. + * @run junit ListValidationTest + */ + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Interfaces; +import java.lang.classfile.Label; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.*; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; +import java.util.List; +import java.util.Optional; + +import jdk.internal.classfile.impl.TemporaryConstantPool; +import jdk.internal.classfile.impl.UnboundAttribute; +import org.junit.jupiter.api.Test; + +import static java.lang.constant.ConstantDescs.*; +import static java.util.Collections.nCopies; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ListValidationTest { + @Test + void testAnnotationElements() { + var e = AnnotationElement.ofInt("dummy", 0); + assertDoesNotThrow(() -> Annotation.of(CD_String, nCopies(65535, e))); + assertThrows(IllegalArgumentException.class, () -> Annotation.of(CD_String, nCopies(66000, e))); + } + + @Test + void testAnnotationArrayValue() { + var v = AnnotationValue.ofInt(0); + assertDoesNotThrow(() -> AnnotationValue.ofArray(nCopies(65535, v))); + assertThrows(IllegalArgumentException.class, () -> AnnotationValue.ofArray(nCopies(66000, v))); + } + + @Test + void testTypeAnnotationPath() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), nCopies(255, TypeAnnotation.TypePathComponent.INNER_TYPE), anno)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), nCopies(256, TypeAnnotation.TypePathComponent.INNER_TYPE), anno)); + } + + @Test + void testBsmArgs() { + var cpb = ConstantPoolBuilder.of(); + assertDoesNotThrow(() -> cpb.bsmEntry(BSM_INVOKE, nCopies(65535, 0))); + assertThrows(IllegalArgumentException.class, () -> cpb.bsmEntry(BSM_INVOKE, nCopies(66000, 0))); + } + + @Test + void testInterfaces() { + var cpb = ConstantPoolBuilder.of(); + assertDoesNotThrow(() -> Interfaces.ofSymbols(nCopies(65535, CD_Number))); + assertThrows(IllegalArgumentException.class, () -> cpb.bsmEntry(BSM_INVOKE, nCopies(66000, 0))); + } + + @Test + void testStackMapFrame() { + Label label = dummyLabel(); + assertDoesNotThrow(() -> StackMapFrameInfo.of(label, + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE))); + assertThrows(IllegalArgumentException.class, () -> StackMapFrameInfo.of(label, + nCopies(66000, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE))); + assertThrows(IllegalArgumentException.class, () -> StackMapFrameInfo.of(label, + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(66000, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE))); + } + + @Test + void testTypeAnnotationLocalVarTarget() { + Label label = dummyLabel(); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofLocalVariable(nCopies(65535, TypeAnnotation.LocalVarTargetInfo.of(label, label, 0)))); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofLocalVariable(nCopies(66000, TypeAnnotation.LocalVarTargetInfo.of(label, label, 0)))); + } + + @Test + void testExceptionsAttribute() { + assertDoesNotThrow(() -> ExceptionsAttribute.ofSymbols(nCopies(65535, CD_Throwable))); + assertThrows(IllegalArgumentException.class, () -> ExceptionsAttribute.ofSymbols(nCopies(66000, CD_Throwable))); + } + + @Test + void testStackMapTableAttribute() { + var frame = StackMapFrameInfo.of(dummyLabel(), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE)); + assertDoesNotThrow(() -> StackMapTableAttribute.of(nCopies(65535, frame))); + assertThrows(IllegalArgumentException.class, () -> StackMapTableAttribute.of(nCopies(66000, frame))); + } + + @Test + void testInnerClassesAttribute() { + var entry = InnerClassInfo.of(CD_Void, Optional.empty(), Optional.empty(), 0); + assertDoesNotThrow(() -> InnerClassesAttribute.of(nCopies(65535, entry))); + assertThrows(IllegalArgumentException.class, () -> InnerClassesAttribute.of(nCopies(66000, entry))); + } + + @Test + void testRecordAttribute() { + var component = RecordComponentInfo.of("hello", CD_int, List.of()); + assertDoesNotThrow(() -> RecordAttribute.of(nCopies(65535, component))); + assertThrows(IllegalArgumentException.class, () -> RecordAttribute.of(nCopies(66000, component))); + } + + @Test + void testMethodParametersAttribute() { + var component = MethodParameterInfo.of(Optional.empty(), 0); + assertDoesNotThrow(() -> MethodParametersAttribute.of(nCopies(255, component))); + assertThrows(IllegalArgumentException.class, () -> MethodParametersAttribute.of(nCopies(300, component))); + } + + @Test + void testModuleHashesAttribute() { + var hash = ModuleHashInfo.of(ModuleDesc.of("java.base"), new byte[0]); + assertDoesNotThrow(() -> ModuleHashesAttribute.of("dummy", nCopies(65535, hash))); + assertThrows(IllegalArgumentException.class, () -> ModuleHashesAttribute.of("dummy", nCopies(66000, hash))); + } + + @Test + void testModulePackagesAttribute() { + var pkgDesc = PackageDesc.of("java.io"); + assertDoesNotThrow(() -> ModulePackagesAttribute.ofNames(nCopies(65535, pkgDesc))); + assertThrows(IllegalArgumentException.class, () -> ModulePackagesAttribute.ofNames(nCopies(66000, pkgDesc))); + } + + @Test + void testPermittedSubclassesAttribute() { + assertDoesNotThrow(() -> PermittedSubclassesAttribute.ofSymbols(nCopies(65535, CD_Collection))); + assertThrows(IllegalArgumentException.class, () -> PermittedSubclassesAttribute.ofSymbols(nCopies(66000, CD_Collection))); + } + + @Test + void testNestMembersAttribute() { + assertDoesNotThrow(() -> NestMembersAttribute.ofSymbols(nCopies(65535, CD_Collection))); + assertThrows(IllegalArgumentException.class, () -> NestMembersAttribute.ofSymbols(nCopies(66000, CD_Collection))); + } + + @Test + void testCharacterRangeTableAttribute() { + var range = CharacterRangeInfo.of(0, 0, 0, 0, 0); + assertDoesNotThrow(() -> CharacterRangeTableAttribute.of(nCopies(65535, range))); + assertThrows(IllegalArgumentException.class, () -> CharacterRangeTableAttribute.of(nCopies(66000, range))); + } + + @Test + void testLineNumberTableAttribute() { + var lineNumber = LineNumberInfo.of(0, 0); + assertDoesNotThrow(() -> LineNumberTableAttribute.of(nCopies(65535, lineNumber))); + assertThrows(IllegalArgumentException.class, () -> LineNumberTableAttribute.of(nCopies(66000, lineNumber))); + } + + @Test + void testLocalVariableTableAttribute() { + var utf8 = TemporaryConstantPool.INSTANCE.utf8Entry("dummy"); + var localVariable = new UnboundAttribute.UnboundLocalVariableInfo(0, 0, utf8, utf8, 0); + assertDoesNotThrow(() -> LocalVariableTableAttribute.of(nCopies(65535, localVariable))); + assertThrows(IllegalArgumentException.class, () -> LocalVariableTableAttribute.of(nCopies(66000, localVariable))); + } + + @Test + void testLocalVariableTypeTableAttribute() { + var utf8 = TemporaryConstantPool.INSTANCE.utf8Entry("dummy"); + var localVariableType = new UnboundAttribute.UnboundLocalVariableTypeInfo(0, 0, utf8, utf8, 0); + assertDoesNotThrow(() -> LocalVariableTypeTableAttribute.of(nCopies(65535, localVariableType))); + assertThrows(IllegalArgumentException.class, () -> LocalVariableTypeTableAttribute.of(nCopies(66000, localVariableType))); + } + + @Test + void testRuntimeVisibleAnnotationsAttribute() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeVisibleAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testRuntimeInvisibleAnnotationsAttribute() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeInvisibleAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testRuntimeVisibleParameterAnnotationsAttributeTopLevel() { + assertDoesNotThrow(() -> RuntimeVisibleParameterAnnotationsAttribute.of(nCopies(255, List.of()))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleParameterAnnotationsAttribute.of(nCopies(256, List.of()))); + } + + @Test + void testRuntimeInvisibleParameterAnnotationsAttributeTopLevel() { + assertDoesNotThrow(() -> RuntimeInvisibleParameterAnnotationsAttribute.of(nCopies(255, List.of()))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleParameterAnnotationsAttribute.of(nCopies(256, List.of()))); + } + + @Test + void testRuntimeVisibleParameterAnnotationsAttributeNested() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeVisibleParameterAnnotationsAttribute.of(List.of(nCopies(65535, anno)))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleParameterAnnotationsAttribute.of(List.of(nCopies(65536, anno)))); + } + + @Test + void testRuntimeInvisibleParameterAnnotationsAttributeNested() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(nCopies(65535, anno)))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(nCopies(65536, anno)))); + } + + @Test + void testRuntimeVisibleTypeAnnotationsAttribute() { + var anno = TypeAnnotation.of(TypeAnnotation.TargetInfo.ofMethodReturn(), List.of(), Annotation.of(CD_String)); + assertDoesNotThrow(() -> RuntimeVisibleTypeAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleTypeAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testRuntimeInvisibleTypeAnnotationsAttribute() { + var anno = TypeAnnotation.of(TypeAnnotation.TargetInfo.ofMethodReturn(), List.of(), Annotation.of(CD_String)); + assertDoesNotThrow(() -> RuntimeInvisibleTypeAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleTypeAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testModuleExportEntry() { + var pkg = PackageDesc.of("dummy.test"); + var mod = ModuleDesc.of("the.other"); + assertDoesNotThrow(() -> ModuleExportInfo.of(pkg, 0, nCopies(65535, mod))); + assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(pkg, 0, nCopies(66000, mod))); + } + + @Test + void testModuleOpenEntry() { + var pkg = PackageDesc.of("dummy.test"); + var mod = ModuleDesc.of("the.other"); + assertDoesNotThrow(() -> ModuleOpenInfo.of(pkg, 0, nCopies(65535, mod))); + assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(pkg, 0, nCopies(66000, mod))); + } + + @Test + void testModuleProvideEntry() { + assertDoesNotThrow(() -> ModuleProvideInfo.of(CD_Object, nCopies(65535, CD_String))); + assertThrows(IllegalArgumentException.class, () -> ModuleProvideInfo.of(CD_Object, nCopies(66000, CD_String))); + } + + @Test + void testRecordComponentAttributes() { + var attr = SyntheticAttribute.of(); + assertDoesNotThrow(() -> RecordComponentInfo.of("dummy", CD_int, nCopies(65535, attr))); + assertThrows(IllegalArgumentException.class, () -> RecordComponentInfo.of("dummy", CD_int, nCopies(66000, attr))); + } + + @Test + void testModuleAttribute() { + var md = ModuleDesc.of("java.base"); + var pkg = PackageDesc.of("java.lang"); + var require = ModuleRequireInfo.of(md, 0, null); + var export = ModuleExportInfo.of(pkg, 0, List.of()); + var provide = ModuleProvideInfo.of(CD_Object, List.of()); + var open = ModuleOpenInfo.of(pkg, 0, List.of()); + var classEntry = TemporaryConstantPool.INSTANCE.classEntry(CD_String); + var moduleEntry = TemporaryConstantPool.INSTANCE.moduleEntry(md); + assertDoesNotThrow(() -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(66000, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(66000, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(66000, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(66000, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(66000, provide) + )); + } + + private static Label dummyLabel() { + Label[] capture = new Label[1]; + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + capture[0] = cob.startLabel(); + cob.return_(); + })); + return capture[0]; + } +} From becc35f28792a48fac488841d0bc43226d7c96a7 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Sep 2025 21:58:26 +0000 Subject: [PATCH 116/295] 8366400: JCK test api/java_text/DecimalFormat/Parse.html fails after JDK-8363972 Reviewed-by: naoto --- .../classes/java/text/DecimalFormat.java | 7 +- .../Format/NumberFormat/PositionTest.java | 68 ++++++++++++++++--- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index aa881aecc8a..7ace5e136fe 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -3517,13 +3517,14 @@ public class DecimalFormat extends NumberFormat { var alen = affix.length(); var tlen = text.length(); + // Verify position can fit length wise before checking char by char + if (position + alen > tlen || position < 0) { + return false; + } if (alen == 0) { // always match with an empty affix, as affix is optional return true; } - if (position >= tlen) { - return false; - } if (parseStrict) { return text.regionMatches(position, affix, 0, alen); } diff --git a/test/jdk/java/text/Format/NumberFormat/PositionTest.java b/test/jdk/java/text/Format/NumberFormat/PositionTest.java index d916e0ab1ed..5b3a01f5ef1 100644 --- a/test/jdk/java/text/Format/NumberFormat/PositionTest.java +++ b/test/jdk/java/text/Format/NumberFormat/PositionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * 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,12 +21,6 @@ * questions. */ -/** - * @test - * @bug 4109023 4153060 4153061 - * @summary test ParsePosition and FieldPosition - * @run junit PositionTest - */ /* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved (C) Copyright IBM Corp. 1996 - All Rights Reserved @@ -39,15 +33,71 @@ attribution to Taligent may not be removed. Taligent is a registered trademark of Taligent, Inc. */ -import java.text.*; -import java.io.*; +/* + * @test + * @bug 4109023 4153060 4153061 8366400 + * @summary test ParsePosition and FieldPosition + * @run junit PositionTest + */ import org.junit.jupiter.api.Test; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; public class PositionTest { + // Parsing text which contains un-parseable data, but the index + // begins at the valid portion. Ensure PP is properly updated. + @Test + public void modifiedPositionTest() { + var df = new DecimalFormat("YY#"); + df.setStrict(false); // Lenient by default, set for test explicitness + var pp = new ParsePosition(9); + assertEquals(123L, assertDoesNotThrow(() -> df.parse("FOOBARBAZYY123", pp))); + assertEquals(-1, pp.getErrorIndex()); + assertEquals(14, pp.getIndex()); + } + + // Clearly invalid index value that could not work under any scenarios + // Specifically, ensuring no SIOOBE during affix matching + @Test + public void invalidPositionParseTest() { + var df = new DecimalFormat(); + df.setStrict(false); // Lenient by default, set for test explicitness + assertNull(assertDoesNotThrow(() -> df.parse("1", new ParsePosition(-1)))); + assertNull(assertDoesNotThrow(() -> df.parse("1", new ParsePosition(Integer.MAX_VALUE)))); + } + + // When prefix matching, position + affix length is greater than parsed String length + // Ensure we do not index out of bounds of the length of the parsed String + @Test + public void prefixMatchingTest() { + var df = new DecimalFormat("ZZZ#;YYY#"); + df.setStrict(false); // Lenient by default, set for test explicitness + // 0 + 3 > 2 = (pos + prefix > text) + assertNull(assertDoesNotThrow(() -> df.parse("Z1", new ParsePosition(0)))); + assertNull(assertDoesNotThrow(() -> df.parse("Y1", new ParsePosition(0)))); + } + + // When suffix matching, position + affix length is greater than parsed String length + // Ensure we do not index out of bounds of the length of the parsed String + @Test + public void suffixMatchingTest() { + var df = new DecimalFormat("#ZZ;#YY"); + df.setStrict(false); // Lenient by default, set for test explicitness + // Matches prefix properly first. Then 3 + 2 > 4 = (pos + suffix > text) + assertNull(assertDoesNotThrow(() -> df.parse("123Z", new ParsePosition(0)))); + assertNull(assertDoesNotThrow(() -> df.parse("123Y", new ParsePosition(0)))); + } + @Test public void TestParsePosition() { ParsePosition pp1 = new ParsePosition(0); From 02dd21196ed27289a6fad92c4881af484ce9c258 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 01:28:25 +0000 Subject: [PATCH 117/295] 8366692: Several gc/shenandoah tests timed out Reviewed-by: shade, wkemper --- test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java | 4 ++-- test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java | 4 ++-- .../jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java b/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java index 18f0e104ce0..fa6f3ab9b04 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java @@ -54,12 +54,12 @@ * @summary Acceptance tests: collector can withstand allocation * @requires vm.gc.Shenandoah * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=240 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify * TestAllocObjects * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=480 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify * TestAllocObjects diff --git a/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java b/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java index 37359b038b3..c3b09f5ab4c 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java @@ -63,7 +63,7 @@ * -XX:+ShenandoahOOMDuringEvacALot * TestSieveObjects * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=240 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahAllocFailureALot * TestSieveObjects @@ -103,7 +103,7 @@ * -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify * TestSieveObjects * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=480 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive -XX:ShenandoahGCMode=generational * -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify * TestSieveObjects diff --git a/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java b/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java index 6f211edf343..d2a6269dddd 100644 --- a/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java +++ b/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java @@ -27,7 +27,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahVerify * TestJNIGlobalRefs @@ -37,7 +37,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * TestJNIGlobalRefs */ @@ -46,7 +46,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * TestJNIGlobalRefs @@ -56,7 +56,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * TestJNIGlobalRefs */ From ed62bda2e0c51a67baae1fc28e41c9cd878db5f4 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 01:29:34 +0000 Subject: [PATCH 118/295] 8366694: Test JdbStopInNotificationThreadTest.java timed out after 60 second Reviewed-by: cjplummer, ayang, lmesnik --- test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java index 98a0d9d98ce..761c84d2c4c 100644 --- a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java +++ b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,9 +113,11 @@ public class JdbStopInNotificationThreadTest extends JdbTest { private static final String DEBUGGEE_CLASS = JdbStopInNotificationThreadTestTarg.class.getName(); private static final String PATTERN1_TEMPLATE = "^Breakpoint hit: \"thread=Notification Thread\", " + "JdbStopInNotificationThreadTestTarg\\$1\\.handleNotification\\(\\), line=%LINE_NUMBER.*\\R%LINE_NUMBER\\s+System\\.out\\.println\\(\"Memory usage low!!!\"\\);.*"; + private static final String[] DEBUGGEE_OPTIONS = {"-Xmx64M"}; private JdbStopInNotificationThreadTest() { - super(DEBUGGEE_CLASS); + super(new LaunchOptions(DEBUGGEE_CLASS) + .addDebuggeeOptions(DEBUGGEE_OPTIONS)); } public static void main(String argv[]) { From 11743b1ed3d681ce17c2342616c4040c4b539b31 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 01:37:42 +0000 Subject: [PATCH 119/295] 8366695: Test sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java timed out Reviewed-by: lmesnik, kevinw --- .../jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java index 2dc2b2b4587..88f1ed22e35 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -70,7 +70,7 @@ import sun.jvmstat.monitor.event.VmStatusChangeEvent; * @modules java.management * jdk.internal.jvmstat/sun.jvmstat.monitor * jdk.internal.jvmstat/sun.jvmstat.monitor.event - * @run main/othervm MonitorVmStartTerminate + * @run main/othervm/timeout=240 MonitorVmStartTerminate */ public final class MonitorVmStartTerminate { From f4d73d2a3dbeccfd04d49c0cfd690086edd0544f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 02:31:12 +0000 Subject: [PATCH 120/295] 8366584: Add an InstanceKlass::super() method that returns InstanceKlass* Reviewed-by: dholmes, coleenp --- src/hotspot/share/cds/aotArtifactFinder.cpp | 4 +-- src/hotspot/share/cds/aotClassLinker.cpp | 4 +-- .../share/cds/aotLinkedClassBulkLoader.cpp | 4 +-- src/hotspot/share/cds/classListParser.cpp | 4 +-- src/hotspot/share/cds/classListWriter.cpp | 4 +-- src/hotspot/share/cds/dynamicArchive.cpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 2 +- src/hotspot/share/cds/metaspaceShared.cpp | 4 +-- src/hotspot/share/ci/ciReplay.cpp | 4 +-- .../share/classfile/classFileParser.cpp | 14 ++++---- .../share/classfile/defaultMethods.cpp | 6 ++-- .../share/classfile/fieldLayoutBuilder.cpp | 4 +-- .../share/classfile/systemDictionary.cpp | 4 +-- .../classfile/systemDictionaryShared.cpp | 6 ++-- src/hotspot/share/classfile/vmClasses.cpp | 2 +- .../jfrEventClassTransformer.cpp | 2 +- .../jfr/leakprofiler/chains/edgeUtils.cpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 3 +- src/hotspot/share/oops/fieldStreams.hpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 32 +++++++++---------- src/hotspot/share/oops/instanceKlass.hpp | 8 ++++- src/hotspot/share/oops/klass.hpp | 4 ++- src/hotspot/share/oops/klassVtable.cpp | 19 ++++++----- src/hotspot/share/prims/jvmtiTagMap.cpp | 14 ++++---- src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 2 +- src/hotspot/share/services/heapDumper.cpp | 14 ++++---- 28 files changed, 90 insertions(+), 84 deletions(-) diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index a42d8882099..84bc2797c58 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -201,7 +201,7 @@ void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) { if (created) { _pending_aot_inited_classes->push(ik); - InstanceKlass* s = ik->java_super(); + InstanceKlass* s = ik->super(); if (s != nullptr) { add_aot_inited_class(s); } @@ -236,7 +236,7 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { append_to_all_cached_classes(ik); // All super types must be added. - InstanceKlass* s = ik->java_super(); + InstanceKlass* s = ik->super(); if (s != nullptr) { add_cached_instance_class(s); } diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp index 47c7f6e3bf8..adb18aa3aef 100644 --- a/src/hotspot/share/cds/aotClassLinker.cpp +++ b/src/hotspot/share/cds/aotClassLinker.cpp @@ -93,7 +93,7 @@ void AOTClassLinker::add_vm_class(InstanceKlass* ik) { bool v = try_add_candidate(ik); assert(v, "must succeed for VM class"); } - InstanceKlass* super = ik->java_super(); + InstanceKlass* super = ik->super(); if (super != nullptr) { add_vm_class(super); } @@ -151,7 +151,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) { } } - InstanceKlass* s = ik->java_super(); + InstanceKlass* s = ik->super(); if (s != nullptr && !try_add_candidate(s)) { return false; } diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 39236975782..99d7c26b293 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -294,7 +294,7 @@ void AOTLinkedClassBulkLoader::load_hidden_class(ClassLoaderData* loader_data, I HeapShared::is_lambda_proxy_klass(ik) || HeapShared::is_string_concat_klass(ik), "sanity"); DEBUG_ONLY({ - assert(ik->java_super()->is_loaded(), "must be"); + assert(ik->super()->is_loaded(), "must be"); for (int i = 0; i < ik->local_interfaces()->length(); i++) { assert(ik->local_interfaces()->at(i)->is_loaded(), "must be"); } @@ -434,4 +434,4 @@ void AOTLinkedClassBulkLoader::replay_training_at_init_for_preloaded_classes(TRA replay_training_at_init(table->platform(), CHECK); replay_training_at_init(table->app(), CHECK); } -} \ No newline at end of file +} diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 9ee7afcbc3e..75737b1432e 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -561,10 +561,10 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS const char* source_path = ClassLoader::uri_to_path(_source); InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL); - if (k->java_super() != specified_super) { + if (k->super() != specified_super) { error("The specified super class %s (id %d) does not match actual super class %s", specified_super->external_name(), _super, - k->java_super()->external_name()); + k->super()->external_name()); } if (k->local_interfaces()->length() != _interfaces->length()) { print_specified_interfaces(); diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 727cc03c216..4d48a07d736 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -139,7 +139,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre } { - InstanceKlass* super = k->java_super(); + InstanceKlass* super = k->super(); if (super != nullptr && !has_id(super)) { return; } @@ -165,7 +165,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre ResourceMark rm; stream->print("%s id: %d", k->name()->as_C_string(), get_id(k)); if (!is_builtin_loader) { - InstanceKlass* super = k->java_super(); + InstanceKlass* super = k->super(); assert(super != nullptr, "must be"); stream->print(" super: %d", get_id(super)); diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 397f9146afb..35a50297536 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -276,7 +276,7 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { remark_pointers_for_instance_klass(ik, false); // Make sure all supertypes have been sorted - sort_methods(ik->java_super()); + sort_methods(ik->super()); Array* interfaces = ik->local_interfaces(); int len = interfaces->length(); for (int i = 0; i < len; i++) { diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index ea9368c9277..89b3eca1257 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -183,7 +183,7 @@ static void reset_states(oop obj, TRAPS) { JavaCalls::call_special(&result, h_obj, klass, method_name, method_sig, CHECK); } - klass = klass->java_super(); + klass = klass->super(); } } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 4d8f2b50017..73c8710c62e 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -191,8 +191,8 @@ class DumpClassListCLDClosure : public CLDClosure { if (_dumped_classes.maybe_grow()) { log_info(aot, hashtables)("Expanded _dumped_classes table to %d", _dumped_classes.table_size()); } - if (ik->java_super()) { - dump(ik->java_super()); + if (ik->super()) { + dump(ik->super()); } Array* interfaces = ik->local_interfaces(); int len = interfaces->length(); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 72ec2866c6e..6266c024260 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -1572,7 +1572,7 @@ oop ciReplay::obj_field(oop obj, Symbol* name) { do { if (!ik->has_nonstatic_fields()) { - ik = ik->java_super(); + ik = ik->super(); continue; } @@ -1591,7 +1591,7 @@ oop ciReplay::obj_field(oop obj, Symbol* name) { } } - ik = ik->java_super(); + ik = ik->super(); } while (ik != nullptr); return nullptr; } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 01e35161efd..6c019f7c612 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -3957,7 +3957,7 @@ void OopMapBlocksBuilder::print_value_on(outputStream* st) const { void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { assert(ik != nullptr, "invariant"); - const InstanceKlass* const super = ik->java_super(); + const InstanceKlass* const super = ik->super(); // Check if this klass has an empty finalize method (i.e. one with return bytecode only), // in which case we don't have to register objects as finalizable @@ -4092,7 +4092,7 @@ static Array* compute_transitive_interfaces(const InstanceKlass* void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass, TRAPS) { assert(this_klass != nullptr, "invariant"); - const InstanceKlass* const super = this_klass->java_super(); + const InstanceKlass* const super = this_klass->super(); if (super != nullptr) { if (super->is_final()) { @@ -4210,7 +4210,7 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) const Symbol* const name = m->name(); const Symbol* const signature = m->signature(); - const InstanceKlass* k = this_klass->java_super(); + const InstanceKlass* k = this_klass->super(); const Method* super_m = nullptr; while (k != nullptr) { // skip supers that don't have final methods. @@ -4242,11 +4242,11 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) } // continue to look from super_m's holder's super. - k = super_m->method_holder()->java_super(); + k = super_m->method_holder()->super(); continue; } - k = k->java_super(); + k = k->super(); } } } @@ -5292,10 +5292,10 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, ResourceMark rm; // print out the superclass. const char * from = ik->external_name(); - if (ik->java_super() != nullptr) { + if (ik->super() != nullptr) { log_debug(class, resolve)("%s %s (super)", from, - ik->java_super()->external_name()); + ik->super()->external_name()); } // print out each of the interface classes referred to by this class. const Array* const local_interfaces = ik->local_interfaces(); diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 80de93261f4..e5cb5d8f354 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -123,7 +123,7 @@ class HierarchyVisitor : StackObj { InstanceKlass* interface_at(int index) { return _class->local_interfaces()->at(index); } - InstanceKlass* next_super() { return _class->java_super(); } + InstanceKlass* next_super() { return _class->super(); } InstanceKlass* next_interface() { return interface_at(interface_index()); } @@ -636,7 +636,7 @@ static void find_empty_vtable_slots(GrowableArray* slots, // Also any overpasses in our superclasses, that we haven't implemented. // (can't use the vtable because it is not guaranteed to be initialized yet) - InstanceKlass* super = klass->java_super(); + InstanceKlass* super = klass->super(); while (super != nullptr) { for (int i = 0; i < super->methods()->length(); ++i) { Method* m = super->methods()->at(i); @@ -668,7 +668,7 @@ static void find_empty_vtable_slots(GrowableArray* slots, } } } - super = super->java_super(); + super = super->super(); } LogTarget(Debug, defaultmethods) lt; diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index d06f5dd96d1..a87e12edc96 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -316,7 +316,7 @@ void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_instance block->set_offset(fs.offset()); all_fields->append(block); } - ik = ik->java_super() == nullptr ? nullptr : ik->java_super(); + ik = ik->super() == nullptr ? nullptr : ik->super(); } assert(last_offset == -1 || last_offset > 0, "Sanity"); if (last_offset > 0 && @@ -474,7 +474,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas break; } } - ik = ik->java_super(); + ik = ik->super(); } break; } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index ae7432c9fce..9bc94f15100 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -431,7 +431,7 @@ InstanceKlass* SystemDictionary::resolve_with_circularity_detection(Symbol* clas // (a) RedefineClasses -- the class is already loaded // (b) Rarely, the class might have been loaded by a parallel thread // We can do a quick check against the already assigned superclass's name and loader. - InstanceKlass* superk = klassk->java_super(); + InstanceKlass* superk = klassk->super(); if (superk != nullptr && superk->name() == next_name && superk->class_loader() == class_loader()) { @@ -1049,7 +1049,7 @@ bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle // load from the shared archive. if (ik->super() != nullptr) { - bool check_super = check_shared_class_super_type(ik, ik->java_super(), + bool check_super = check_shared_class_super_type(ik, ik->super(), class_loader, true, CHECK_false); if (!check_super) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 1be7a6db662..904e8cca89d 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -238,7 +238,7 @@ bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { if (k->name()->equals("jdk/internal/event/Event")) { return true; } - k = k->java_super(); + k = k->super(); } return false; } @@ -329,7 +329,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return true; } - InstanceKlass* super = k->java_super(); + InstanceKlass* super = k->super(); if (super != nullptr && check_for_exclusion(super, nullptr)) { ResourceMark rm; aot_log_warning(aot)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); @@ -571,7 +571,7 @@ bool SystemDictionaryShared::has_been_redefined(InstanceKlass* k) { if (k->has_been_redefined()) { return true; } - if (k->java_super() != nullptr && has_been_redefined(k->java_super())) { + if (k->super() != nullptr && has_been_redefined(k->super())) { return true; } Array* interfaces = k->local_interfaces(); diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 9b9222268a6..f51c17eb038 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -225,7 +225,7 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load } // add super and interfaces first - InstanceKlass* super = klass->java_super(); + InstanceKlass* super = klass->super(); if (super != nullptr && super->class_loader_data() == nullptr) { assert(super->is_instance_klass(), "Super should be instance klass"); resolve_shared_class(super, loader_data, domain, CHECK); diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index 81e8a82c78d..d5ef3502fa2 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -214,7 +214,7 @@ static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_t if (has_annotation(ik, annotation_type, default_value, value)) { return true; } - InstanceKlass* const super = ik->java_super(); + InstanceKlass* const super = ik->super(); return super != nullptr && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, default_value, value) : false; } diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index c9d79a23c2f..d431d98e383 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -76,7 +76,7 @@ const Symbol* EdgeUtils::field_name(const Edge& edge, jshort* modifiers) { } jfs.next(); } - ik = ik->java_super(); + ik = ik->super(); } *modifiers = 0; return nullptr; diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 867ccc6106d..4d7e6c9369c 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -364,6 +364,7 @@ void KlassHierarchy::print_class_hierarchy(outputStream* st, bool print_interfac } else { // We are only printing the hierarchy of a specific class. if (strcmp(classname, cie->klass()->external_name()) == 0) { + assert(cie->klass()->is_instance_klass(), "elements array contains only instance klasses"); KlassHierarchy::set_do_print_for_class_hierarchy(cie, &cit, print_subclasses); } } @@ -402,7 +403,7 @@ void KlassHierarchy::print_class_hierarchy(outputStream* st, bool print_interfac void KlassHierarchy::set_do_print_for_class_hierarchy(KlassInfoEntry* cie, KlassInfoTable* cit, bool print_subclasses) { // Set do_print for all superclasses of this class. - Klass* super = ((InstanceKlass*)cie->klass())->java_super(); + InstanceKlass* super = InstanceKlass::cast(cie->klass())->super(); while (super != nullptr) { KlassInfoEntry* super_cie = cit->lookup(super); super_cie->set_do_print(true); diff --git a/src/hotspot/share/oops/fieldStreams.hpp b/src/hotspot/share/oops/fieldStreams.hpp index 23ec156473b..08b04409a97 100644 --- a/src/hotspot/share/oops/fieldStreams.hpp +++ b/src/hotspot/share/oops/fieldStreams.hpp @@ -212,7 +212,7 @@ class HierarchicalFieldStream : public StackObj { InstanceKlass* result = _next_klass; do { if (!result->is_interface() && result->super() != nullptr) { - result = result->java_super(); + result = result->super(); } else if (_interface_index > 0) { result = _interfaces->at(--_interface_index); } else { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index a7641b9a546..964006b3b9c 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -677,7 +677,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(nullptr, SECONDARY_SUPERS_BITMAP_EMPTY); - deallocate_interfaces(loader_data, java_super(), local_interfaces(), transitive_interfaces()); + deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); @@ -748,7 +748,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { bool InstanceKlass::is_record() const { return _record_components != nullptr && is_final() && - java_super() == vmClasses::Record_klass(); + super() == vmClasses::Record_klass(); } bool InstanceKlass::is_sealed() const { @@ -763,9 +763,9 @@ bool InstanceKlass::is_sealed() const { // sealing conditions: it merely checks for a super of Enum. // This is sufficient for recognizing well-formed enums. bool InstanceKlass::is_enum_subclass() const { - InstanceKlass* s = java_super(); + InstanceKlass* s = super(); return (s == vmClasses::Enum_klass() || - (s != nullptr && s->java_super() == vmClasses::Enum_klass())); + (s != nullptr && s->super() == vmClasses::Enum_klass())); } bool InstanceKlass::should_be_initialized() const { @@ -829,7 +829,7 @@ void InstanceKlass::initialize(TRAPS) { void InstanceKlass::assert_no_clinit_will_run_for_aot_initialized_class() const { assert(has_aot_initialized_mirror(), "must be"); - InstanceKlass* s = java_super(); + InstanceKlass* s = super(); if (s != nullptr) { DEBUG_ONLY(ResourceMark rm); assert(s->is_initialized(), "super class %s of aot-inited class %s must have been initialized", @@ -942,7 +942,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { JavaThread* jt = THREAD; // link super class before linking this class - InstanceKlass* super_klass = java_super(); + InstanceKlass* super_klass = super(); if (super_klass != nullptr) { if (super_klass->is_interface()) { // check if super class is an interface ResourceMark rm(THREAD); @@ -1465,7 +1465,7 @@ void InstanceKlass::add_implementor(InstanceKlass* ik) { // Filter out subclasses whose supers already implement me. // (Note: CHA must walk subclasses of direct implementors // in order to locate indirect implementors.) - InstanceKlass* super_ik = ik->java_super(); + InstanceKlass* super_ik = ik->super(); if (super_ik != nullptr && super_ik->implements_interface(this)) // We only need to check one immediate superclass, since the // implements_interface query looks at transitive_interfaces. @@ -1831,7 +1831,7 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { InstanceKlass* supr = java_super(); + { InstanceKlass* supr = super(); if (supr != nullptr) return supr->find_field(name, sig, fd); } // 4) otherwise field lookup fails @@ -1851,7 +1851,7 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { InstanceKlass* supr = java_super(); + { InstanceKlass* supr = super(); if (supr != nullptr) return supr->find_field(name, sig, is_static, fd); } // 4) otherwise field lookup fails @@ -1876,7 +1876,7 @@ bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDesc if (klass->find_local_field_from_offset(offset, is_static, fd)) { return true; } - klass = klass->java_super(); + klass = klass->super(); } return false; } @@ -1919,7 +1919,7 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, Handle, TRAP } void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = java_super(); + InstanceKlass* super = this->super(); if (super != nullptr) { super->do_nonstatic_fields(cl); } @@ -1936,7 +1936,7 @@ static int compare_fields_by_offset(FieldInfo* a, FieldInfo* b) { } void InstanceKlass::print_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = java_super(); + InstanceKlass* super = this->super(); if (super != nullptr) { super->print_nonstatic_fields(cl); } @@ -2241,7 +2241,7 @@ Method* InstanceKlass::uncached_lookup_method(const Symbol* name, if (method != nullptr) { return method; } - klass = klass->java_super(); + klass = klass->super(); overpass_local_mode = OverpassLookupMode::skip; // Always ignore overpass methods in superclasses } return nullptr; @@ -2256,7 +2256,7 @@ bool InstanceKlass::has_redefined_this_or_super() const { if (klass->has_been_redefined()) { return true; } - klass = klass->java_super(); + klass = klass->super(); } return false; } @@ -2853,7 +2853,7 @@ bool InstanceKlass::can_be_verified_at_dumptime() const { if (major_version() < 50 /*JAVA_6_VERSION*/) { return false; } - if (java_super() != nullptr && !java_super()->can_be_verified_at_dumptime()) { + if (super() != nullptr && !super()->can_be_verified_at_dumptime()) { return false; } Array* interfaces = local_interfaces(); @@ -3985,7 +3985,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, // Class hierarchy info debug_stream.print(" klass: " PTR_FORMAT " super: " PTR_FORMAT, - p2i(this), p2i(java_super())); + p2i(this), p2i(super())); // Interfaces if (local_interfaces() != nullptr && local_interfaces()->length() > 0) { diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index a158494736b..3338b5cd446 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -918,8 +918,14 @@ public: return static_cast(k); } + // This hides Klass::super(). The _super of an InstanceKlass is + // always an InstanceKlass (or nullptr) + InstanceKlass* super() const { + return (Klass::super() == nullptr) ? nullptr : InstanceKlass::cast(Klass::super()); + } + virtual InstanceKlass* java_super() const { - return (super() == nullptr) ? nullptr : cast(super()); + return InstanceKlass::super(); } // Sizing (in words) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 1257f4cbcf8..91bd60b0e3e 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -217,7 +217,9 @@ protected: // super() cannot be InstanceKlass* -- Java arrays are covariant, and _super is used // to implement that. NB: the _super of "[Ljava/lang/Integer;" is "[Ljava/lang/Number;" - // If this is not what your code expects, you're probably looking for Klass::java_super(). + // If this is not what your code expects, you're probably looking for: + // - Klass::java_super() - if you have a Klass* + // - InstanceKlass::super() - if you have an InstanceKlass* ik, ik->super() returns InstanceKlass*. Klass* super() const { return _super; } void set_super(Klass* k) { _super = k; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index bb47496b406..55242b2a2d1 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -346,7 +346,7 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper break; } // if no override found yet, continue to search up - superk = superk->java_super(); + superk = superk->super(); } return superk; @@ -683,14 +683,14 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // a new entry Symbol* name = target_method->name(); Symbol* signature = target_method->signature(); - const InstanceKlass* k = super; + const InstanceKlass* ik = super; Method* super_method = nullptr; InstanceKlass *holder = nullptr; Method* recheck_method = nullptr; bool found_pkg_prvt_method = false; - while (k != nullptr) { + while (ik != nullptr) { // lookup through the hierarchy for a method with matching name and sign. - super_method = InstanceKlass::cast(k)->lookup_method(name, signature); + super_method = ik->lookup_method(name, signature); if (super_method == nullptr) { break; // we still have to search for a matching miranda method } @@ -722,7 +722,7 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // Start with lookup result and continue to search up, for versions supporting transitive override if (major_version >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) { - k = superk->java_super(); // haven't found an override match yet; continue to look + ik = superk->super(); // haven't found an override match yet; continue to look } else { break; } @@ -774,7 +774,7 @@ bool klassVtable::is_miranda_entry_at(int i) { if (holder->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(holder) , "this class should implement the interface"); - if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->java_super(), klass()->is_interface())) { + if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super(), klass()->is_interface())) { return true; } } @@ -865,7 +865,7 @@ bool klassVtable::is_miranda(Method* m, Array* class_methods, // Overpasses may or may not exist for supers for pass 1, // they should have been created for pass 2 and later. - for (const InstanceKlass* cursuper = super; cursuper != nullptr; cursuper = cursuper->java_super()) { + for (const InstanceKlass* cursuper = super; cursuper != nullptr; cursuper = cursuper->super()) { Method* found_mth = cursuper->find_local_method(name, signature, Klass::OverpassLookupMode::find, Klass::StaticLookupMode::skip, @@ -959,7 +959,7 @@ void klassVtable::get_mirandas(GrowableArray* new_mirandas, int klassVtable::fill_in_mirandas(Thread* current, int initialized) { ResourceMark rm(current); GrowableArray mirandas(20); - get_mirandas(&mirandas, nullptr, ik()->java_super(), ik()->methods(), + get_mirandas(&mirandas, nullptr, ik()->super(), ik()->methods(), ik()->default_methods(), ik()->local_interfaces(), klass()->is_interface()); for (int i = 0; i < mirandas.length(); i++) { @@ -1571,8 +1571,7 @@ void klassVtable::verify(outputStream* st, bool forced) { // verify consistency with superKlass vtable Klass* super = _klass->super(); if (super != nullptr) { - InstanceKlass* sk = InstanceKlass::cast(super); - klassVtable vt = sk->vtable(); + klassVtable vt = super->vtable(); for (int i = 0; i < vt.length(); i++) { verify_against(st, &vt, i); } diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 0375756e219..4febb4f3125 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -451,7 +451,7 @@ ClassFieldMap* ClassFieldMap::create_map_of_static_fields(Klass* k) { // Static fields of interfaces and superclasses are reported as references from the interfaces/superclasses. // Need to calculate start index of this class fields: number of fields in all interfaces and superclasses. int index = interfaces_field_count(ik); - for (InstanceKlass* super_klass = ik->java_super(); super_klass != nullptr; super_klass = super_klass->java_super()) { + for (InstanceKlass* super_klass = ik->super(); super_klass != nullptr; super_klass = super_klass->super()) { FilteredJavaFieldStream super_fld(super_klass); index += super_fld.field_count(); } @@ -478,12 +478,12 @@ ClassFieldMap* ClassFieldMap::create_map_of_instance_fields(oop obj) { // fields of the superclasses are reported first, so need to know total field number to calculate field indices int total_field_number = interfaces_field_count(ik); - for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->java_super()) { + for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->super()) { FilteredJavaFieldStream fld(klass); total_field_number += fld.field_count(); } - for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->java_super()) { + for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->super()) { FilteredJavaFieldStream fld(klass); int start_index = total_field_number - fld.field_count(); for (int index = 0; !fld.done(); fld.next(), index++) { @@ -2597,10 +2597,10 @@ inline bool VM_HeapWalkOperation::iterate_over_class(oop java_class) { oop mirror = klass->java_mirror(); // super (only if something more interesting than java.lang.Object) - InstanceKlass* java_super = ik->java_super(); - if (java_super != nullptr && java_super != vmClasses::Object_klass()) { - oop super = java_super->java_mirror(); - if (!CallbackInvoker::report_superclass_reference(mirror, super)) { + InstanceKlass* super_klass = ik->super(); + if (super_klass != nullptr && super_klass != vmClasses::Object_klass()) { + oop super_oop = super_klass->java_mirror(); + if (!CallbackInvoker::report_superclass_reference(mirror, super_oop)) { return false; } } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 521ac5454ea..da9a4e9cd9a 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1474,7 +1474,7 @@ public: // Gets the fields of `klass` that are eliminated by escape analysis and need to be reassigned static GrowableArray* get_reassigned_fields(InstanceKlass* klass, GrowableArray* fields, bool is_jvmci) { - InstanceKlass* super = klass->java_super(); + InstanceKlass* super = klass->super(); if (super != nullptr) { get_reassigned_fields(super, fields, is_jvmci); } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 5ea2a4e4385..89d742e0ea8 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1140,7 +1140,7 @@ void JavaThread::install_async_exception(AsyncExceptionHandshakeClosure* aehc) { ResourceMark rm; if (log_is_enabled(Info, exceptions)) { log_info(exceptions)("Pending Async. exception installed of type: %s", - InstanceKlass::cast(exception->klass())->external_name()); + exception->klass()->external_name()); } // for AbortVMOnException flag Exceptions::debug_check_abort(exception->klass()->external_name()); diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index f2a7587d364..0f61770a639 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -459,7 +459,7 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) { char klass_name[256]; char tmp_sig_name[16]; const char* sig_name = "UNKNOWN"; - InstanceKlass::cast(PENDING_EXCEPTION->klass())-> + PENDING_EXCEPTION->klass()-> name()->as_klass_external_name(klass_name, 256); if (os::exception_name(sig, tmp_sig_name, 16) != nullptr) sig_name = tmp_sig_name; diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 59460dbf89b..cf62972ca16 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -765,7 +765,7 @@ class DumperSupport : AllStatic { // creates HPROF_GC_INSTANCE_DUMP record for the given object static void dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache); // creates HPROF_GC_CLASS_DUMP record for the given instance class - static void dump_instance_class(AbstractDumpWriter* writer, Klass* k); + static void dump_instance_class(AbstractDumpWriter* writer, InstanceKlass* ik); // creates HPROF_GC_CLASS_DUMP record for a given array class static void dump_array_class(AbstractDumpWriter* writer, Klass* k); @@ -1204,9 +1204,7 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClass } // creates HPROF_GC_CLASS_DUMP record for the given instance class -void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { - InstanceKlass* ik = InstanceKlass::cast(k); - +void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, InstanceKlass* ik) { // We can safepoint and do a heap dump at a point where we have a Klass, // but no java mirror class has been setup for it. So we need to check // that the class is at least loaded, to avoid crash from a null mirror. @@ -1227,11 +1225,11 @@ void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { writer->write_u4(STACK_TRACE_ID); // super class ID - InstanceKlass* java_super = ik->java_super(); - if (java_super == nullptr) { + InstanceKlass* super = ik->super(); + if (super == nullptr) { writer->write_objectID(oop(nullptr)); } else { - writer->write_classID(java_super); + writer->write_classID(super); } writer->write_objectID(ik->class_loader()); @@ -1505,7 +1503,7 @@ class ClassDumper : public KlassClosure { void do_klass(Klass* k) { if (k->is_instance_klass()) { - DumperSupport::dump_instance_class(writer(), k); + DumperSupport::dump_instance_class(writer(), InstanceKlass::cast(k)); } else { DumperSupport::dump_array_class(writer(), k); } From 4d1dfabcb4e94601995b07b7ecea4249ae375a04 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Thu, 4 Sep 2025 04:35:51 +0000 Subject: [PATCH 121/295] 8366038: Thread::SpinRelease should use Atomic::release_store Reviewed-by: dholmes, ayang --- src/hotspot/share/runtime/thread.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index ed1c8c2508f..9c12da15180 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -602,7 +602,6 @@ void Thread::SpinAcquire(volatile int * adr) { void Thread::SpinRelease(volatile int * adr) { assert(*adr != 0, "invariant"); - OrderAccess::fence(); // guarantee at least release consistency. // Roach-motel semantics. // It's safe if subsequent LDs and STs float "up" into the critical section, // but prior LDs and STs within the critical section can't be allowed @@ -610,8 +609,7 @@ void Thread::SpinRelease(volatile int * adr) { // Loads and stores in the critical section - which appear in program // order before the store that releases the lock - must also appear // before the store that releases the lock in memory visibility order. - // Conceptually we need a #loadstore|#storestore "release" MEMBAR before - // the ST of 0 into the lock-word which releases the lock, so fence - // more than covers this on all platforms. - *adr = 0; + // So we need a #loadstore|#storestore "release" memory barrier before + // the ST of 0 into the lock-word which releases the lock. + Atomic::release_store(adr, 0); } From 90a2db1ecbc3ea25a8e9f15b34a3d8f3941b60d0 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 04:47:48 +0000 Subject: [PATCH 122/295] 8366474: Rename MetaspaceObj::is_shared() to MetaspaceObj::in_aot_cache() Reviewed-by: liach, kvn --- src/hotspot/os/posix/vmError_posix.cpp | 2 +- src/hotspot/os/windows/vmError_windows.cpp | 2 +- src/hotspot/share/cds/aotArtifactFinder.cpp | 2 +- src/hotspot/share/cds/aotClassLinker.cpp | 2 +- .../share/cds/aotConstantPoolResolver.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 8 +-- src/hotspot/share/cds/archiveUtils.hpp | 6 +- src/hotspot/share/cds/archiveUtils.inline.hpp | 2 +- src/hotspot/share/cds/cdsProtectionDomain.cpp | 4 +- src/hotspot/share/cds/classListWriter.cpp | 2 +- src/hotspot/share/cds/cppVtables.cpp | 2 +- src/hotspot/share/cds/dumpTimeClassInfo.cpp | 4 +- src/hotspot/share/cds/dynamicArchive.cpp | 16 ++--- src/hotspot/share/cds/filemap.cpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 4 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 +- .../share/cds/lambdaProxyClassDictionary.cpp | 14 ++-- src/hotspot/share/cds/metaspaceShared.cpp | 32 +++++----- src/hotspot/share/cds/metaspaceShared.hpp | 15 +++-- src/hotspot/share/cds/runTimeClassInfo.cpp | 2 +- src/hotspot/share/cds/runTimeClassInfo.hpp | 2 +- .../share/classfile/classLoaderData.cpp | 4 +- src/hotspot/share/classfile/javaClasses.cpp | 4 +- src/hotspot/share/classfile/klassFactory.cpp | 2 +- .../share/classfile/systemDictionary.cpp | 6 +- .../classfile/systemDictionaryShared.cpp | 16 ++--- .../classfile/systemDictionaryShared.hpp | 4 +- src/hotspot/share/classfile/verifier.cpp | 2 +- src/hotspot/share/classfile/vmClasses.cpp | 6 +- .../share/compiler/compilationPolicy.cpp | 2 +- .../share/interpreter/interpreterRuntime.cpp | 2 +- src/hotspot/share/interpreter/rewriter.cpp | 6 +- src/hotspot/share/memory/allocation.cpp | 4 +- src/hotspot/share/memory/allocation.hpp | 38 +++++------ src/hotspot/share/memory/metadataFactory.hpp | 6 +- src/hotspot/share/memory/metaspace.cpp | 4 +- src/hotspot/share/memory/metaspace.hpp | 6 +- .../printCLDMetaspaceInfoClosure.cpp | 2 +- .../printMetaspaceInfoKlassClosure.cpp | 4 +- src/hotspot/share/oops/arrayKlass.cpp | 4 +- src/hotspot/share/oops/constantPool.cpp | 14 ++-- src/hotspot/share/oops/constantPool.hpp | 8 +-- src/hotspot/share/oops/cpCache.cpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 64 +++++++++---------- .../share/oops/instanceMirrorKlass.inline.hpp | 4 +- src/hotspot/share/oops/klass.cpp | 4 +- src/hotspot/share/oops/klass.hpp | 14 ++-- src/hotspot/share/oops/klassVtable.cpp | 10 +-- src/hotspot/share/oops/method.cpp | 8 +-- src/hotspot/share/oops/trainingData.cpp | 2 +- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 4 +- .../sun/jvm/hotspot/memory/MetaspaceObj.java | 14 ++-- 55 files changed, 204 insertions(+), 201 deletions(-) diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp index 9d6cd175c66..4bfd8efabe8 100644 --- a/src/hotspot/os/posix/vmError_posix.cpp +++ b/src/hotspot/os/posix/vmError_posix.cpp @@ -117,7 +117,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { if (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) { const void* const fault_addr = si->si_addr; if (fault_addr != nullptr) { - if (MetaspaceShared::is_in_shared_metaspace(fault_addr)) { + if (MetaspaceShared::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/os/windows/vmError_windows.cpp b/src/hotspot/os/windows/vmError_windows.cpp index 1613f52136f..fbd91309822 100644 --- a/src/hotspot/os/windows/vmError_windows.cpp +++ b/src/hotspot/os/windows/vmError_windows.cpp @@ -51,7 +51,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { er->NumberParameters >= 2) { const void* const fault_addr = (const void*) er->ExceptionInformation[1]; if (fault_addr != nullptr) { - if (MetaspaceShared::is_in_shared_metaspace(fault_addr)) { + if (MetaspaceShared::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index 84bc2797c58..5f346e832a8 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -224,7 +224,7 @@ void AOTArtifactFinder::append_to_all_cached_classes(Klass* k) { } void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { - if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->in_aot_cache()) { // This class is already included in the base archive. No need to cache // it again in the dynamic archive. return; diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp index adb18aa3aef..1f9a03de83f 100644 --- a/src/hotspot/share/cds/aotClassLinker.cpp +++ b/src/hotspot/share/cds/aotClassLinker.cpp @@ -212,7 +212,7 @@ Array* AOTClassLinker::write_classes(oop class_loader, bool is_j continue; } - if (ik->is_shared() && CDSConfig::is_dumping_dynamic_archive()) { + if (ik->in_aot_cache() && CDSConfig::is_dumping_dynamic_archive()) { if (CDSConfig::is_using_aot_linked_classes()) { // This class was recorded as AOT-linked for the base archive, // so there's no need to do so again for the dynamic archive. diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.cpp b/src/hotspot/share/cds/aotConstantPoolResolver.cpp index 0eb7ddfbbf6..6cc3a81c2ae 100644 --- a/src/hotspot/share/cds/aotConstantPoolResolver.cpp +++ b/src/hotspot/share/cds/aotConstantPoolResolver.cpp @@ -85,7 +85,7 @@ bool AOTConstantPoolResolver::is_class_resolution_deterministic(InstanceKlass* c if (resolved_class->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(resolved_class); - if (!ik->is_shared() && SystemDictionaryShared::is_excluded_class(ik)) { + if (!ik->in_aot_cache() && SystemDictionaryShared::is_excluded_class(ik)) { return false; } diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 7ffbf0151d2..00aca188f96 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -365,8 +365,8 @@ address ArchiveBuilder::reserve_buffer() { if (CDSConfig::is_dumping_static_archive()) { my_archive_requested_bottom = _requested_static_archive_bottom; } else { - _mapped_static_archive_bottom = (address)MetaspaceObj::shared_metaspace_base(); - _mapped_static_archive_top = (address)MetaspaceObj::shared_metaspace_top(); + _mapped_static_archive_bottom = (address)MetaspaceObj::aot_metaspace_base(); + _mapped_static_archive_top = (address)MetaspaceObj::aot_metaspace_top(); assert(_mapped_static_archive_top >= _mapped_static_archive_bottom, "must be"); size_t static_archive_size = _mapped_static_archive_top - _mapped_static_archive_bottom; @@ -540,7 +540,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { return SystemDictionaryShared::is_excluded_class(ik); } else if (klass->is_objArray_klass()) { Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_shared_static(bottom)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache_static_region(bottom)) { // The bottom class is in the static archive so it's clearly not excluded. return false; } else if (bottom->is_instance_klass()) { @@ -553,7 +553,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) { address obj = ref->obj(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(obj)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(obj)) { // Don't dump existing shared metadata again. return point_to_it; } else if (ref->msotype() == MetaspaceObj::MethodDataType || diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 8fce6e31bb1..be423881008 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -275,7 +275,7 @@ public: } // The following functions translate between a u4 offset and an address in the - // the range of the mapped CDS archive (e.g., Metaspace::is_in_shared_metaspace()). + // the range of the mapped CDS archive (e.g., Metaspace::in_aot_cache()). // Since the first 16 bytes in this range are dummy data (see ArchiveBuilder::reserve_buffer()), // we know that offset 0 never represents a valid object. As a result, an offset of 0 // is used to encode a nullptr. @@ -287,7 +287,7 @@ public: template T static offset_to_archived_address(u4 offset) { assert(offset != 0, "sanity"); T p = (T)(SharedBaseAddress + offset); - assert(Metaspace::is_in_shared_metaspace(p), "must be"); + assert(Metaspace::in_aot_cache(p), "must be"); return p; } @@ -303,7 +303,7 @@ public: template static u4 archived_address_to_offset(T p) { uintx pn = (uintx)p; uintx base = (uintx)SharedBaseAddress; - assert(Metaspace::is_in_shared_metaspace(p), "must be"); + assert(Metaspace::in_aot_cache(p), "must be"); assert(pn > base, "sanity"); // No valid object is stored at 0 offset from SharedBaseAddress uintx offset = pn - base; assert(offset <= MAX_SHARED_DELTA, "range check"); diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 12c9a0bc705..70b91fb8900 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.inline.hpp @@ -80,7 +80,7 @@ Array* ArchiveUtils::archive_ptr_array(GrowableArray* tmp_array) { for (int i = 0; i < tmp_array->length(); i++) { T ptr = tmp_array->at(i); if (ptr != nullptr && !builder->is_in_buffer_space(ptr)) { - if (is_dynamic_dump && MetaspaceShared::is_in_shared_metaspace(ptr)) { + if (is_dynamic_dump && MetaspaceShared::in_aot_cache(ptr)) { // We have a pointer that lives in the dynamic archive but points into // the static archive. } else { diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index e907998fa85..c95fd8b64df 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -117,8 +117,8 @@ Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) { PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) { PackageEntry* pkg_entry = ik->package(); - if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) { - assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be"); + if (CDSConfig::is_using_full_module_graph() && ik->in_aot_cache() && pkg_entry != nullptr) { + assert(MetaspaceShared::in_aot_cache(pkg_entry), "must be"); assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class"); return pkg_entry; } diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 4d48a07d736..882bb84036f 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -110,7 +110,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre bool is_builtin_loader = SystemDictionaryShared::is_builtin_loader(loader_data); if (!is_builtin_loader) { // class may be loaded from shared archive - if (!k->is_shared()) { + if (!k->in_aot_cache()) { if (cfs == nullptr || cfs->source() == nullptr) { // CDS static dump only handles unregistered class with known source. return; diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 319e4f6e95f..261f5332526 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -321,7 +321,7 @@ void CppVtables::zero_archived_vtables() { } bool CppVtables::is_valid_shared_method(const Method* m) { - assert(MetaspaceShared::is_in_shared_metaspace(m), "must be"); + assert(MetaspaceShared::in_aot_cache(m), "must be"); return vtable_of(m) == _index[Method_Kind]->cloned_vtable() || vtable_of(m) == _archived_cpp_vtptrs[Method_Kind]; } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.cpp b/src/hotspot/share/cds/dumpTimeClassInfo.cpp index 6a06344fb0d..8af762dba4d 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -142,7 +142,7 @@ bool DumpTimeClassInfo::is_builtin() { } DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) { - assert(CDSConfig::is_dumping_final_static_archive() || !k->is_shared(), "Do not call with shared classes"); + assert(CDSConfig::is_dumping_final_static_archive() || !k->in_aot_cache(), "Do not call with shared classes"); bool created; DumpTimeClassInfo* p = put_if_absent(k, &created); assert(created, "must not exist in table"); @@ -151,7 +151,7 @@ DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) { } DumpTimeClassInfo* DumpTimeSharedClassTable::get_info(InstanceKlass* k) { - assert(CDSConfig::is_dumping_final_static_archive() || !k->is_shared(), "Do not call with shared classes"); + assert(CDSConfig::is_dumping_final_static_archive() || !k->in_aot_cache(), "Do not call with shared classes"); DumpTimeClassInfo* p = get(k); assert(p != nullptr, "we must not see any non-shared InstanceKlass* that's " "not stored with SystemDictionaryShared::init_dumptime_info"); diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 35a50297536..8499dced126 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -187,10 +187,10 @@ public: for (int i = T_BOOLEAN; i <= T_LONG; i++) { assert(is_java_primitive((BasicType)i), "sanity"); Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc - assert(MetaspaceShared::is_shared_static((void*)k), + assert(MetaspaceShared::in_aot_cache_static_region((void*)k), "one-dimensional primitive array should be in static archive"); ArrayKlass* ak = ArrayKlass::cast(k); - while (ak != nullptr && ak->is_shared()) { + while (ak != nullptr && ak->in_aot_cache()) { Klass* next_k = ak->array_klass_or_null(); if (next_k != nullptr) { ak = ArrayKlass::cast(next_k); @@ -253,7 +253,7 @@ void DynamicArchiveBuilder::sort_methods() { // klasses were created. Re-sort all the tables. See Method::sort_methods(). void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { assert(ik != nullptr, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); - if (MetaspaceShared::is_in_shared_metaspace(ik)) { + if (MetaspaceShared::in_aot_cache(ik)) { // We have reached a supertype that's already in the base archive return; } @@ -287,13 +287,13 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { if (ik->methods() != nullptr) { for (int m = 0; m < ik->methods()->length(); m++) { Symbol* name = ik->methods()->at(m)->name(); - assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be"); + assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } if (ik->default_methods() != nullptr) { for (int m = 0; m < ik->default_methods()->length(); m++) { Symbol* name = ik->default_methods()->at(m)->name(); - assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be"); + assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } #endif @@ -367,14 +367,14 @@ void DynamicArchiveBuilder::gather_array_klasses() { if (klasses()->at(i)->is_objArray_klass()) { ObjArrayKlass* oak = ObjArrayKlass::cast(klasses()->at(i)); Klass* elem = oak->element_klass(); - if (MetaspaceShared::is_shared_static(elem)) { + if (MetaspaceShared::in_aot_cache_static_region(elem)) { // Only capture the array klass whose element_klass is in the static archive. // During run time, setup (see DynamicArchive::setup_array_klasses()) is needed // so that the element_klass can find its array klasses from the dynamic archive. DynamicArchive::append_array_klass(oak); } else { // The element_klass and its array klasses are in the same archive. - assert(!MetaspaceShared::is_shared_static(oak), + assert(!MetaspaceShared::in_aot_cache_static_region(oak), "we should not gather klasses that are already in the static archive"); } } @@ -435,7 +435,7 @@ void DynamicArchive::setup_array_klasses() { assert(!oak->is_typeArray_klass(), "all type array classes must be in static archive"); Klass* elm = oak->element_klass(); - assert(MetaspaceShared::is_shared_static((void*)elm), "must be"); + assert(MetaspaceShared::in_aot_cache_static_region((void*)elm), "must be"); if (elm->is_instance_klass()) { assert(InstanceKlass::cast(elm)->array_klasses() == nullptr, "must be"); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index a2b9e83ee68..78f02161477 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1144,7 +1144,7 @@ MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* FileMapRegion* r = region_at(idx); DEBUG_ONLY(if (last_region != nullptr) { // Ensure that the OS won't be able to allocate new memory spaces between any mapped - // regions, or else it would mess up the simple comparison in MetaspaceObj::is_shared(). + // regions, or else it would mess up the simple comparison in MetaspaceObj::in_aot_cache(). assert(r->mapped_base() == last_region->mapped_end(), "must have no gaps"); } last_region = r;) diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 89b3eca1257..cfa2944d974 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1220,7 +1220,7 @@ const ArchivedKlassSubGraphInfoRecord* HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAPS) { assert(!CDSConfig::is_dumping_heap(), "Should not be called when dumping heap"); - if (!k->is_shared()) { + if (!k->in_aot_cache()) { return nullptr; } unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(k); @@ -1274,7 +1274,7 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP if (klasses != nullptr) { for (int i = 0; i < klasses->length(); i++) { Klass* klass = klasses->at(i); - if (!klass->is_shared()) { + if (!klass->in_aot_cache()) { return nullptr; } resolve_or_init(klass, do_init, CHECK_NULL); diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index ab91e76e923..4241619385e 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -179,7 +179,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { TempNewSymbol class_name_sym = SymbolTable::new_symbol(class_name); Klass* klass = SystemDictionary::resolve_or_null(class_name_sym, THREAD); assert(klass != nullptr, "must already be loaded"); - if (!klass->is_shared() && klass->shared_classpath_index() < 0) { + if (!klass->in_aot_cache() && klass->shared_classpath_index() < 0) { // Fake it, so that it will be included into the archive. klass->set_shared_classpath_index(0); // Set the "generated" bit, so it won't interfere with JVMTI. @@ -223,7 +223,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, assert(!HAS_PENDING_EXCEPTION, "Invariant"); result->set_is_generated_shared_class(); - if (!klass->is_shared()) { + if (!klass->in_aot_cache()) { log_info(aot, lambda)("regenerate_class excluding klass %s %s", class_name, klass->name()->as_C_string()); SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump } diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index a812af18ba7..c8281ef497c 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -247,12 +247,12 @@ InstanceKlass* LambdaProxyClassDictionary::find_lambda_proxy_class(InstanceKlass assert(method_type != nullptr, "sanity"); assert(instantiated_method_type != nullptr, "sanity"); - if (!caller_ik->is_shared() || - !invoked_name->is_shared() || - !invoked_type->is_shared() || - !method_type->is_shared() || - (member_method != nullptr && !member_method->is_shared()) || - !instantiated_method_type->is_shared()) { + if (!caller_ik->in_aot_cache() || + !invoked_name->in_aot_cache() || + !invoked_type->in_aot_cache() || + !method_type->in_aot_cache() || + (member_method != nullptr && !member_method->in_aot_cache()) || + !instantiated_method_type->in_aot_cache()) { // These can't be represented as u4 offset, but we wouldn't have archived a lambda proxy in this case anyway. return nullptr; } @@ -325,7 +325,7 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst InstanceKlass* shared_nest_host = get_shared_nest_host(lambda_ik); assert(shared_nest_host != nullptr, "unexpected nullptr _nest_host"); - assert(shared_nest_host->is_shared(), "nest host must be in CDS archive"); + assert(shared_nest_host->in_aot_cache(), "nest host must be in aot metaspace"); Klass* resolved_nest_host = SystemDictionary::resolve_or_fail(shared_nest_host->name(), class_loader, true, CHECK_NULL); if (resolved_nest_host != shared_nest_host) { diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 73c8710c62e..92773c5be90 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -108,7 +108,7 @@ ReservedSpace MetaspaceShared::_symbol_rs; VirtualSpace MetaspaceShared::_symbol_vs; bool MetaspaceShared::_archive_loading_failed = false; bool MetaspaceShared::_remapped_readwrite = false; -void* MetaspaceShared::_shared_metaspace_static_top = nullptr; +void* MetaspaceShared::_aot_metaspace_static_top = nullptr; intx MetaspaceShared::_relocation_delta; char* MetaspaceShared::_requested_base_address; Array* MetaspaceShared::_archived_method_handle_intrinsics = nullptr; @@ -1208,7 +1208,7 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { JavaThread* THREAD = current; // For exception macros. assert(CDSConfig::is_dumping_archive(), "sanity"); - if (ik->is_shared() && !CDSConfig::is_dumping_final_static_archive()) { + if (ik->in_aot_cache() && !CDSConfig::is_dumping_final_static_archive()) { assert(CDSConfig::is_dumping_dynamic_archive(), "must be"); return false; } @@ -1252,23 +1252,23 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() { } } -void MetaspaceShared::set_shared_metaspace_range(void* base, void *static_top, void* top) { +void MetaspaceShared::set_aot_metaspace_range(void* base, void *static_top, void* top) { assert(base <= static_top && static_top <= top, "must be"); - _shared_metaspace_static_top = static_top; - MetaspaceObj::set_shared_metaspace_range(base, top); + _aot_metaspace_static_top = static_top; + MetaspaceObj::set_aot_metaspace_range(base, top); } -bool MetaspaceShared::is_shared_dynamic(void* p) { - if ((p < MetaspaceObj::shared_metaspace_top()) && - (p >= _shared_metaspace_static_top)) { +bool MetaspaceShared::in_aot_cache_dynamic_region(void* p) { + if ((p < MetaspaceObj::aot_metaspace_top()) && + (p >= _aot_metaspace_static_top)) { return true; } else { return false; } } -bool MetaspaceShared::is_shared_static(void* p) { - if (is_in_shared_metaspace(p) && !is_shared_dynamic(p)) { +bool MetaspaceShared::in_aot_cache_static_region(void* p) { + if (in_aot_cache(p) && !in_aot_cache_dynamic_region(p)) { return true; } else { return false; @@ -1368,7 +1368,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { char* cds_end = dynamic_mapped ? dynamic_mapinfo->mapped_end() : static_mapinfo->mapped_end(); // Register CDS memory region with LSan. LSAN_REGISTER_ROOT_REGION(cds_base, cds_end - cds_base); - set_shared_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end); + set_aot_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end); _relocation_delta = static_mapinfo->relocation_delta(); _requested_base_address = static_mapinfo->requested_base_address(); if (dynamic_mapped) { @@ -1376,7 +1376,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { AutoCreateSharedArchive = false; } } else { - set_shared_metaspace_range(nullptr, nullptr, nullptr); + set_aot_metaspace_range(nullptr, nullptr, nullptr); if (CDSConfig::is_dumping_dynamic_archive()) { aot_log_warning(aot)("-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); } @@ -1466,7 +1466,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File if (dynamic_mapinfo != nullptr) { // Ensure that the OS won't be able to allocate new memory spaces between the two - // archives, or else it would mess up the simple comparison in MetaspaceObj::is_shared(). + // archives, or else it would mess up the simple comparison in MetaspaceObj::in_aot_cache(). assert(static_mapinfo->mapping_end_offset() == dynamic_mapinfo->mapping_base_offset(), "no gap"); } @@ -2075,9 +2075,9 @@ bool MetaspaceShared::remap_shared_readonly_as_readwrite() { void MetaspaceShared::print_on(outputStream* st) { if (CDSConfig::is_using_archive()) { st->print("CDS archive(s) mapped at: "); - address base = (address)MetaspaceObj::shared_metaspace_base(); - address static_top = (address)_shared_metaspace_static_top; - address top = (address)MetaspaceObj::shared_metaspace_top(); + address base = (address)MetaspaceObj::aot_metaspace_base(); + address static_top = (address)_aot_metaspace_static_top; + address top = (address)MetaspaceObj::aot_metaspace_top(); st->print("[" PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "), ", p2i(base), p2i(static_top), p2i(top)); st->print("size %zu, ", top - base); st->print("SharedBaseAddress: " PTR_FORMAT ", ArchiveRelocationMode: %d.", SharedBaseAddress, ArchiveRelocationMode); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 130e7fe4484..7f0f1128f96 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -54,7 +54,7 @@ class MetaspaceShared : AllStatic { static VirtualSpace _symbol_vs; // used only during -Xshare:dump static bool _archive_loading_failed; static bool _remapped_readwrite; - static void* _shared_metaspace_static_top; + static void* _aot_metaspace_static_top; static intx _relocation_delta; static char* _requested_base_address; static bool _use_optimized_module_handling; @@ -101,14 +101,17 @@ public: // Return true if given address is in the shared metaspace regions (i.e., excluding the // mapped heap region.) - static bool is_in_shared_metaspace(const void* p) { - return MetaspaceObj::is_shared((const MetaspaceObj*)p); + static bool in_aot_cache(const void* p) { + return MetaspaceObj::in_aot_cache((const MetaspaceObj*)p); } - static void set_shared_metaspace_range(void* base, void *static_top, void* top) NOT_CDS_RETURN; + static void set_aot_metaspace_range(void* base, void *static_top, void* top) NOT_CDS_RETURN; - static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false); - static bool is_shared_static(void* p) NOT_CDS_RETURN_(false); + // inside the metaspace of the AOT cache, or the static CDS archive + static bool in_aot_cache_static_region(void* p) NOT_CDS_RETURN_(false); + + // inside the metaspace of the dynamic static CDS archive + static bool in_aot_cache_dynamic_region(void* p) NOT_CDS_RETURN_(false); static void unrecoverable_loading_error(const char* message = "unrecoverable error"); static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0); diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index 3d237e6759a..10d2fc35ea9 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -75,7 +75,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { } InstanceKlass* RunTimeClassInfo::klass() const { - if (MetaspaceShared::is_in_shared_metaspace(this)) { + if (MetaspaceShared::in_aot_cache(this)) { // is inside a mmaped CDS archive. return ArchiveUtils::offset_to_archived_address(_klass_offset); } else { diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index 058d5181881..bf41e05eee5 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -251,7 +251,7 @@ private: public: static RunTimeClassInfo* get_for(InstanceKlass* klass) { - assert(klass->is_shared(), "don't call for non-shared class"); + assert(klass->in_aot_cache(), "don't call for non-shared class"); return *info_pointer_addr(klass); } static void set_for(InstanceKlass* klass, RunTimeClassInfo* record) { diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index d6677faa91d..deb2035eef2 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -415,7 +415,7 @@ void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { if (!InstanceKlass::cast(k)->is_loaded()) { continue; } - } else if (k->is_shared() && k->is_objArray_klass()) { + } else if (k->in_aot_cache() && k->is_objArray_klass()) { Klass* bottom = ObjArrayKlass::cast(k)->bottom_klass(); if (bottom->is_instance_klass() && !InstanceKlass::cast(bottom)->is_loaded()) { // This could happen if is a shared class that has been restored @@ -868,7 +868,7 @@ void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) { // a safepoint which checks if handles point to this metadata field. void ClassLoaderData::add_to_deallocate_list(Metadata* m) { // Metadata in shared region isn't deleted. - if (!m->is_shared()) { + if (!m->in_aot_cache()) { MutexLocker ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); if (_deallocate_list == nullptr) { _deallocate_list = new (mtClass) GrowableArray(100, mtClass); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index bf678f94e0e..683fc22b27a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -939,7 +939,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { assert(InstanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already"); // If the offset was read from the shared archive, it was fixed up already - if (!k->is_shared()) { + if (!k->in_aot_cache()) { if (k->is_instance_klass()) { // During bootstrap, java.lang.Class wasn't loaded so static field // offsets were computed without the size added it. Go back and @@ -977,7 +977,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { } } - if (k->is_shared() && k->has_archived_mirror_index()) { + if (k->in_aot_cache() && k->has_archived_mirror_index()) { if (ArchiveHeapLoader::is_in_use()) { bool present = restore_archived_mirror(k, Handle(), Handle(), Handle(), CHECK); assert(present, "Missing archived mirror for %s", k->external_name()); diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 5dd2cd2385b..50d327d7e8c 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -51,7 +51,7 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( TRAPS) { #if INCLUDE_CDS && INCLUDE_JVMTI assert(ik != nullptr, "sanity"); - assert(ik->is_shared(), "expecting a shared class"); + assert(ik->in_aot_cache(), "expecting a shared class"); if (JvmtiExport::should_post_class_file_load_hook()) { ResourceMark rm(THREAD); // Post the CFLH diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 9bc94f15100..946fbc07f28 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1014,7 +1014,7 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name, bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, InstanceKlass* super_type, Handle class_loader, bool is_superclass, TRAPS) { - assert(super_type->is_shared(), "must be"); + assert(super_type->in_aot_cache(), "must be"); // Quick check if the super type has been already loaded. // + Don't do it for unregistered classes -- they can be unloaded so @@ -1077,7 +1077,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS) { assert(ik != nullptr, "sanity"); - assert(ik->is_shared(), "sanity"); + assert(ik->in_aot_cache(), "sanity"); assert(!ik->is_unshareable_info_restored(), "shared class can be restored only once"); assert(Atomic::add(&ik->_shared_class_load_count, 1) == 1, "shared class loaded more than once"); Symbol* class_name = ik->name(); @@ -1745,7 +1745,7 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name, klass2, loader_data2); #if INCLUDE_CDS if (CDSConfig::is_dumping_archive() && klass_being_linked != nullptr && - !klass_being_linked->is_shared()) { + !klass_being_linked->in_aot_cache()) { SystemDictionaryShared::record_linking_constraint(constraint_name, InstanceKlass::cast(klass_being_linked), class_loader1, class_loader2); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 904e8cca89d..7b52dfe46aa 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -205,7 +205,7 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { } bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(k)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(k)) { // We have reached a super type that's already in the base archive. Treat it // as "not excluded". return false; @@ -250,7 +250,7 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() - && k->is_shared()) { + && k->in_aot_cache()) { return false; // Do not exclude: unregistered classes are passed from preimage to final image. } @@ -483,7 +483,7 @@ InstanceKlass* SystemDictionaryShared::get_unregistered_class(Symbol* name) { void SystemDictionaryShared::copy_unregistered_class_size_and_crc32(InstanceKlass* klass) { precond(CDSConfig::is_dumping_final_static_archive()); - precond(klass->is_shared()); + precond(klass->in_aot_cache()); // A shared class must have a RunTimeClassInfo record const RunTimeClassInfo* record = find_record(&_static_archive._unregistered_dictionary, @@ -665,7 +665,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { } else { InstanceKlass* ik = InstanceKlass::cast(k); - if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->in_aot_cache()) { // ik is already part of the static archive, so it will never be considered as excluded. return false; } @@ -1018,7 +1018,7 @@ unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) { uintx offset = ArchiveBuilder::current()->any_to_offset(ptr); unsigned int hash = primitive_hash(offset); DEBUG_ONLY({ - if (MetaspaceObj::is_shared((const MetaspaceObj*)ptr)) { + if (MetaspaceObj::in_aot_cache((const MetaspaceObj*)ptr)) { assert(hash == SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr), "must be"); } }); @@ -1106,7 +1106,7 @@ void SystemDictionaryShared::serialize_vm_classes(SerializeClosure* soc) { const RunTimeClassInfo* SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTimeSharedDictionary* dynamic_dict, Symbol* name) { - if (!CDSConfig::is_using_archive() || !name->is_shared()) { + if (!CDSConfig::is_using_archive() || !name->in_aot_cache()) { // The names of all shared classes must also be a shared Symbol. return nullptr; } @@ -1124,7 +1124,7 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim } } - if (!MetaspaceShared::is_shared_dynamic(name)) { + if (!MetaspaceShared::in_aot_cache_dynamic_region(name)) { // The names of all shared classes in the static dict must also be in the // static archive record = static_dict->lookup(name, hash, 0); @@ -1163,7 +1163,7 @@ void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) { const char* SystemDictionaryShared::loader_type_for_shared_class(Klass* k) { assert(k != nullptr, "Sanity"); - assert(k->is_shared(), "Must be"); + assert(k->in_aot_cache(), "Must be"); assert(k->is_instance_klass(), "Must be"); InstanceKlass* ik = InstanceKlass::cast(k); if (ik->defined_by_boot_loader()) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index e3c22ee11a0..30b38a5aa59 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -127,7 +127,7 @@ class SharedClassLoadingMark { assert(THREAD != nullptr, "Current thread is nullptr"); assert(_klass != nullptr, "InstanceKlass is nullptr"); if (HAS_PENDING_EXCEPTION) { - if (_klass->is_shared()) { + if (_klass->in_aot_cache()) { _klass->set_shared_loading_failed(); } } @@ -297,7 +297,7 @@ public: template static unsigned int hash_for_shared_dictionary_quick(T* ptr) { - assert(MetaspaceObj::is_shared((const MetaspaceObj*)ptr), "must be"); + assert(MetaspaceObj::in_aot_cache((const MetaspaceObj*)ptr), "must be"); assert(ptr > (T*)SharedBaseAddress, "must be"); uintx offset = uintx(ptr) - uintx(SharedBaseAddress); return primitive_hash(offset); diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 4c0a40b837d..f6f5aa70fbd 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -140,7 +140,7 @@ static bool is_eligible_for_verification(InstanceKlass* klass, bool should_verif // Shared classes shouldn't have stackmaps either. // However, bytecodes for shared old classes can be verified because // they have not been rewritten. - !(klass->is_shared() && klass->is_rewritten())); + !(klass->in_aot_cache() && klass->is_rewritten())); } void Verifier::trace_class_resolution(Klass* resolve_class, InstanceKlass* verify_class) { diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index f51c17eb038..23bc054755a 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -138,7 +138,7 @@ void vmClasses::resolve_all(TRAPS) { ArchiveHeapLoader::fixup_region(); // Initialize the constant pool for the Object_class - assert(Object_klass()->is_shared(), "must be"); + assert(Object_klass()->in_aot_cache(), "must be"); Object_klass()->constants()->restore_unshareable_info(CHECK); resolve_through(VM_CLASS_ID(Class_klass), scan, CHECK); } else @@ -204,7 +204,7 @@ void vmClasses::resolve_all(TRAPS) { "All well known classes must be resolved in JVMTI early phase")); for (auto id : EnumRange{}) { InstanceKlass* k = _klasses[as_int(id)]; - assert(k->is_shared(), "must not be replaced by JVMTI class file load hook"); + assert(k->in_aot_cache(), "must not be replaced by JVMTI class file load hook"); } } #endif @@ -219,7 +219,7 @@ void vmClasses::resolve_all(TRAPS) { void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* loader_data, Handle domain, TRAPS) { assert(!Universe::is_fully_initialized(), "We can make short cuts only during VM initialization"); - assert(klass->is_shared(), "Must be shared class"); + assert(klass->in_aot_cache(), "Must be shared class"); if (klass->class_loader_data() != nullptr) { return; } diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 80223a4e5cb..5db6cb1b0cc 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -165,7 +165,7 @@ void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, JavaT void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, JavaThread* current) { assert(klass->is_initialized(), ""); - if (TrainingData::have_data() && klass->is_shared()) { + if (TrainingData::have_data() && klass->in_aot_cache()) { _training_replay_queue.push(klass, TrainingReplayQueue_lock, current); } } diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 50115f842e2..ae103c8a339 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -925,7 +925,7 @@ void InterpreterRuntime::cds_resolve_invoke(Bytecodes::Code bytecode, int method ResourceMark rm; InstanceKlass* resolved_iklass = InstanceKlass::cast(link_info.resolved_klass()); log_info(aot, resolve)("Not resolved: class not linked: %s %s %s", - resolved_iklass->is_shared() ? "is_shared" : "", + resolved_iklass->in_aot_cache() ? "in_aot_cache" : "", resolved_iklass->init_state_name(), resolved_iklass->external_name()); } diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index d64954b50bd..41a96eebfad 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -124,7 +124,7 @@ void Rewriter::make_constant_pool_cache(TRAPS) { THREAD); #if INCLUDE_CDS if (!HAS_PENDING_EXCEPTION && CDSConfig::is_dumping_archive()) { - if (_pool->pool_holder()->is_shared()) { + if (_pool->pool_holder()->in_aot_cache()) { assert(CDSConfig::is_dumping_dynamic_archive(), "must be"); // We are linking a shared class from the base archive. This // class won't be written into the dynamic archive, so there's no @@ -567,8 +567,8 @@ void Rewriter::rewrite_bytecodes(TRAPS) { void Rewriter::rewrite(InstanceKlass* klass, TRAPS) { #if INCLUDE_CDS - if (klass->is_shared()) { - assert(!klass->is_rewritten(), "rewritten shared classes cannot be rewritten again"); + if (klass->in_aot_cache()) { + assert(!klass->is_rewritten(), "rewritten classes in the AOT cache cannot be rewritten again"); } #endif // INCLUDE_CDS ResourceMark rm(THREAD); diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index a7c0045eac3..f158fefdba0 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -65,8 +65,8 @@ void FreeHeap(void* p) { os::free(p); } -void* MetaspaceObj::_shared_metaspace_base = nullptr; -void* MetaspaceObj::_shared_metaspace_top = nullptr; +void* MetaspaceObj::_aot_metaspace_base = nullptr; +void* MetaspaceObj::_aot_metaspace_top = nullptr; void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 9e500135d0b..35180fdba5e 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -261,43 +261,43 @@ class MetaspaceObj { // void deallocate_contents(ClassLoaderData* loader_data); friend class VMStructs; - // When CDS is enabled, all shared metaspace objects are mapped + // All metsapce objects in the AOT cache (CDS archive) are mapped // into a single contiguous memory block, so we can use these - // two pointers to quickly determine if something is in the - // shared metaspace. - // When CDS is not enabled, both pointers are set to null. - static void* _shared_metaspace_base; // (inclusive) low address - static void* _shared_metaspace_top; // (exclusive) high address + // two pointers to quickly determine if a MetaspaceObj is in the + // AOT cache. + // When AOT/CDS is not enabled, both pointers are set to null. + static void* _aot_metaspace_base; // (inclusive) low address + static void* _aot_metaspace_top; // (exclusive) high address public: // Returns true if the pointer points to a valid MetaspaceObj. A valid // MetaspaceObj is MetaWord-aligned and contained within either - // non-shared or shared metaspace. + // regular- or aot metaspace. static bool is_valid(const MetaspaceObj* p); #if INCLUDE_CDS - static bool is_shared(const MetaspaceObj* p) { - // If no shared metaspace regions are mapped, _shared_metaspace_{base,top} will + static bool in_aot_cache(const MetaspaceObj* p) { + // If no shared metaspace regions are mapped, _aot_metaspace_{base,top} will // both be null and all values of p will be rejected quickly. - return (((void*)p) < _shared_metaspace_top && - ((void*)p) >= _shared_metaspace_base); + return (((void*)p) < _aot_metaspace_top && + ((void*)p) >= _aot_metaspace_base); } - bool is_shared() const { return MetaspaceObj::is_shared(this); } + bool in_aot_cache() const { return MetaspaceObj::in_aot_cache(this); } #else - static bool is_shared(const MetaspaceObj* p) { return false; } - bool is_shared() const { return false; } + static bool in_aot_cache(const MetaspaceObj* p) { return false; } + bool in_aot_cache() const { return false; } #endif void print_address_on(outputStream* st) const; // nonvirtual address printing - static void set_shared_metaspace_range(void* base, void* top) { - _shared_metaspace_base = base; - _shared_metaspace_top = top; + static void set_aot_metaspace_range(void* base, void* top) { + _aot_metaspace_base = base; + _aot_metaspace_top = top; } - static void* shared_metaspace_base() { return _shared_metaspace_base; } - static void* shared_metaspace_top() { return _shared_metaspace_top; } + static void* aot_metaspace_base() { return _aot_metaspace_base; } + static void* aot_metaspace_top() { return _aot_metaspace_top; } #define METASPACE_OBJ_TYPES_DO(f) \ f(Class) \ diff --git a/src/hotspot/share/memory/metadataFactory.hpp b/src/hotspot/share/memory/metadataFactory.hpp index f2542069f04..6cc4fd97b0a 100644 --- a/src/hotspot/share/memory/metadataFactory.hpp +++ b/src/hotspot/share/memory/metadataFactory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ class MetadataFactory : AllStatic { static void free_array(ClassLoaderData* loader_data, Array* data) { if (data != nullptr) { assert(loader_data != nullptr, "shouldn't pass null"); - assert(!data->is_shared(), "cannot deallocate array in shared spaces"); + assert(!data->in_aot_cache(), "cannot deallocate array in aot metaspace spaces"); int size = data->size(); loader_data->metaspace_non_null()->deallocate((MetaWord*)data, size); } @@ -73,7 +73,7 @@ class MetadataFactory : AllStatic { int size = md->size(); // Call metadata's deallocate function which will deallocate fields and release_C_heap_structures assert(!md->on_stack(), "can't deallocate things on stack"); - assert(!md->is_shared(), "cannot deallocate if in shared spaces"); + assert(!md->in_aot_cache(), "cannot deallocate if in aot metaspace spaces"); md->deallocate_contents(loader_data); // Call the destructor. This is currently used for MethodData which has a member // that needs to be destructed to release resources. Most Metadata derived classes have noop diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 92b33443457..1983fbc870c 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1036,8 +1036,8 @@ void Metaspace::purge(bool classes_unloaded) { // Returns true if pointer points into one of the metaspace regions, or // into the class space. -bool Metaspace::is_in_shared_metaspace(const void* ptr) { - return MetaspaceShared::is_in_shared_metaspace(ptr); +bool Metaspace::in_aot_cache(const void* ptr) { + return MetaspaceShared::in_aot_cache(ptr); } // Returns true if pointer points into one of the non-class-space metaspace regions. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index 293782c0d75..b2c3c29a812 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -130,7 +130,7 @@ public: // Returns true if the pointer points into class space, non-class metaspace, or the // metadata portion of the CDS archive. static bool contains(const void* ptr) { - return is_in_shared_metaspace(ptr) || // in cds + return in_aot_cache(ptr) || // in cds is_in_class_space(ptr) || // in class space is_in_nonclass_metaspace(ptr); // in one of the non-class regions? } @@ -142,7 +142,7 @@ public: } // Returns true if pointer points into the CDS klass region. - static bool is_in_shared_metaspace(const void* ptr); + static bool in_aot_cache(const void* ptr); // Returns true if pointer points into one of the non-class-space metaspace regions. static bool is_in_nonclass_metaspace(const void* ptr); diff --git a/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp b/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp index d366038ceb1..2d1877a1ed1 100644 --- a/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp +++ b/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp @@ -63,7 +63,7 @@ public: CountKlassClosure() : _num_classes(0), _num_classes_shared(0) {} void do_klass(Klass* k) { _num_classes++; - if (k->is_shared()) { + if (k->in_aot_cache()) { _num_classes_shared++; } } diff --git a/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp b/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp index d0d68203759..75fc02df38f 100644 --- a/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp +++ b/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp @@ -39,8 +39,8 @@ void PrintMetaspaceInfoKlassClosure::do_klass(Klass* k) { _out->cr(); _out->print("%4zu: ", _cnt); - // Print a 's' for shared classes - _out->put(k->is_shared() ? 's': ' '); + // Print a 's' for classes in the aot metaspace (used to be called shared classes) + _out->put(k->in_aot_cache() ? 's': ' '); ResourceMark rm; _out->print(" %s", k->external_name()); diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 73e3a5e4c15..198ff1ef75e 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -259,9 +259,9 @@ void ArrayKlass::log_array_class_load(Klass* k) { LogStream ls(lt); ResourceMark rm; ls.print("%s", k->name()->as_klass_external_name()); - if (MetaspaceShared::is_shared_dynamic((void*)k)) { + if (MetaspaceShared::in_aot_cache_dynamic_region((void*)k)) { ls.print(" source: shared objects file (top)"); - } else if (MetaspaceShared::is_shared_static((void*)k)) { + } else if (MetaspaceShared::in_aot_cache_static_region((void*)k)) { ls.print(" source: shared objects file"); } ls.cr(); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 3223c56628e..735968f7a95 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -383,8 +383,8 @@ void ConstantPool::restore_unshareable_info(TRAPS) { return; } assert(is_constantPool(), "ensure C++ vtable is restored"); - assert(on_stack(), "should always be set for shared constant pools"); - assert(is_shared(), "should always be set for shared constant pools"); + assert(on_stack(), "should always be set for constant pools in AOT cache"); + assert(in_aot_cache(), "should always be set for constant pools in AOT cache"); if (is_for_method_handle_intrinsic()) { // See the same check in remove_unshareable_info() below. assert(cache() == nullptr, "must not have cpCache"); @@ -428,11 +428,11 @@ void ConstantPool::restore_unshareable_info(TRAPS) { } void ConstantPool::remove_unshareable_info() { - // Shared ConstantPools are in the RO region, so the _flags cannot be modified. + // ConstantPools in AOT cache are in the RO region, so the _flags cannot be modified. // The _on_stack flag is used to prevent ConstantPools from deallocation during - // class redefinition. Since shared ConstantPools cannot be deallocated anyway, + // class redefinition. Since such ConstantPools cannot be deallocated anyway, // we always set _on_stack to true to avoid having to change _flags during runtime. - _flags |= (_on_stack | _is_shared); + _flags |= (_on_stack | _in_aot_cache); if (is_for_method_handle_intrinsic()) { // This CP was created by Method::make_method_handle_intrinsic() and has nothing @@ -2258,13 +2258,13 @@ void ConstantPool::set_on_stack(const bool value) { if (value) { // Only record if it's not already set. if (!on_stack()) { - assert(!is_shared(), "should always be set for shared constant pools"); + assert(!in_aot_cache(), "should always be set for constant pools in AOT cache"); _flags |= _on_stack; MetadataOnStackMark::record(this); } } else { // Clearing is done single-threadedly. - if (!is_shared()) { + if (!in_aot_cache()) { _flags &= (u2)(~_on_stack); } } diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 8999acf4d3a..9cbeb1245be 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -145,7 +145,7 @@ class ConstantPool : public Metadata { enum { _has_preresolution = 1, // Flags _on_stack = 2, - _is_shared = 4, + _in_aot_cache = 4, _has_dynamic_constant = 8, _is_for_method_handle_intrinsic = 16 }; @@ -212,7 +212,7 @@ class ConstantPool : public Metadata { bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } void set_has_preresolution() { - assert(!is_shared(), "should never be called on shared ConstantPools"); + assert(!in_aot_cache(), "should never be called on ConstantPools in AOT cache"); _flags |= _has_preresolution; } @@ -248,8 +248,8 @@ class ConstantPool : public Metadata { bool is_maybe_on_stack() const; void set_on_stack(const bool value); - // Faster than MetaspaceObj::is_shared() - used by set_on_stack() - bool is_shared() const { return (_flags & _is_shared) != 0; } + // Shadows MetaspaceObj::in_aot_cache(). It's faster and is used by set_on_stack() + bool in_aot_cache() const { return (_flags & _in_aot_cache) != 0; } bool has_dynamic_constant() const { return (_flags & _has_dynamic_constant) != 0; } void set_has_dynamic_constant() { _flags |= _has_dynamic_constant; } diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index a56e3453970..8944f85af0d 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -584,7 +584,7 @@ bool ConstantPoolCache::can_archive_resolved_method(ConstantPool* src_cp, Resolv #endif // INCLUDE_CDS void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) { - assert(!is_shared(), "shared caches are not deallocated"); + assert(!in_aot_cache(), "objects in aot metaspace are not deallocated"); data->remove_handle(_resolved_references); set_resolved_references(OopHandle()); MetadataFactory::free_array(data, _reference_map); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 964006b3b9c..568ccd72176 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -561,7 +561,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, Array* methods) { if (methods != nullptr && methods != Universe::the_empty_method_array() && - !methods->is_shared()) { + !methods->in_aot_cache()) { for (int i = 0; i < methods->length(); i++) { Method* method = methods->at(i); if (method == nullptr) continue; // maybe null if error processing @@ -585,21 +585,21 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, // check that the interfaces don't come from super class Array* sti = (super_klass == nullptr) ? nullptr : super_klass->transitive_interfaces(); - if (ti != sti && ti != nullptr && !ti->is_shared()) { + if (ti != sti && ti != nullptr && !ti->in_aot_cache()) { MetadataFactory::free_array(loader_data, ti); } } // local interfaces can be empty if (local_interfaces != Universe::the_empty_instance_klass_array() && - local_interfaces != nullptr && !local_interfaces->is_shared()) { + local_interfaces != nullptr && !local_interfaces->in_aot_cache()) { MetadataFactory::free_array(loader_data, local_interfaces); } } void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data, Array* record_components) { - if (record_components != nullptr && !record_components->is_shared()) { + if (record_components != nullptr && !record_components->in_aot_cache()) { for (int i = 0; i < record_components->length(); i++) { RecordComponent* record_component = record_components->at(i); MetadataFactory::free_metadata(loader_data, record_component); @@ -643,7 +643,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { if (method_ordering() != nullptr && method_ordering() != Universe::the_empty_int_array() && - !method_ordering()->is_shared()) { + !method_ordering()->in_aot_cache()) { MetadataFactory::free_array(loader_data, method_ordering()); } set_method_ordering(nullptr); @@ -651,7 +651,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // default methods can be empty if (default_methods() != nullptr && default_methods() != Universe::the_empty_method_array() && - !default_methods()->is_shared()) { + !default_methods()->in_aot_cache()) { MetadataFactory::free_array(loader_data, default_methods()); } // Do NOT deallocate the default methods, they are owned by superinterfaces. @@ -659,7 +659,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // default methods vtable indices can be empty if (default_vtable_indices() != nullptr && - !default_vtable_indices()->is_shared()) { + !default_vtable_indices()->in_aot_cache()) { MetadataFactory::free_array(loader_data, default_vtable_indices()); } set_default_vtable_indices(nullptr); @@ -672,7 +672,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { secondary_supers() != Universe::the_empty_klass_array() && // see comments in compute_secondary_supers about the following cast (address)(secondary_supers()) != (address)(transitive_interfaces()) && - !secondary_supers()->is_shared()) { + !secondary_supers()->in_aot_cache()) { MetadataFactory::free_array(loader_data, secondary_supers()); } set_secondary_supers(nullptr, SECONDARY_SUPERS_BITMAP_EMPTY); @@ -681,17 +681,17 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); - if (fieldinfo_stream() != nullptr && !fieldinfo_stream()->is_shared()) { + if (fieldinfo_stream() != nullptr && !fieldinfo_stream()->in_aot_cache()) { MetadataFactory::free_array(loader_data, fieldinfo_stream()); } set_fieldinfo_stream(nullptr); - if (fieldinfo_search_table() != nullptr && !fieldinfo_search_table()->is_shared()) { + if (fieldinfo_search_table() != nullptr && !fieldinfo_search_table()->in_aot_cache()) { MetadataFactory::free_array(loader_data, fieldinfo_search_table()); } set_fieldinfo_search_table(nullptr); - if (fields_status() != nullptr && !fields_status()->is_shared()) { + if (fields_status() != nullptr && !fields_status()->in_aot_cache()) { MetadataFactory::free_array(loader_data, fields_status()); } set_fields_status(nullptr); @@ -700,7 +700,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // delete it, yet. The new class's previous version will point to this. if (constants() != nullptr) { assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - if (!constants()->is_shared()) { + if (!constants()->in_aot_cache()) { MetadataFactory::free_metadata(loader_data, constants()); } // Delete any cached resolution errors for the constant pool @@ -711,27 +711,27 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { if (inner_classes() != nullptr && inner_classes() != Universe::the_empty_short_array() && - !inner_classes()->is_shared()) { + !inner_classes()->in_aot_cache()) { MetadataFactory::free_array(loader_data, inner_classes()); } set_inner_classes(nullptr); if (nest_members() != nullptr && nest_members() != Universe::the_empty_short_array() && - !nest_members()->is_shared()) { + !nest_members()->in_aot_cache()) { MetadataFactory::free_array(loader_data, nest_members()); } set_nest_members(nullptr); if (permitted_subclasses() != nullptr && permitted_subclasses() != Universe::the_empty_short_array() && - !permitted_subclasses()->is_shared()) { + !permitted_subclasses()->in_aot_cache()) { MetadataFactory::free_array(loader_data, permitted_subclasses()); } set_permitted_subclasses(nullptr); // We should deallocate the Annotations instance if it's not in shared spaces. - if (annotations() != nullptr && !annotations()->is_shared()) { + if (annotations() != nullptr && !annotations()->in_aot_cache()) { MetadataFactory::free_metadata(loader_data, annotations()); } set_annotations(nullptr); @@ -994,7 +994,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { if (!is_linked()) { if (!is_rewritten()) { - if (is_shared()) { + if (in_aot_cache()) { assert(!verified_at_dump_time(), "must be"); } { @@ -1013,7 +1013,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { // also sets rewritten rewrite_class(CHECK_false); - } else if (is_shared()) { + } else if (in_aot_cache()) { SystemDictionaryShared::check_verification_constraints(this, CHECK_false); } @@ -1031,7 +1031,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { // 2) the class is loaded by built-in class loader but failed to add archived loader constraints or // 3) the class was not verified during dump time bool need_init_table = true; - if (is_shared() && verified_at_dump_time() && + if (in_aot_cache() && verified_at_dump_time() && SystemDictionaryShared::check_linking_constraints(THREAD, this)) { need_init_table = false; } @@ -1073,7 +1073,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { void InstanceKlass::rewrite_class(TRAPS) { assert(is_loaded(), "must be loaded"); if (is_rewritten()) { - assert(is_shared(), "rewriting an unshared class?"); + assert(in_aot_cache(), "rewriting an unshared class?"); return; } Rewriter::rewrite(this, CHECK); @@ -1685,7 +1685,7 @@ void InstanceKlass::call_class_initializer(TRAPS) { AOTClassInitializer::call_runtime_setup(THREAD, this); return; } else if (has_archived_enum_objs()) { - assert(is_shared(), "must be"); + assert(in_aot_cache(), "must be"); bool initialized = CDSEnumKlass::initialize_enum_klass(this, CHECK); if (initialized) { return; @@ -2330,7 +2330,7 @@ void PrintClassClosure::do_klass(Klass* k) { if (ik->is_rewritten()) buf[i++] = 'W'; if (ik->is_contended()) buf[i++] = 'C'; if (ik->has_been_redefined()) buf[i++] = 'R'; - if (ik->is_shared()) buf[i++] = 'S'; + if (ik->in_aot_cache()) buf[i++] = 'S'; } buf[i++] = '\0'; _st->print("%-7s ", buf); @@ -2763,7 +2763,7 @@ void InstanceKlass::init_shared_package_entry() { } } else if (CDSConfig::is_dumping_dynamic_archive() && CDSConfig::is_using_full_module_graph() && - MetaspaceShared::is_in_shared_metaspace(_package_entry)) { + MetaspaceShared::in_aot_cache(_package_entry)) { // _package_entry is an archived package in the base archive. Leave it as is. } else { _package_entry = nullptr; @@ -2845,7 +2845,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl // retrieved during dump time. // Verification of archived old classes will be performed during run time. bool InstanceKlass::can_be_verified_at_dumptime() const { - if (MetaspaceShared::is_in_shared_metaspace(this)) { + if (MetaspaceShared::in_aot_cache(this)) { // This is a class that was dumped into the base archive, so we know // it was verified at dump time. return true; @@ -3081,14 +3081,14 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, PackageEntry* pkg_ // ensure java/ packages only loaded by boot or platform builtin loaders // not needed for shared class since CDS does not archive prohibited classes. - if (!is_shared()) { + if (!in_aot_cache()) { check_prohibited_package(name(), loader_data, CHECK); } - if (is_shared() && _package_entry != nullptr) { + if (in_aot_cache() && _package_entry != nullptr) { if (CDSConfig::is_using_full_module_graph() && _package_entry == pkg_entry) { // we can use the saved package - assert(MetaspaceShared::is_in_shared_metaspace(_package_entry), "must be"); + assert(MetaspaceShared::in_aot_cache(_package_entry), "must be"); return; } else { _package_entry = nullptr; @@ -3970,8 +3970,8 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, info_stream.print(" source: %s", class_loader->klass()->external_name()); } } else { - assert(this->is_shared(), "must be"); - if (MetaspaceShared::is_shared_dynamic((void*)this)) { + assert(this->in_aot_cache(), "must be"); + if (MetaspaceShared::in_aot_cache_dynamic_region((void*)this)) { info_stream.print(" source: shared objects file (top)"); } else { info_stream.print(" source: shared objects file"); @@ -4254,7 +4254,7 @@ void JNIid::verify(InstanceKlass* holder) { void InstanceKlass::set_init_state(ClassState state) { #ifdef ASSERT - bool good_state = is_shared() ? (_init_state <= state) + bool good_state = in_aot_cache() ? (_init_state <= state) : (_init_state < state); assert(good_state || state == allocated, "illegal state transition"); #endif @@ -4355,7 +4355,7 @@ void InstanceKlass::purge_previous_version_list() { assert(pvcp->pool_holder() != nullptr, "Constant pool with no holder"); guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack"); live_count++; - if (pvcp->is_shared()) { + if (pvcp->in_aot_cache()) { // Shared previous versions can never be removed so no cleaning is needed. log_trace(redefine, class, iklass, purge)("previous version " PTR_FORMAT " is shared", p2i(pv_node)); } else { @@ -4467,7 +4467,7 @@ void InstanceKlass::add_previous_version(InstanceKlass* scratch_class, assert(scratch_class->previous_versions() == nullptr, "shouldn't have a previous version"); scratch_class->link_previous_versions(previous_versions()); link_previous_versions(scratch_class); - if (cp_ref->is_shared()) { + if (cp_ref->in_aot_cache()) { log_trace(redefine, class, iklass, add) ("scratch class added; class is shared"); } else { // We only set clean_previous_versions flag for processing during class diff --git a/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp b/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp index eed87d2644b..4014c752e04 100644 --- a/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp +++ b/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ void InstanceMirrorKlass::do_metadata(oop obj, OopClosureType* closure) { if (klass != nullptr) { if (klass->class_loader_data() == nullptr) { // This is a mirror that belongs to a shared class that has not been loaded yet. - assert(klass->is_shared(), "Must be"); + assert(klass->in_aot_cache(), "Must be"); } else if (klass->is_instance_klass() && klass->class_loader_data()->has_class_mirror_holder()) { // A non-strong hidden class doesn't have its own class loader, // so when handling the java mirror for the class we need to make sure its class diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 17e2ccbc911..f4ae128aef7 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -805,7 +805,7 @@ void Klass::remove_unshareable_info() { // Null out class_loader_data because we don't share that yet. set_class_loader_data(nullptr); - set_is_shared(); + set_in_aot_cache(); if (CDSConfig::is_dumping_classic_static_archive()) { // "Classic" static archives are required to have deterministic contents. @@ -858,7 +858,7 @@ void Klass::remove_java_mirror() { void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { assert(is_klass(), "ensure C++ vtable is restored"); - assert(is_shared(), "must be set"); + assert(in_aot_cache(), "must be set"); assert(secondary_supers()->length() >= (int)population_count(_secondary_supers_bitmap), "must be"); JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, aot, unshareable)) { diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 91bd60b0e3e..d62f3f21ee2 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -174,9 +174,9 @@ private: #if INCLUDE_CDS // Various attributes for shared classes. Should be zero for a non-shared class. - u2 _shared_class_flags; + u2 _shared_class_flags; enum CDSSharedClassFlags { - _is_shared_class = 1 << 0, // shadows MetaspaceObj::is_shared + _in_aot_cache = 1 << 0, _archived_lambda_proxy_is_available = 1 << 1, _has_value_based_class_annotation = 1 << 2, _verified_at_dump_time = 1 << 3, @@ -378,13 +378,13 @@ protected: NOT_CDS(return false;) } - bool is_shared() const { // shadows MetaspaceObj::is_shared)() - CDS_ONLY(return (_shared_class_flags & _is_shared_class) != 0;) + bool in_aot_cache() const { // shadows MetaspaceObj::in_aot_cache)() + CDS_ONLY(return (_shared_class_flags & _in_aot_cache) != 0;) NOT_CDS(return false;) } - void set_is_shared() { - CDS_ONLY(_shared_class_flags |= _is_shared_class;) + void set_in_aot_cache() { + CDS_ONLY(_shared_class_flags |= _in_aot_cache;) } // Obtain the module or package for this class @@ -610,7 +610,7 @@ public: virtual void remove_java_mirror(); bool is_unshareable_info_restored() const { - assert(is_shared(), "use this for shared classes only"); + assert(in_aot_cache(), "use this for shared classes only"); if (has_archived_mirror_index()) { // _java_mirror is not a valid OopHandle but rather an encoded reference in the shared heap return false; diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index 55242b2a2d1..ce4e322930f 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -50,7 +50,7 @@ inline InstanceKlass* klassVtable::ik() const { } bool klassVtable::is_preinitialized_vtable() { - return _klass->is_shared() && !MetaspaceShared::remapped_readwrite() && _klass->verified_at_dump_time(); + return _klass->in_aot_cache() && !MetaspaceShared::remapped_readwrite() && _klass->verified_at_dump_time(); } @@ -163,7 +163,7 @@ void klassVtable::initialize_vtable(GrowableArray* supers) { // Note: Arrays can have intermediate array supers. Use java_super to skip them. InstanceKlass* super = _klass->java_super(); - bool is_shared = _klass->is_shared(); + bool in_aot_cache = _klass->in_aot_cache(); Thread* current = Thread::current(); if (!_klass->is_array_klass()) { @@ -178,7 +178,7 @@ void klassVtable::initialize_vtable(GrowableArray* supers) { #endif if (Universe::is_bootstrapping()) { - assert(!is_shared, "sanity"); + assert(!in_aot_cache, "sanity"); // just clear everything for (int i = 0; i < _length; i++) table()[i].clear(); return; @@ -1089,7 +1089,7 @@ void itableMethodEntry::initialize(InstanceKlass* klass, Method* m) { if (m == nullptr) return; #ifdef ASSERT - if (MetaspaceShared::is_in_shared_metaspace((void*)&_method) && + if (MetaspaceShared::in_aot_cache((void*)&_method) && !MetaspaceShared::remapped_readwrite() && m->method_holder()->verified_at_dump_time() && klass->verified_at_dump_time()) { @@ -1275,7 +1275,7 @@ int klassItable::assign_itable_indices_for_interface(InstanceKlass* klass) { // A shared method could have an initialized itable_index that // is < 0. assert(m->vtable_index() == Method::pending_itable_index || - m->is_shared(), + m->in_aot_cache(), "set by initialize_vtable"); m->set_itable_index(ime_num); // Progress to next itable entry diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 40c44e07e37..03330aee209 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -446,7 +446,7 @@ void Method::restore_unshareable_info(TRAPS) { #endif void Method::set_vtable_index(int index) { - if (is_shared() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_vtable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. @@ -457,7 +457,7 @@ void Method::set_vtable_index(int index) { } void Method::set_itable_index(int index) { - if (is_shared() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_itable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. The dumptime @@ -1251,7 +1251,7 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { // If the code cache is full, we may reenter this function for the // leftover methods that weren't linked. if (adapter() != nullptr) { - if (adapter()->is_shared()) { + if (adapter()->in_aot_cache()) { assert(adapter()->is_linked(), "Adapter is shared but not linked"); } else { return; @@ -2175,7 +2175,7 @@ bool Method::is_valid_method(const Method* m) { return false; } else if (!os::is_readable_range(m, m + 1)) { return false; - } else if (m->is_shared()) { + } else if (m->in_aot_cache()) { return CppVtables::is_valid_shared_method(m); } else if (Metaspace::contains_non_shared(m)) { return has_method_vptr((const void*)m); diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 4797eed0a31..49153b3e931 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -705,7 +705,7 @@ void TrainingData::metaspace_pointers_do(MetaspaceClosure* iter) { } bool TrainingData::Key::can_compute_cds_hash(const Key* const& k) { - return k->meta() == nullptr || MetaspaceObj::is_shared(k->meta()); + return k->meta() == nullptr || MetaspaceObj::in_aot_cache(k->meta()); } uint TrainingData::Key::cds_hash(const Key* const& k) { diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 0d705c84f82..511f9efdfb9 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3422,7 +3422,7 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); - if (!caller_ik->is_shared()) { + if (!caller_ik->in_aot_cache()) { // there won't be a shared lambda class if the caller_ik is not in the shared archive. return nullptr; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a22cb9d51ce..63920583e18 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2154,7 +2154,7 @@ WB_ENTRY(jboolean, WB_IsSharedInternedString(JNIEnv* env, jobject wb, jobject st WB_END WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) - return (jboolean)MetaspaceShared::is_in_shared_metaspace(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + return (jboolean)MetaspaceShared::in_aot_cache(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); WB_END WB_ENTRY(jboolean, WB_AreSharedStringsMapped(JNIEnv* env)) diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index dc25fec9de7..4d3f1327d43 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2737,7 +2737,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth if (entry != nullptr) { assert(entry->is_linked(), "AdapterHandlerEntry must have been linked"); #ifdef ASSERT - if (!entry->is_shared() && VerifyAdapterSharing) { + if (!entry->in_aot_cache() && VerifyAdapterSharing) { verify_adapter_sharing(total_args_passed, sig_bt, entry); } #endif diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 3575ef70d19..1fba55cde99 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -347,8 +347,8 @@ /* Memory */ \ /**********/ \ \ - static_field(MetaspaceObj, _shared_metaspace_base, void*) \ - static_field(MetaspaceObj, _shared_metaspace_top, void*) \ + static_field(MetaspaceObj, _aot_metaspace_base, void*) \ + static_field(MetaspaceObj, _aot_metaspace_top, void*) \ nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java index 6550ca32d65..aab0281ef82 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +32,8 @@ import sun.jvm.hotspot.utilities.Observable; import sun.jvm.hotspot.utilities.Observer; public class MetaspaceObj { - private static Address sharedMetaspaceBaseAddr; - private static Address sharedMetaspaceTopAddr; + private static Address aotMetaspaceBaseAddr; + private static Address aotMetaspaceTopAddr; static { VM.registerVMInitializedObserver(new Observer() { @@ -45,13 +45,13 @@ public class MetaspaceObj { private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("MetaspaceObj"); - sharedMetaspaceBaseAddr = type.getAddressField("_shared_metaspace_base").getStaticFieldAddress(); - sharedMetaspaceTopAddr = type.getAddressField("_shared_metaspace_top").getStaticFieldAddress(); + aotMetaspaceBaseAddr = type.getAddressField("_aot_metaspace_base").getStaticFieldAddress(); + aotMetaspaceTopAddr = type.getAddressField("_aot_metaspace_top").getStaticFieldAddress(); } public static boolean isShared(Address addr) { - Address base = sharedMetaspaceBaseAddr.getAddressAt(0); - Address top = sharedMetaspaceTopAddr. getAddressAt(0); + Address base = aotMetaspaceBaseAddr.getAddressAt(0); + Address top = aotMetaspaceTopAddr. getAddressAt(0); return base.lessThanOrEqual(addr) && addr.lessThan(top); } From 62bc7b7c4247a62c23ea93cd960c3c0434925c49 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 4 Sep 2025 05:42:18 +0000 Subject: [PATCH 123/295] 8300080: offset_of for GCC/Clang exhibits undefined behavior and is not always a compile-time constant Reviewed-by: stefank, jsjolen --- make/hotspot/lib/CompileJvm.gmk | 4 +++- .../share/utilities/globalDefinitions.hpp | 3 +++ .../share/utilities/globalDefinitions_gcc.hpp | 18 ------------------ .../utilities/globalDefinitions_visCPP.hpp | 2 -- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 6b5edc85b23..bf92c50576a 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -97,11 +97,13 @@ CFLAGS_VM_VERSION := \ DISABLED_WARNINGS_gcc := array-bounds comment delete-non-virtual-dtor \ empty-body format-zero-length implicit-fallthrough int-in-bool-context \ + invalid-offsetof \ maybe-uninitialized missing-field-initializers \ shift-negative-value unknown-pragmas unused-but-set-variable \ unused-local-typedefs unused-variable -DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor missing-braces \ +DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor \ + invalid-offsetof missing-braces \ sometimes-uninitialized unknown-pragmas unused-but-set-variable \ unused-function unused-local-typedef unused-private-field unused-variable diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 1ef548d6510..64ccae539a3 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -85,6 +85,9 @@ class oopDesc; // they cannot be defined and potential callers will fail to compile. #define NONCOPYABLE(C) C(C const&) = delete; C& operator=(C const&) = delete /* next token must be ; */ +// offset_of was a workaround for UB with offsetof uses that are no longer an +// issue. This can be removed once all uses have been converted. +#define offset_of(klass, field) offsetof(klass, field) //---------------------------------------------------------------------------------------------------- // Printf-style formatters for fixed- and variable-width types as pointers and diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp index 41b7868f8c7..f82f9b1386a 100644 --- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -84,24 +84,6 @@ inline int g_isnan(double f) { return isnan(f); } inline int g_isfinite(jfloat f) { return isfinite(f); } inline int g_isfinite(jdouble f) { return isfinite(f); } - -// gcc warns about applying offsetof() to non-POD object or calculating -// offset directly when base address is null. The -Wno-invalid-offsetof -// option could be used to suppress this warning, but we instead just -// avoid the use of offsetof(). -// -// FIXME: This macro is complex and rather arcane. Perhaps we should -// use offsetof() instead, with the invalid-offsetof warning -// temporarily disabled. -#define offset_of(klass,field) \ -([]() { \ - alignas(16) char space[sizeof (klass)]; \ - klass* dummyObj = (klass*)space; \ - char* c = (char*)(void*)&dummyObj->field; \ - return (size_t)(c - space); \ -}()) - - #if defined(_LP64) && defined(__APPLE__) #define JLONG_FORMAT "%ld" #define JLONG_FORMAT_W(width) "%" #width "ld" diff --git a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp index 536b79165ae..b9d25096cd5 100644 --- a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp @@ -85,8 +85,6 @@ inline int g_isnan(jdouble f) { return _isnan(f); } inline int g_isfinite(jfloat f) { return _finite(f); } inline int g_isfinite(jdouble f) { return _finite(f); } -#define offset_of(klass,field) offsetof(klass,field) - #define THREAD_LOCAL __declspec(thread) // Inlining support From a03302d41bb9971736d4d56381ca0cad1eb3e34b Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Thu, 4 Sep 2025 06:33:57 +0000 Subject: [PATCH 124/295] 8366434: THP not working properly with G1 after JDK-8345655 Co-authored-by: Stefan Karlsson Co-authored-by: Stefan Johansson Reviewed-by: stefank, shade --- src/hotspot/share/memory/memoryReserver.cpp | 5 +- src/hotspot/share/memory/memoryReserver.hpp | 1 + .../gc/TestTransparentHugePagesHeap.java | 152 ++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index a6c1be5b33c..11a0422f7b0 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -110,12 +110,13 @@ static char* reserve_memory_inner(char* requested_address, ReservedSpace MemoryReserver::reserve_memory(char* requested_address, size_t size, size_t alignment, + size_t page_size, bool exec, MemTag mem_tag) { char* base = reserve_memory_inner(requested_address, size, alignment, exec, mem_tag); if (base != nullptr) { - return ReservedSpace(base, size, alignment, os::vm_page_size(), exec, false /* special */); + return ReservedSpace(base, size, alignment, page_size, exec, false /* special */); } // Failed @@ -188,7 +189,7 @@ ReservedSpace MemoryReserver::reserve(char* requested_address, } // == Case 3 == - return reserve_memory(requested_address, size, alignment, executable, mem_tag); + return reserve_memory(requested_address, size, alignment, page_size, executable, mem_tag); } ReservedSpace MemoryReserver::reserve(char* requested_address, diff --git a/src/hotspot/share/memory/memoryReserver.hpp b/src/hotspot/share/memory/memoryReserver.hpp index f8f642cca95..fd052e5e283 100644 --- a/src/hotspot/share/memory/memoryReserver.hpp +++ b/src/hotspot/share/memory/memoryReserver.hpp @@ -34,6 +34,7 @@ class MemoryReserver : AllStatic { static ReservedSpace reserve_memory(char* requested_address, size_t size, size_t alignment, + size_t page_size, bool exec, MemTag mem_tag); diff --git a/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java new file mode 100644 index 00000000000..25044d2c3e4 --- /dev/null +++ b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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=G1 + * @summary Run tests with G1 + * @library /test/lib + * @build jdk.test.lib.Platform + * @requires os.family == "linux" + * @requires vm.gc.G1 + * @run driver TestTransparentHugePagesHeap G1 +*/ +/* + * @test id=Parallel + * @summary Run tests with Parallel + * @library /test/lib + * @build jdk.test.lib.Platform + * @requires os.family == "linux" + * @requires vm.gc.Parallel + * @run driver TestTransparentHugePagesHeap Parallel +*/ +/* + * @test id=Serial + * @summary Run tests with Serial + * @library /test/lib + * @build jdk.test.lib.Platform + * @requires os.family == "linux" + * @requires vm.gc.Serial + * @run driver TestTransparentHugePagesHeap Serial +*/ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Scanner; + +import jdk.test.lib.os.linux.HugePageConfiguration; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; + +import jtreg.SkippedException; + +// We verify that the heap can be backed by THP by looking at the +// THPeligible field for the heap section in /proc/self/smaps. This +// field indicates if a mapping can use THP. +// THP mode 'always': this field is 1 whenever huge pages can be used +// THP mode 'madvise': this field is 1 if the mapping has been madvised +// as MADV_HUGEPAGE. In the JVM that should happen when the flag +// -XX:+UseTransparentHugePages is specified. +// +// Note: we don't verify if the heap is backed by huge pages because we +// can't know if the underlying system have any available. +public class TestTransparentHugePagesHeap { + + public static void main(String args[]) throws Exception { + // To be able to detect large page use (esp. THP) somewhat reliably, we + // need at least kernel 3.8 to get the "VmFlags" tag in smaps. + // (Note: its still good we started the VM at least since this serves as a nice + // test for all manners of large page options). + if (Platform.getOsVersionMajor() < 3 || + (Platform.getOsVersionMajor() == 3 && Platform.getOsVersionMinor() < 8)) { + throw new SkippedException("Kernel older than 3.8 - skipping this test."); + } + + final HugePageConfiguration hugePageConfiguration = HugePageConfiguration.readFromOS(); + if (!hugePageConfiguration.supportsTHP()) { + throw new SkippedException("THP is turned off"); + } + + OutputAnalyzer oa = ProcessTools.executeTestJava("-XX:+Use" + args[0] + "GC", "-Xmx128m", "-Xms128m", "-Xlog:pagesize:thp-%p.log", "-XX:+UseTransparentHugePages", VerifyTHPEnabledForHeap.class.getName()); + oa.shouldHaveExitValue(0); + } + + class VerifyTHPEnabledForHeap { + + public static void main(String args[]) throws Exception { + String heapAddress = readHeapAddressInLog(); + Path smaps = makeSmapsCopy(); + + final Pattern heapSection = Pattern.compile("^" + heapAddress + ".*"); + final Pattern thpEligible = Pattern.compile("THPeligible:\\s+(\\d)\\s*"); + + Scanner smapsFile = new Scanner(smaps); + while (smapsFile.hasNextLine()) { + Matcher heapMatcher = heapSection.matcher(smapsFile.nextLine()); + + if (heapMatcher.matches()) { + // Found the first heap section, verify that it is THP eligible + while (smapsFile.hasNextLine()) { + Matcher m = thpEligible.matcher(smapsFile.nextLine()); + if (m.matches()) { + if (Integer.parseInt(m.group(1)) == 1) { + // THPeligible is 1, heap can be backed by huge pages + return; + } + + throw new RuntimeException("First heap section at 0x" + heapAddress + " is not THPeligible"); + } + } + } + } + + // Failed to verify THP for heap + throw new RuntimeException("Could not find heap section in smaps file"); + } + + private static String readHeapAddressInLog() throws Exception { + final Pattern heapAddress = Pattern.compile(".* Heap: .*base=(0x[0-9A-Fa-f]*).*"); + + Scanner logFile = new Scanner(Paths.get("thp-" + ProcessHandle.current().pid() + ".log")); + while (logFile.hasNextLine()) { + Matcher m = heapAddress.matcher(logFile.nextLine()); + if (m.matches()) { + return Long.toHexString(Long.decode(m.group(1))); + } + } + throw new RuntimeException("Failed to parse heap address, failing test"); + } + + private static Path makeSmapsCopy() throws Exception { + Path src = Paths.get("/proc/self/smaps"); + Path dest = Paths.get("smaps-copy-" + ProcessHandle.current().pid() + ".txt"); + Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING); + return dest; + } + } +} + From 2527e9e58d770c50e6d807bf1483c6bb07dd3de7 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 4 Sep 2025 06:53:35 +0000 Subject: [PATCH 125/295] 8366490: C2 SuperWord: wrong result because CastP2X is missing ctrl and floats over SafePoint creating stale oops Reviewed-by: thartmann, chagedorn, mhaessig --- src/hotspot/share/opto/vectorization.cpp | 19 ++- src/hotspot/share/opto/vectorization.hpp | 4 +- src/hotspot/share/opto/vtransform.cpp | 19 ++- src/hotspot/share/opto/vtransform.hpp | 4 +- .../superword/TestAliasingCastP2XCtrl.java | 118 ++++++++++++++++++ 5 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index cd5aba6c31d..8e0f0980ff7 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -934,7 +934,7 @@ BoolNode* make_a_plus_b_leq_c(Node* a, Node* b, Node* c, PhaseIdealLoop* phase) return bol; } -BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) const { +BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, Node* ctrl) const { // Ensure iv_scale1 <= iv_scale2. const VPointer& vp1 = (this->iv_scale() <= other.iv_scale()) ? *this : other; const VPointer& vp2 = (this->iv_scale() <= other.iv_scale()) ? other :*this ; @@ -971,8 +971,8 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) Node* main_init = new ConvL2INode(main_initL); phase->register_new_node_with_ctrl_of(main_init, pre_init); - Node* p1_init = vp1.make_pointer_expression(main_init); - Node* p2_init = vp2.make_pointer_expression(main_init); + Node* p1_init = vp1.make_pointer_expression(main_init, ctrl); + Node* p2_init = vp2.make_pointer_expression(main_init, ctrl); Node* size1 = igvn.longcon(vp1.size()); Node* size2 = igvn.longcon(vp2.size()); @@ -1092,13 +1092,18 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) return bol; } -Node* VPointer::make_pointer_expression(Node* iv_value) const { +// Creates the long pointer expression, evaluated with iv = iv_value. +// Since we are casting pointers to long with CastP2X, we must be careful +// that the values do not cross SafePoints, where the oop could be moved +// by GC, and the already cast value would not be updated, as it is not in +// the oop-map. For this, we must set a ctrl that is late enough, so that we +// cannot cross a SafePoint. +Node* VPointer::make_pointer_expression(Node* iv_value, Node* ctrl) const { assert(is_valid(), "must be valid"); PhaseIdealLoop* phase = _vloop.phase(); PhaseIterGVN& igvn = phase->igvn(); Node* iv = _vloop.iv(); - Node* ctrl = phase->get_ctrl(iv_value); auto maybe_add = [&] (Node* n1, Node* n2, BasicType bt) { if (n1 == nullptr) { return n2; } @@ -1120,7 +1125,9 @@ Node* VPointer::make_pointer_expression(Node* iv_value) const { Node* scaleL = igvn.longcon(s.scaleL().value()); Node* variable = (s.variable() == iv) ? iv_value : s.variable(); if (variable->bottom_type()->isa_ptr() != nullptr) { - variable = new CastP2XNode(nullptr, variable); + // Use a ctrl that is late enough, so that we do not + // evaluate the cast before a SafePoint. + variable = new CastP2XNode(ctrl, variable); phase->register_new_node(variable, ctrl); } node = new MulLNode(scaleL, variable); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index baca0d5b927..b39e46cbf35 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -1013,8 +1013,8 @@ public: } bool can_make_speculative_aliasing_check_with(const VPointer& other) const; - Node* make_pointer_expression(Node* iv_value) const; - BoolNode* make_speculative_aliasing_check_with(const VPointer& other) const; + Node* make_pointer_expression(Node* iv_value, Node* ctrl) const; + BoolNode* make_speculative_aliasing_check_with(const VPointer& other, Node* ctrl) const; NOT_PRODUCT( void print_on(outputStream* st, bool end_with_cr = true) const; ) diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 2882cc2c1a3..af4cb345e14 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -217,7 +217,7 @@ void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { TRACE_SPECULATIVE_ALIGNMENT_CHECK(cmp_alignment); TRACE_SPECULATIVE_ALIGNMENT_CHECK(bol_alignment); - add_speculative_check(bol_alignment); + add_speculative_check([&] (Node* ctrl) { return bol_alignment; }); } class VPointerWeakAliasingPair : public StackObj { @@ -389,8 +389,9 @@ void VTransform::apply_speculative_aliasing_runtime_checks() { } #endif - BoolNode* bol = vp1_union.make_speculative_aliasing_check_with(vp2_union); - add_speculative_check(bol); + add_speculative_check([&] (Node* ctrl) { + return vp1_union.make_speculative_aliasing_check_with(vp2_union, ctrl); + }); group_start = group_end; } @@ -420,7 +421,13 @@ void VTransform::apply_speculative_aliasing_runtime_checks() { // Multiversioning takes more compile time and code cache, but it also // produces fast code for when the runtime check passes (vectorized) and // when it fails (scalar performance). -void VTransform::add_speculative_check(BoolNode* bol) { +// +// Callback: +// In some cases, we require the ctrl just before the check iff_speculate to +// generate the values required in the check. We pass this ctrl into the +// callback, which is expected to produce the check, i.e. a BoolNode. +template +void VTransform::add_speculative_check(Callback callback) { assert(_vloop.are_speculative_checks_possible(), "otherwise we cannot make speculative assumptions"); ParsePredicateSuccessProj* parse_predicate_proj = _vloop.auto_vectorization_parse_predicate_proj(); IfTrueNode* new_check_proj = nullptr; @@ -432,6 +439,10 @@ void VTransform::add_speculative_check(BoolNode* bol) { new_check_proj = phase()->create_new_if_for_multiversion(_vloop.multiversioning_fast_proj()); } Node* iff_speculate = new_check_proj->in(0); + + // Create the check, given the ctrl just before the iff. + BoolNode* bol = callback(iff_speculate->in(0)); + igvn().replace_input_of(iff_speculate, 1, bol); TRACE_SPECULATIVE_ALIGNMENT_CHECK(iff_speculate); } diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 17dd81634ed..60b0b5d4f9d 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -258,7 +258,9 @@ private: void apply_speculative_alignment_runtime_checks(); void apply_speculative_aliasing_runtime_checks(); void add_speculative_alignment_check(Node* node, juint alignment); - void add_speculative_check(BoolNode* bol); + + template + void add_speculative_check(Callback callback); void apply_vectorization() const; }; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java new file mode 100644 index 00000000000..f33a46f4b49 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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=all-flags + * @bug 8366490 + * @summary Test that we set the ctrl of CastP2X when generating + * the aliasing runtime check, preventing the CastP2X + * from floating over a SafePoint that could move the oop, + * and render the cast value stale. + * @requires vm.gc == "G1" | vm.gc == "null" + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCastP2XCtrl::test + * -XX:CompileCommand=dontinline,*TestAliasingCastP2XCtrl::allocateArrays + * -XX:-TieredCompilation + * -Xbatch + * -XX:+UseG1GC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM + * compiler.loopopts.superword.TestAliasingCastP2XCtrl + */ + +/* + * @test id=fewer-flags + * @bug 8366490 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCastP2XCtrl::test + * -XX:CompileCommand=dontinline,*TestAliasingCastP2XCtrl::allocateArrays + * -Xbatch + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM + * compiler.loopopts.superword.TestAliasingCastP2XCtrl + */ + +/* + * @test id=vanilla + * @bug 8366490 + * @run main compiler.loopopts.superword.TestAliasingCastP2XCtrl + */ + +package compiler.loopopts.superword; + +public class TestAliasingCastP2XCtrl { + static final int N = 400; + static boolean flag = false; + + static void allocateArrays() { + for (int i = 0; 200_000 > i; ++i) { + int[] a = new int[N]; + } + // Makes GC more likely. + // Without it I could not reproduce it on slowdebug, + // but only with fastdebug. + if (flag) { System.gc(); } + flag = !flag; + } + + static int[] test() { + int a[] = new int[N]; + // We must make sure that no CastP2X happens before + // the call below, otherwise we may have an old oop. + allocateArrays(); + // The CastP2X for the aliasing runtime check should + // only be emitted after the call, to ensure we only + // deal with oops that are updated if there is a GC + // that could move our allocated array. + + // Not fully sure why we need the outer loop, but maybe + // it is needed so that a part of the check is hoisted, + // and the floats up, over the call if we do not set + // the ctrl. + for (int k = 0; k < 500; k++) { + for (int i = 1; i < 69; i++) { + // Aliasing references -> needs runtime check, + // should always fail. + a[i] = 14; + a[4] -= 14; + // The range computation for the constant access + // produces a shape: + // AddL(CastP2X(a), 0x20) + // And this shape only depends on a, so it could + // easily float above the call to allocateArrays + // if we do not set a ctrl that prevents that. + } + } + return a; + } + + public static void main(String[] args) { + int[] gold = test(); + for (int r = 0; r < 20; r++) { + int[] a = test(); + if (a[4] != gold[4]) { + throw new RuntimeException("wrong value " + gold[4] + " " + a[4]); + } + } + } +} From 49fd6a0cb4ddabaa865155bbfd4290077b7d13ea Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Thu, 4 Sep 2025 07:03:10 +0000 Subject: [PATCH 126/295] 8366558: Gtests leave /tmp/cgroups-test* files Reviewed-by: mbaesken, stuefe, lmesnik --- test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index c090aa28e9a..b33d6454477 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -341,7 +341,6 @@ TEST(cgroupTest, read_string_tests) { ok = controller->read_string(base_with_slash, result, 1024); EXPECT_FALSE(ok) << "Empty file should have failed"; EXPECT_STREQ("", result) << "Expected untouched result"; - delete_file(test_file); // File contents larger than 1K // We only read in the first 1K - 1 bytes @@ -358,6 +357,8 @@ TEST(cgroupTest, read_string_tests) { EXPECT_TRUE(1023 == strlen(result)) << "Expected only the first 1023 chars to be read in"; EXPECT_EQ(0, strncmp(too_large, result, 1023)); EXPECT_EQ(result[1023], '\0') << "The last character must be the null character"; + + delete_file(test_file); } TEST(cgroupTest, read_number_tuple_test) { @@ -393,6 +394,8 @@ TEST(cgroupTest, read_number_tuple_test) { ok = controller->read_numerical_tuple_value(base_with_slash, true /* use_first */, &result); EXPECT_FALSE(ok) << "Empty file should be an error"; EXPECT_EQ((jlong)-10, result) << "result value should be unchanged"; + + delete_file(test_file); } TEST(cgroupTest, read_numerical_key_beyond_max_path) { From 222ae365c89e7bcd2cd920f60aa34eebee2c83b6 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 4 Sep 2025 07:03:28 +0000 Subject: [PATCH 127/295] 8366688: G1: Rename G1HeapRegionRemSet::is_added_to_cset_group() to has_cset_group() Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CardSet.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp | 8 ++++---- src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp | 14 +++++++------- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 4 ++-- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 2 +- src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 5286a764996..f5b9bf2aebe 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -783,7 +783,7 @@ G1AddCardResult G1CardSet::add_card(uintptr_t card) { { uint region_idx = card_region >> config()->log2_card_regions_per_heap_region(); G1HeapRegion* r = G1CollectedHeap::heap()->region_at(region_idx); - assert(!r->rem_set()->is_added_to_cset_group() || + assert(!r->rem_set()->has_cset_group() || r->rem_set()->cset_group()->card_set() != this, "Should not be sharing a cardset"); } #endif diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 1e836e3efa2..2e10412cebf 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -115,7 +115,7 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { "Precondition, actively building cset or adding optional later on"); assert(hr->is_old(), "the region should be old"); - assert(!hr->rem_set()->is_added_to_cset_group(), "Should have already uninstalled group remset"); + assert(!hr->rem_set()->has_cset_group(), "Should have already uninstalled group remset"); assert(!hr->in_collection_set(), "should not already be in the collection set"); _g1h->register_old_region_with_region_attr(hr); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index f37ede6940e..5e42bf71882 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -3054,7 +3054,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { const char* remset_type = r->rem_set()->get_short_state_str(); uint cset_group_id = 0; - if (r->rem_set()->is_added_to_cset_group()) { + if (r->rem_set()->has_cset_group()) { cset_group_id = r->rem_set()->cset_group_id(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 7852bb7e8e3..b05a60234e2 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -63,7 +63,7 @@ G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr) : _state(Untracked) { } G1HeapRegionRemSet::~G1HeapRegionRemSet() { - assert(!is_added_to_cset_group(), "Still assigned to a CSet group"); + assert(!has_cset_group(), "Still assigned to a CSet group"); } void G1HeapRegionRemSet::clear_fcc() { @@ -76,7 +76,7 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { } clear_fcc(); - if (is_added_to_cset_group()) { + if (has_cset_group()) { card_set()->clear(); assert(card_set()->occupied() == 0, "Should be clear."); } @@ -90,13 +90,13 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { void G1HeapRegionRemSet::reset_table_scanner() { _code_roots.reset_table_scanner(); - if (is_added_to_cset_group()) { + if (has_cset_group()) { card_set()->reset_table_scanner(); } } G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->card_set_memory_stats(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index d2d502636fa..32008f7f20d 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * 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,12 +57,12 @@ class G1HeapRegionRemSet : public CHeapObj { void clear_fcc(); G1CardSet* card_set() { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->card_set(); } const G1CardSet* card_set() const { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->card_set(); } @@ -71,7 +71,7 @@ public: ~G1HeapRegionRemSet(); bool cardset_is_empty() const { - return !is_added_to_cset_group() || card_set()->is_empty(); + return !has_cset_group() || card_set()->is_empty(); } void install_cset_group(G1CSetCandidateGroup* cset_group) { @@ -83,7 +83,7 @@ public: void uninstall_cset_group(); - bool is_added_to_cset_group() const { + bool has_cset_group() const { return _cset_group != nullptr; } @@ -96,7 +96,7 @@ public: } uint cset_group_id() const { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->group_id(); } @@ -118,7 +118,7 @@ public: inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl); size_t occupied() { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return card_set()->occupied(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index 428586e160a..ff927959289 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { } void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); assert(_state != Untracked, "must be"); diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index cf032bc5d17..49cc993dac2 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -228,7 +228,7 @@ public: // Accumulate card set details for regions that are assigned to single region // groups. G1HeapRegionRemSet::mem_size() includes the size of the code roots - if (hrrs->is_added_to_cset_group() && hrrs->cset_group()->length() == 1) { + if (hrrs->has_cset_group() && hrrs->cset_group()->length() == 1) { G1CardSet* card_set = hrrs->cset_group()->card_set(); rs_mem_sz = hrrs->mem_size() + card_set->mem_size(); diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp index a5c8882e057..7b8d92b8fe4 100644 --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp @@ -108,7 +108,7 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) { size_t remset_bytes = r->rem_set()->mem_size(); size_t occupied = 0; // per region cardset details only valid if group contains a single region. - if (r->rem_set()->is_added_to_cset_group() && + if (r->rem_set()->has_cset_group() && r->rem_set()->cset_group()->length() == 1 ) { G1CardSet *card_set = r->rem_set()->cset_group()->card_set(); remset_bytes += card_set->mem_size(); From 1495dd94e97fc023dede71f957ce3b166d20d5ac Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 4 Sep 2025 07:13:41 +0000 Subject: [PATCH 128/295] 8366778: Sort share/asm, share/gc, share/include includes Reviewed-by: shade, ayang, jsikstro --- src/hotspot/share/asm/assembler.cpp | 1 - src/hotspot/share/asm/codeBuffer.hpp | 2 +- src/hotspot/share/asm/codeBuffer.inline.hpp | 1 + src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 1 - .../share/gc/g1/g1FullGCResetMetadataTask.hpp | 1 + src/hotspot/share/gc/serial/serialHeap.cpp | 1 - src/hotspot/share/gc/shared/collectedHeap.cpp | 1 - .../share/gc/shared/referenceProcessor.cpp | 1 - .../share/gc/shenandoah/shenandoahAsserts.cpp | 2 +- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 1 - .../share/gc/shenandoah/shenandoahHeap.cpp | 2 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 1 - .../share/gc/z/zUncoloredRoot.inline.hpp | 1 - src/hotspot/share/include/jvm_io.h | 2 +- .../jtreg/sources/TestIncludesAreSorted.java | 23 +------------------ 15 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index d415ddf004a..9e342d23afd 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -23,7 +23,6 @@ */ #include "asm/codeBuffer.hpp" -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "gc/shared/collectedHeap.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 57b4aaacdce..35bbd2f657f 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -33,8 +33,8 @@ #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" #include "utilities/linkedlist.hpp" -#include "utilities/resizableHashTable.hpp" #include "utilities/macros.hpp" +#include "utilities/resizableHashTable.hpp" template static inline void put_native(address p, T x) { diff --git a/src/hotspot/share/asm/codeBuffer.inline.hpp b/src/hotspot/share/asm/codeBuffer.inline.hpp index 06ec9174b34..076749e8967 100644 --- a/src/hotspot/share/asm/codeBuffer.inline.hpp +++ b/src/hotspot/share/asm/codeBuffer.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_ASM_CODEBUFFER_INLINE_HPP #include "asm/codeBuffer.hpp" + #include "ci/ciEnv.hpp" #include "code/compiledIC.hpp" diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 76d4ba5ab19..693e915b98e 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -30,7 +30,6 @@ #include "gc/shared/gcArguments.hpp" #include "gc/shared/locationPrinter.inline.hpp" #include "logging/log.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp index 5f046e35001..d2bc8e7d8e0 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP #define SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP + #include "gc/g1/g1FullGCTask.hpp" #include "gc/g1/g1HeapRegion.hpp" diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 6bb1183aa56..f97cd4e3b70 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -67,7 +67,6 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index e82ec1439ea..71017817d14 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -27,7 +27,6 @@ #include "classfile/vmClasses.hpp" #include "gc/shared/allocTracer.hpp" #include "gc/shared/barrierSet.hpp" -#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/gcHeapSummary.hpp" diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index e5d1bd4bec1..0153ee13287 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -24,7 +24,6 @@ #include "classfile/javaClasses.inline.hpp" #include "compiler/compilerDefinitions.inline.hpp" -#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/gcTimer.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index ca9624ec752..93c218e9e8b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -29,8 +29,8 @@ #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "oops/oop.inline.hpp" #include "memory/resourceArea.hpp" +#include "oops/oop.inline.hpp" #include "runtime/os.hpp" #include "utilities/vmError.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 293391a86eb..69827d72f44 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -31,7 +31,6 @@ #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index b90468501f6..b662aeb7eb7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -29,10 +29,10 @@ #include "classfile/systemDictionary.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/fullGCForwarding.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcArguments.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/gc_globals.hpp" #include "gc/shared/locationPrinter.inline.hpp" #include "gc/shared/memAllocator.hpp" #include "gc/shared/plab.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 5cccd395d38..3aa3f6cb0ca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -30,7 +30,6 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" -#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index 0d9fccde87c..128d8f1bfef 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -27,7 +27,6 @@ #include "gc/z/zUncoloredRoot.hpp" #include "gc/z/zAddress.inline.hpp" -#include "gc/z/zBarrier.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" #include "oops/oop.hpp" diff --git a/src/hotspot/share/include/jvm_io.h b/src/hotspot/share/include/jvm_io.h index e6265fe5192..5233798b5a8 100644 --- a/src/hotspot/share/include/jvm_io.h +++ b/src/hotspot/share/include/jvm_io.h @@ -28,8 +28,8 @@ #include -#include "jni.h" #include "jvm_md.h" +#include "jni.h" #ifdef __cplusplus extern "C" { diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 695b300f3fd..19aaeed69a2 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -43,28 +43,7 @@ public class TestIncludesAreSorted { * can be checked). */ private static final String[] HOTSPOT_SOURCES_TO_CHECK = { - "share/adlc", - "share/c1", - "share/cds", - "share/ci", - "share/classfile", - "share/code", - "share/compiler", - "share/interpreter", - "share/jfr", - "share/jvmci", - "share/libadt", - "share/logging", - "share/memory", - "share/metaprogramming", - "share/nmt", - "share/oops", - "share/opto", - "share/precompiled", - "share/prims", - "share/runtime", - "share/services", - "share/utilities" + "share" }; /** From 986ecff5f9b16f1b41ff15ad94774d65f3a4631d Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 07:14:59 +0000 Subject: [PATCH 129/295] 8366849: Problemlist jdk/jshell/ToolSimpleTest.java as generic-all Reviewed-by: liach, jlahoda --- test/langtools/ProblemList.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index e1124f4784a..59b5b240a29 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -52,8 +52,8 @@ jdk/jshell/UserJdiUserRemoteTest.java jdk/jshell/UserInputTest.java 8169536 generic-all jdk/jshell/ToolBasicTest.java 8265357 macosx-aarch64 jdk/jshell/HighlightUITest.java 8284144 generic-all -jdk/jshell/ToolSimpleTest.java 8366582 windows-x64 -jdk/jshell/ToolLocalSimpleTest.java 8366582 windows-x64 +jdk/jshell/ToolSimpleTest.java 8366582 generic-all +jdk/jshell/ToolLocalSimpleTest.java 8366582 generic-all ########################################################################### # From ab9f70dd5acd73744e3d82e9884985904f280c26 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 4 Sep 2025 08:01:01 +0000 Subject: [PATCH 130/295] 8366420: AOTMapTest fails when default jsa is missing from JDK Reviewed-by: iklam, azeller --- .../hotspot/jtreg/runtime/cds/CDSMapTest.java | 1 - .../cds/appcds/aotCache/AOTMapTest.java | 27 +++++-------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java index c93b16c68b8..e38b68bdbcf 100644 --- a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java @@ -25,7 +25,6 @@ * @test * @bug 8308903 * @summary Test the contents of -Xlog:aot+map - * @requires vm.flagless * @requires vm.cds * @library /test/lib * @run driver CDSMapTest diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java index f544b5653b7..438bfb22c9b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java @@ -25,7 +25,6 @@ * @test id=aot * @bug 8362566 * @summary Test the contents of -Xlog:aot+map with AOT workflow - * @requires vm.flagless * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/hotspot/jtreg/runtime/cds * @build AOTMapTest @@ -37,7 +36,6 @@ * @test id=dynamic * @bug 8362566 * @summary Test the contents of -Xlog:aot+map with AOT workflow - * @requires vm.flagless * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/hotspot/jtreg/runtime/cds * @build jdk.test.whitebox.WhiteBox @@ -58,16 +56,11 @@ public class AOTMapTest { static final String mainClass = "AOTMapTestApp"; public static void main(String[] args) throws Exception { - doTest(args, false); - - if (Platform.is64bit()) { - // There's no oop/klass compression on 32-bit. - doTest(args, true); - } + doTest(args); } - public static void doTest(String[] args, boolean compressed) throws Exception { - Tester tester = new Tester(compressed); + public static void doTest(String[] args) throws Exception { + Tester tester = new Tester(); tester.run(args); validate(tester.dumpMapFile); @@ -80,16 +73,14 @@ public class AOTMapTest { } static class Tester extends CDSAppTester { - boolean compressed; String dumpMapFile; String runMapFile; - public Tester(boolean compressed) { + public Tester() { super(mainClass); - this.compressed = compressed; - dumpMapFile = "test" + (compressed ? "0" : "1") + ".dump.aotmap"; - runMapFile = "test" + (compressed ? "0" : "1") + ".run.aotmap"; + dumpMapFile = "test" + "0" + ".dump.aotmap"; + runMapFile = "test" + "0" + ".run.aotmap"; } @Override @@ -104,12 +95,6 @@ public class AOTMapTest { vmArgs.add("-Xmx128M"); vmArgs.add("-Xlog:aot=debug"); - if (Platform.is64bit()) { - // These options are available only on 64-bit. - String sign = (compressed) ? "+" : "-"; - vmArgs.add("-XX:" + sign + "UseCompressedOops"); - } - // filesize=0 ensures that a large map file not broken up in multiple files. String logMapPrefix = "-Xlog:aot+map=debug,aot+map+oops=trace:file="; String logMapSuffix = ":none:filesize=0"; From 53d4e928ef2851f3e16d1d200b5c3fb036e15e00 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 4 Sep 2025 09:47:42 +0000 Subject: [PATCH 131/295] 8366238: Improve RBTree API with stricter comparator semantics and pluggable validation/printing hooks Reviewed-by: jsjolen, ayang --- src/hotspot/share/gc/z/zMappedCache.cpp | 14 +- src/hotspot/share/gc/z/zMappedCache.hpp | 4 +- src/hotspot/share/nmt/vmatree.hpp | 9 +- src/hotspot/share/opto/printinlining.hpp | 6 +- src/hotspot/share/utilities/rbTree.hpp | 111 +++++++----- src/hotspot/share/utilities/rbTree.inline.hpp | 55 +++--- test/hotspot/gtest/utilities/test_rbtree.cpp | 159 +++++++++++++++--- 7 files changed, 258 insertions(+), 100 deletions(-) diff --git a/src/hotspot/share/gc/z/zMappedCache.cpp b/src/hotspot/share/gc/z/zMappedCache.cpp index ad02d265e93..394c5649c14 100644 --- a/src/hotspot/share/gc/z/zMappedCache.cpp +++ b/src/hotspot/share/gc/z/zMappedCache.cpp @@ -118,20 +118,20 @@ static ZMappedCacheEntry* create_entry(const ZVirtualMemory& vmem) { return entry; } -bool ZMappedCache::EntryCompare::cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b) { +bool ZMappedCache::EntryCompare::less_than(const IntrusiveRBNode* a, const IntrusiveRBNode* b) { const ZVirtualMemory vmem_a = ZMappedCacheEntry::cast_to_entry(a)->vmem(); const ZVirtualMemory vmem_b = ZMappedCacheEntry::cast_to_entry(b)->vmem(); return vmem_a.end() < vmem_b.start(); } -int ZMappedCache::EntryCompare::cmp(zoffset key, const IntrusiveRBNode* node) { +RBTreeOrdering ZMappedCache::EntryCompare::cmp(zoffset key, const IntrusiveRBNode* node) { const ZVirtualMemory vmem = ZMappedCacheEntry::cast_to_entry(node)->vmem(); - if (key < vmem.start()) { return -1; } - if (key > vmem.end()) { return 1; } + if (key < vmem.start()) { return RBTreeOrdering::LT; } + if (key > vmem.end()) { return RBTreeOrdering::GT; } - return 0; // Containing + return RBTreeOrdering::EQ; // Containing } void ZMappedCache::Tree::verify() const { @@ -168,12 +168,12 @@ void ZMappedCache::Tree::insert(TreeNode* node, const TreeCursor& cursor) { // Insert in tree TreeImpl::insert_at_cursor(node, cursor); - if (_left_most == nullptr || EntryCompare::cmp(node, _left_most)) { + if (_left_most == nullptr || EntryCompare::less_than(node, _left_most)) { // Keep track of left most node _left_most = node; } - if (_right_most == nullptr || EntryCompare::cmp(_right_most, node)) { + if (_right_most == nullptr || EntryCompare::less_than(_right_most, node)) { // Keep track of right most node _right_most = node; } diff --git a/src/hotspot/share/gc/z/zMappedCache.hpp b/src/hotspot/share/gc/z/zMappedCache.hpp index 28f37de0de1..8688e047ae1 100644 --- a/src/hotspot/share/gc/z/zMappedCache.hpp +++ b/src/hotspot/share/gc/z/zMappedCache.hpp @@ -40,8 +40,8 @@ class ZMappedCache { private: struct EntryCompare { - static int cmp(zoffset a, const IntrusiveRBNode* b); - static bool cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b); + static RBTreeOrdering cmp(zoffset a, const IntrusiveRBNode* b); + static bool less_than(const IntrusiveRBNode* a, const IntrusiveRBNode* b); }; struct ZSizeClassListNode { diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 01f0e107a56..1b5729054e4 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -50,11 +50,10 @@ public: class PositionComparator { public: - static int cmp(position a, position b) { - if (a < b) return -1; - if (a == b) return 0; - if (a > b) return 1; - ShouldNotReachHere(); + static RBTreeOrdering cmp(position a, position b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; diff --git a/src/hotspot/share/opto/printinlining.hpp b/src/hotspot/share/opto/printinlining.hpp index 3bf09bc921f..e331593ec0e 100644 --- a/src/hotspot/share/opto/printinlining.hpp +++ b/src/hotspot/share/opto/printinlining.hpp @@ -67,8 +67,10 @@ private: }; struct Cmp { - static int cmp(int a, int b) { - return a - b; + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index cc52cec3fe0..4c358b53ff0 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -35,17 +35,13 @@ // An intrusive red-black tree is constructed with two template parameters: // K is the key type used. // COMPARATOR must have a static function `cmp(K a, const IntrusiveRBNode* b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// Additional static functions used for extra validation can optionally be provided: -// `cmp(K a, K b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// `cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b)` which returns: -// - true if a < b -// - false otherwise +// - RBTreeOrdering::LT when a < b +// - RBTreeOrdering::EQ when a == b +// - RBTreeOrdering::GT when a > b +// A second static function `less_than(const IntrusiveRBNode* a, const IntrusiveRBNode* b)` +// used for extra validation can optionally be provided. This should return: +// - true if a < b +// - false otherwise // K needs to be of a type that is trivially destructible. // K needs to be stored by the user and is not stored inside the tree. // Nodes are address stable and will not change during its lifetime. @@ -54,10 +50,10 @@ // K is the key type stored in the tree nodes. // V is the value type stored in the tree nodes. // COMPARATOR must have a static function `cmp(K a, K b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// A second static function `cmp(const RBNode* a, const RBNode* b)` +// - RBTreeOrdering::LT when a < b +// - RBTreeOrdering::EQ when a == b +// - RBTreeOrdering::GT when a > b +// A second static function `less_than(const RBNode* a, const RBNode* b)` // used for extra validation can optionally be provided. This should return: // - true if a < b // - false otherwise @@ -65,6 +61,8 @@ // The tree will call a value's destructor when its node is removed. // Nodes are address stable and will not change during its lifetime. +enum class RBTreeOrdering : int { LT, EQ, GT }; + template class AbstractRBTree; @@ -126,10 +124,11 @@ private: // Returns left child (now parent) IntrusiveRBNode* rotate_right(); - template + template void verify(size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path, - size_t& tree_depth, bool expect_visited, NodeVerifier verifier) const; + size_t& tree_depth, bool expect_visited, NODE_VERIFIER verifier, + const USER_VERIFIER& extra_verifier) const; }; @@ -203,32 +202,37 @@ private: struct has_cmp_type(CMP::cmp), void())> : std::true_type {}; template - static constexpr bool HasKeyComparator = has_cmp_type::value; + static constexpr bool HasKeyComparator = has_cmp_type::value; template - static constexpr bool HasNodeComparator = has_cmp_type::value; + static constexpr bool HasNodeComparator = has_cmp_type::value; + + template + struct has_less_than_type : std::false_type {}; + template + struct has_less_than_type(CMP::less), void())> : std::true_type {}; template - static constexpr bool HasNodeVerifier = has_cmp_type::value; + static constexpr bool HasNodeVerifier = has_less_than_type::value; template && !HasNodeComparator)> - int cmp(const K& a, const NodeType* b) const { + RBTreeOrdering cmp(const K& a, const NodeType* b) const { return COMPARATOR::cmp(a, b->key()); } template )> - int cmp(const K& a, const NodeType* b) const { + RBTreeOrdering cmp(const K& a, const NodeType* b) const { return COMPARATOR::cmp(a, b); } template )> - bool cmp(const NodeType* a, const NodeType* b) const { + bool less_than(const NodeType* a, const NodeType* b) const { return true; } template )> - bool cmp(const NodeType* a, const NodeType* b) const { - return COMPARATOR::cmp(a, b); + bool less_than(const NodeType* a, const NodeType* b) const { + return COMPARATOR::less_than(a, b); } // Cannot assert if no key comparator exist. @@ -237,7 +241,7 @@ private: template )> void assert_key_leq(K a, K b) const { - assert(COMPARATOR::cmp(a, b) <= 0, "key a must be less or equal to key b"); + assert(COMPARATOR::cmp(a, b) != RBTreeOrdering::GT, "key a must be less or equal to key b"); } // True if node is black (nil nodes count as black) @@ -256,10 +260,23 @@ private: // Assumption: node has at most one child. Two children is handled in `remove_at_cursor()` void remove_from_tree(IntrusiveRBNode* node); - template - void verify_self(NodeVerifier verifier) const; + struct empty_verifier { + bool operator()(const NodeType* n) const { + return true; + } + }; - void print_node_on(outputStream* st, int depth, const NodeType* n) const; + template + void verify_self(NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const; + + struct default_printer { + void operator()(outputStream* st, const NodeType* n, int depth) const { + n->print_on(st, depth); + } + }; + + template + void print_node_on(outputStream* st, int depth, const NodeType* n, const PRINTER& node_printer) const; public: NONCOPYABLE(AbstractRBTree); @@ -422,22 +439,30 @@ public: // Verifies that the tree is correct and holds rb-properties // If not using a key comparator (when using IntrusiveRBTree for example), // A second `cmp` must exist in COMPARATOR (see top of file). - template )> - void verify_self() const { - verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp(a, b);}); + // Accepts an optional callable `bool extra_verifier(const Node* n)`. + // This should return true if the node is valid. + // If provided, each node is also verified through this callable. + template )> + void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const { + verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::less_than(a, b);}, extra_verifier); } - template && !HasNodeVerifier)> - void verify_self() const { - verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp(a->key(), b->key()) < 0; }); + template && !HasNodeVerifier)> + void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const { + verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp(a->key(), b->key()) == RBTreeOrdering::LT; }, extra_verifier); } - template && !HasKeyComparator && !HasNodeVerifier)> - void verify_self() const { - verify_self([](const NodeType*, const NodeType*){ return true;}); + template && !HasKeyComparator && !HasNodeVerifier)> + void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const { + verify_self([](const NodeType*, const NodeType*){ return true;}, extra_verifier); } - void print_on(outputStream* st) const; + // Accepts an optional printing callable `void node_printer(outputStream* st, const Node* n, int depth)`. + // If provided, each node is printed through this callable rather than the default `print_on`. + template + void print_on(outputStream* st, const PRINTER& node_printer = PRINTER()) const; }; @@ -451,6 +476,14 @@ class RBTree : public AbstractRBTree, COMPARATOR> { public: RBTree() : BaseType(), _allocator() {} ~RBTree() { remove_all(); } + RBTree(const RBTree& other) : BaseType(), _allocator() { + assert(std::is_copy_constructible(), "Value type must be copy-constructible"); + other.visit_in_order([&](auto node) { + this->upsert(node->key(), node->val()); + return true; + }); + } + RBTree& operator=(const RBTree& other) = delete; typedef typename BaseType::Cursor Cursor; using BaseType::cursor; diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 365786f7fc1..16150e41be8 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -123,10 +123,11 @@ inline IntrusiveRBNode* IntrusiveRBNode::next() { return const_cast(static_cast(this)->next()); } -template +template inline void IntrusiveRBNode::verify( size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path, - size_t& tree_depth, bool expect_visited, NodeVerifier verifier) const { + size_t& tree_depth, bool expect_visited, NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const { + assert(extra_verifier(static_cast(this)), "user provided verifier failed"); assert(expect_visited != _visited, "node already visited"); DEBUG_ONLY(_visited = !_visited); @@ -143,7 +144,7 @@ inline void IntrusiveRBNode::verify( assert(is_black() || _left->is_black(), "2 red nodes in a row"); assert(_left->parent() == this, "pointer mismatch"); _left->verify(num_nodes, num_black_nodes_left, shortest_leaf_path_left, - longest_leaf_path_left, tree_depth_left, expect_visited, verifier); + longest_leaf_path_left, tree_depth_left, expect_visited, verifier, extra_verifier); } size_t num_black_nodes_right = 0; @@ -159,7 +160,7 @@ inline void IntrusiveRBNode::verify( assert(is_black() || _left->is_black(), "2 red nodes in a row"); assert(_right->parent() == this, "pointer mismatch"); _right->verify(num_nodes, num_black_nodes_right, shortest_leaf_path_right, - longest_leaf_path_right, tree_depth_right, expect_visited, verifier); + longest_leaf_path_right, tree_depth_right, expect_visited, verifier, extra_verifier); } shortest_leaf_path = MAX2(longest_leaf_path_left, longest_leaf_path_right); @@ -190,13 +191,13 @@ AbstractRBTree::cursor(const K& key, const NodeType* hi IntrusiveRBNode* const* insert_location = &_root; if (hint_node != nullptr) { - const int hint_cmp = cmp(key, hint_node); + const RBTreeOrdering hint_cmp = cmp(key, hint_node); while (hint_node->parent() != nullptr) { - const int parent_cmp = cmp(key, (NodeType*)hint_node->parent()); + const RBTreeOrdering parent_cmp = cmp(key, (NodeType*)hint_node->parent()); // Move up until the parent would put us on the other side of the key. // Meaning we are in the correct subtree. - if ((parent_cmp <= 0 && hint_cmp < 0) || - (parent_cmp >= 0 && hint_cmp > 0)) { + if ((parent_cmp != RBTreeOrdering::GT && hint_cmp == RBTreeOrdering::LT) || + (parent_cmp != RBTreeOrdering::LT && hint_cmp == RBTreeOrdering::GT)) { hint_node = (NodeType*)hint_node->parent(); } else { break; @@ -212,14 +213,14 @@ AbstractRBTree::cursor(const K& key, const NodeType* hi while (*insert_location != nullptr) { NodeType* curr = (NodeType*)*insert_location; - const int key_cmp_k = cmp(key, curr); + const RBTreeOrdering key_cmp_k = cmp(key, curr); - if (key_cmp_k == 0) { + if (key_cmp_k == RBTreeOrdering::EQ) { break; } parent = *insert_location; - if (key_cmp_k < 0) { + if (key_cmp_k == RBTreeOrdering::LT) { insert_location = &curr->_left; } else { insert_location = &curr->_right; @@ -551,19 +552,19 @@ inline void AbstractRBTree::replace_at_cursor(NodeType* new_node->_parent = old_node->_parent; if (new_node->is_left_child()) { - assert(cmp(static_cast(new_node), static_cast(new_node->parent())), "new node not < parent"); + assert(less_than(static_cast(new_node), static_cast(new_node->parent())), "new node not < parent"); } else if (new_node->is_right_child()) { - assert(cmp(static_cast(new_node->parent()), static_cast(new_node)), "new node not > parent"); + assert(less_than(static_cast(new_node->parent()), static_cast(new_node)), "new node not > parent"); } new_node->_left = old_node->_left; new_node->_right = old_node->_right; if (new_node->_left != nullptr) { - assert(cmp(static_cast(new_node->_left), static_cast(new_node)), "left child not < new node"); + assert(less_than(static_cast(new_node->_left), static_cast(new_node)), "left child not < new node"); new_node->_left->set_parent(new_node); } if (new_node->_right != nullptr) { - assert(cmp(static_cast(new_node), static_cast(new_node->_right)), "right child not > new node"); + assert(less_than(static_cast(new_node), static_cast(new_node->_right)), "right child not > new node"); new_node->_right->set_parent(new_node); } @@ -661,8 +662,8 @@ inline void AbstractRBTree::visit_range_in_order(const } template -template -inline void AbstractRBTree::verify_self(NodeVerifier verifier) const { +template +inline void AbstractRBTree::verify_self(NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const { if (_root == nullptr) { assert(_num_nodes == 0, "rbtree has %zu nodes but no root", _num_nodes); return; @@ -679,7 +680,7 @@ inline void AbstractRBTree::verify_self(NodeVerifier ve bool expected_visited = DEBUG_ONLY(_expected_visited) NOT_DEBUG(false); _root->verify(num_nodes, black_depth, shortest_leaf_path, longest_leaf_path, - tree_depth, expected_visited, verifier); + tree_depth, expected_visited, verifier, extra_verifier); const unsigned int maximum_depth = log2i(size() + 1) * 2; @@ -731,21 +732,23 @@ inline void RBNode::print_on(outputStream* st, int depth) const { } template -void AbstractRBTree::print_node_on(outputStream* st, int depth, const NodeType* n) const { - n->print_on(st, depth); +template +void AbstractRBTree::print_node_on(outputStream* st, int depth, const NodeType* n, const PRINTER& node_printer) const { + node_printer(st, n, depth); depth++; - if (n->_right != nullptr) { - print_node_on(st, depth, (NodeType*)n->_right); - } if (n->_left != nullptr) { - print_node_on(st, depth, (NodeType*)n->_left); + print_node_on(st, depth, (NodeType*)n->_left, node_printer); + } + if (n->_right != nullptr) { + print_node_on(st, depth, (NodeType*)n->_right, node_printer); } } template -void AbstractRBTree::print_on(outputStream* st) const { +template +void AbstractRBTree::print_on(outputStream* st, const PRINTER& node_printer) const { if (_root != nullptr) { - print_node_on(st, 0, (NodeType*)_root); + print_node_on(st, 0, (NodeType*)_root, node_printer); } } diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index d8394de017e..609fb43e59e 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -36,26 +36,30 @@ public: using RBTreeIntNode = RBNode; struct Cmp { - static int cmp(int a, int b) { - return a - b; + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } - static bool cmp(const RBTreeIntNode* a, const RBTreeIntNode* b) { + static bool less_than(const RBTreeIntNode* a, const RBTreeIntNode* b) { return a->key() < b->key(); } }; struct CmpInverse { - static int cmp(int a, int b) { - return b - a; + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::GT; + if (a > b) return RBTreeOrdering::LT; + return RBTreeOrdering::EQ; } }; struct FCmp { - static int cmp(float a, float b) { - if (a < b) return -1; - if (a == b) return 0; - return 1; + static RBTreeOrdering cmp(float a, float b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; @@ -94,16 +98,15 @@ struct ArrayAllocator { }; struct IntrusiveCmp { - static int cmp(int a, const IntrusiveTreeNode* b) { - return a - IntrusiveHolder::cast_to_self(b)->key; - } - - static int cmp(int a, int b) { - return a - b; + static RBTreeOrdering cmp(int a, const IntrusiveTreeNode* b_node) { + int b = IntrusiveHolder::cast_to_self(b_node)->key; + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } // true if a < b - static bool cmp(const IntrusiveTreeNode* a, const IntrusiveTreeNode* b) { + static bool less_than(const IntrusiveTreeNode* a, const IntrusiveTreeNode* b) { return (IntrusiveHolder::cast_to_self(a)->key - IntrusiveHolder::cast_to_self(b)->key) < 0; } @@ -837,6 +840,50 @@ public: } } + static bool custom_validator(const IntrusiveRBNode* n) { + IntrusiveHolder* holder = IntrusiveHolder::cast_to_self(n); + assert(holder->key == holder->data, "must be"); + + return true; + } + + void test_custom_verify_intrusive() { + IntrusiveTreeInt intrusive_tree; + int num_nodes = 100; + + // Insert values + for (int n = 0; n < num_nodes; n++) { + IntrusiveCursor cursor = intrusive_tree.cursor(n); + EXPECT_NULL(cursor.node()); + + // Custom allocation here is just malloc + IntrusiveHolder* place = (IntrusiveHolder*)os::malloc(sizeof(IntrusiveHolder), mtTest); + new (place) IntrusiveHolder(n, n); + + intrusive_tree.insert_at_cursor(place->get_node(), cursor); + IntrusiveCursor cursor2 = intrusive_tree.cursor(n); + + EXPECT_NOT_NULL(cursor2.node()); + } + + intrusive_tree.verify_self(RBTreeTest::custom_validator); + + int node_count = 0; + intrusive_tree.verify_self([&](const IntrusiveRBNode* n) { + node_count++; + + IntrusiveHolder* holder = IntrusiveHolder::cast_to_self(n); + assert(holder->key >= 0, "must be"); + assert(holder->data >= 0, "must be"); + assert(holder->key < num_nodes, "must be"); + assert(holder->data < num_nodes, "must be"); + + return true; + }); + + EXPECT_EQ(node_count, num_nodes); + } + #ifdef ASSERT void test_nodes_visited_once() { constexpr size_t memory_size = 65536; @@ -945,10 +992,13 @@ TEST_VM_F(RBTreeTest, LeftMostRightMost) { } struct PtrCmp { - static int cmp(const void* a, const void* b) { + static RBTreeOrdering cmp(const void* a, const void* b) { const uintptr_t ai = p2u(a); const uintptr_t bi = p2u(b); - return ai == bi ? 0 : (ai > bi ? 1 : -1); + + if (ai < bi) return RBTreeOrdering::LT; + if (ai > bi) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; @@ -982,7 +1032,11 @@ TEST_VM(RBTreeTestNonFixture, TestPrintPointerTree) { } struct IntCmp { - static int cmp(int a, int b) { return a == b ? 0 : (a > b ? 1 : -1); } + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; + } }; TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { @@ -1005,10 +1059,42 @@ TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { ASSERT_NE(strstr(ss.base(), s3), N); } +TEST_VM(RBTreeTestNonFixture, TestPrintCustomPrinter) { + typedef RBTree > TreeType; + typedef RBNode NodeType; + + TreeType tree; + const int i1 = -13591; + const int i2 = 0; + const int i3 = 82924; + tree.upsert(i1, 1U); + tree.upsert(i2, 2U); + tree.upsert(i3, 3U); + + stringStream ss; + int print_count = 0; + tree.print_on(&ss, [&](outputStream* st, const NodeType* n, int depth) { + st->print_cr("[%d] (%d): %d", depth, n->val(), n->key()); + print_count++; + }); + +const char* const expected = + "[0] (2): 0\n" + "[1] (1): -13591\n" + "[1] (3): 82924\n"; + + ASSERT_EQ(print_count, 3); + ASSERT_STREQ(ss.base(), expected); +} + TEST_VM_F(RBTreeTest, IntrusiveTest) { this->test_intrusive(); } +TEST_VM_F(RBTreeTest, IntrusiveCustomVerifyTest) { + this->test_custom_verify_intrusive(); +} + TEST_VM_F(RBTreeTest, FillAndVerify) { this->test_fill_verify(); } @@ -1021,6 +1107,22 @@ TEST_VM_F(RBTreeTest, CursorReplace) { TEST_VM_F(RBTreeTest, NodesVisitedOnce) { this->test_nodes_visited_once(); } + +TEST_VM_ASSERT_MSG(RBTreeTestNonFixture, CustomVerifyAssert, ".*failed on key = 7") { + typedef RBTreeCHeap TreeType; + typedef RBNode NodeType; + + TreeType tree; + for (int i = 0; i < 10; i++) { + tree.upsert(i, i); + } + + tree.verify_self([&](const NodeType* n) { + assert(n->key() != 7, "failed on key = %d", n->key()); + return true; + }); +} + #endif // ASSERT TEST_VM_F(RBTreeTest, InsertRemoveVerify) { @@ -1039,6 +1141,25 @@ TEST_VM_F(RBTreeTest, InsertRemoveVerify) { } } +TEST_VM_F(RBTreeTest, CustomVerify) { + constexpr int num_nodes = 1000; + RBTreeInt tree; + for (int i = 0; i < num_nodes; i++) { + tree.upsert(i, i); + } + + int node_count = 0; + tree.verify_self([&](const RBTreeIntNode* n) { + node_count++; + + assert(n->key() >= 0, "must be"); + assert(n->key() < num_nodes, "must be"); + return true; + }); + + EXPECT_EQ(node_count, num_nodes); +} + TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { { // Repeatedly verify a tree of moderate size RBTreeInt rbtree; From 8c50bed86709a45615743dd7953b8c6861f1da0c Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 4 Sep 2025 10:48:57 +0000 Subject: [PATCH 132/295] 8366872: Wrong number of template arguments in test in test_rbtree.cpp Reviewed-by: ayang, syan --- test/hotspot/gtest/utilities/test_rbtree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index 609fb43e59e..ff234dd764a 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -1060,7 +1060,7 @@ TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { } TEST_VM(RBTreeTestNonFixture, TestPrintCustomPrinter) { - typedef RBTree > TreeType; + typedef RBTreeCHeap TreeType; typedef RBNode NodeType; TreeType tree; From 80873a09bf8392d98d20273e0688b17c62252242 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Thu, 4 Sep 2025 13:17:29 +0000 Subject: [PATCH 133/295] 8366836: Don't execute post-IncludeCustomExtension if file was not included Reviewed-by: erikj --- make/common/MakeIncludeEnd.gmk | 13 +++++++++---- make/common/MakeIncludeStart.gmk | 1 - 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/make/common/MakeIncludeEnd.gmk b/make/common/MakeIncludeEnd.gmk index 7023a861fa1..47be7c65c72 100644 --- a/make/common/MakeIncludeEnd.gmk +++ b/make/common/MakeIncludeEnd.gmk @@ -27,10 +27,15 @@ # MakeIncludeEnd.gmk should be included last of all in all include files ################################################################################ -# Hook to include the corresponding custom file, if present. -ifneq ($(NO_CUSTOM_EXTENSIONS), true) - CUSTOM_POST_NAME := $(subst .gmk,-post.gmk, $(THIS_INCLUDE)) - $(eval $(call IncludeCustomExtension, $(CUSTOM_POST_NAME))) +ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true) + # This was the first time this file was included. Prevent future inclusion. + INCLUDE_GUARD_$(THIS_INCLUDE) := true + + # Hook to include the corresponding custom file, if present. + ifneq ($(NO_CUSTOM_EXTENSIONS), true) + CUSTOM_POST_NAME := $(subst .gmk,-post.gmk, $(THIS_INCLUDE)) + $(eval $(call IncludeCustomExtension, $(CUSTOM_POST_NAME))) + endif endif # Pop our helper name off the stack diff --git a/make/common/MakeIncludeStart.gmk b/make/common/MakeIncludeStart.gmk index 3904633f9f2..f1d690ddb41 100644 --- a/make/common/MakeIncludeStart.gmk +++ b/make/common/MakeIncludeStart.gmk @@ -70,7 +70,6 @@ INCLUDE_STACK := $(THIS_INCLUDE) $(INCLUDE_STACK) # Setup an automatic include guard ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true) - INCLUDE_GUARD_$(THIS_INCLUDE) := true INCLUDE := true # Hook to include the corresponding custom file, if present. From e19035577724f40aca14ef7d5dad0906ce9e89ab Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 4 Sep 2025 13:19:12 +0000 Subject: [PATCH 134/295] 8365467: Issues with jrtfs implementation for exploded run-time images Reviewed-by: rriggs, sundar --- .../jdk/internal/jrtfs/ExplodedImage.java | 175 ++++++------- .../jdk/internal/jrtfs/SystemImage.java | 8 +- .../whitebox/ExplodedImageTestDriver.java | 30 +++ .../internal/jrtfs/whitebox/TEST.properties | 4 + .../jdk/internal/jrtfs/ExplodedImageTest.java | 232 ++++++++++++++++++ 5 files changed, 359 insertions(+), 90 deletions(-) create mode 100644 test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java create mode 100644 test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties create mode 100644 test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java b/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java index 87a00da4393..4fe6612a8ed 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,17 +27,15 @@ package jdk.internal.jrtfs; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.DirectoryStream; -import java.nio.file.FileSystem; import java.nio.file.FileSystemException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Stream; import jdk.internal.jimage.ImageReader.Node; @@ -56,16 +54,15 @@ class ExplodedImage extends SystemImage { private static final String MODULES = "/modules/"; private static final String PACKAGES = "/packages/"; - private static final int PACKAGES_LEN = PACKAGES.length(); - private final FileSystem defaultFS; + private final Path modulesDir; private final String separator; - private final Map nodes = Collections.synchronizedMap(new HashMap<>()); + private final Map nodes = new HashMap<>(); private final BasicFileAttributes modulesDirAttrs; ExplodedImage(Path modulesDir) throws IOException { - defaultFS = FileSystems.getDefault(); - String str = defaultFS.getSeparator(); + this.modulesDir = modulesDir; + String str = modulesDir.getFileSystem().getSeparator(); separator = str.equals("/") ? null : str; modulesDirAttrs = Files.readAttributes(modulesDir, BasicFileAttributes.class); initNodes(); @@ -79,21 +76,26 @@ class ExplodedImage extends SystemImage { private PathNode link; private List children; - PathNode(String name, Path path, BasicFileAttributes attrs) { // path + private PathNode(String name, Path path, BasicFileAttributes attrs) { // path super(name, attrs); this.path = path; } - PathNode(String name, Node link) { // link + private PathNode(String name, Node link) { // link super(name, link.getFileAttributes()); this.link = (PathNode)link; } - PathNode(String name, List children) { // dir + private PathNode(String name, List children) { // dir super(name, modulesDirAttrs); this.children = children; } + @Override + public boolean isResource() { + return link == null && !getFileAttributes().isDirectory(); + } + @Override public boolean isDirectory() { return children != null || @@ -112,7 +114,7 @@ class ExplodedImage extends SystemImage { return recursive && link.isLink() ? link.resolveLink(true) : link; } - byte[] getContent() throws IOException { + private byte[] getContent() throws IOException { if (!getFileAttributes().isRegularFile()) throw new FileSystemException(getName() + " is not file"); return Files.readAllBytes(path); @@ -126,7 +128,7 @@ class ExplodedImage extends SystemImage { List list = new ArrayList<>(); try (DirectoryStream stream = Files.newDirectoryStream(path)) { for (Path p : stream) { - p = explodedModulesDir.relativize(p); + p = modulesDir.relativize(p); String pName = MODULES + nativeSlashToFrontSlash(p.toString()); Node node = findNode(pName); if (node != null) { // findNode may choose to hide certain files! @@ -152,7 +154,7 @@ class ExplodedImage extends SystemImage { } @Override - public void close() throws IOException { + public synchronized void close() throws IOException { nodes.clear(); } @@ -161,72 +163,76 @@ class ExplodedImage extends SystemImage { return ((PathNode)node).getContent(); } - // find Node for the given Path @Override - public synchronized Node findNode(String str) { - Node node = findModulesNode(str); + public synchronized Node findNode(String name) { + PathNode node = nodes.get(name); if (node != null) { return node; } - // lazily created for paths like /packages///xyz - // For example /packages/java.lang/java.base/java/lang/ - if (str.startsWith(PACKAGES)) { - // pkgEndIdx marks end of part - int pkgEndIdx = str.indexOf('/', PACKAGES_LEN); - if (pkgEndIdx != -1) { - // modEndIdx marks end of part - int modEndIdx = str.indexOf('/', pkgEndIdx + 1); - if (modEndIdx != -1) { - // make sure we have such module link! - // ie., /packages// is valid - Node linkNode = nodes.get(str.substring(0, modEndIdx)); - if (linkNode == null || !linkNode.isLink()) { - return null; - } - // map to "/modules/zyz" path and return that node - // For example, "/modules/java.base/java/lang" for - // "/packages/java.lang/java.base/java/lang". - String mod = MODULES + str.substring(pkgEndIdx + 1); - return findModulesNode(mod); + // If null, this was not the name of "/modules/..." node, and since all + // "/packages/..." nodes were created and cached in advance, the name + // cannot reference a valid node. + Path path = underlyingModulesPath(name); + if (path == null) { + return null; + } + // This can still return null for hidden files. + return createModulesNode(name, path); + } + + /** + * Lazily creates and caches a {@code Node} for the given "/modules/..." name + * and corresponding path to a file or directory. + * + * @param name a resource or directory node name, of the form "/modules/...". + * @param path the path of a file for a resource or directory. + * @return the newly created and cached node, or {@code null} if the given + * path references a file which must be hidden in the node hierarchy. + */ + private Node createModulesNode(String name, Path path) { + assert !nodes.containsKey(name) : "Node must not already exist: " + name; + assert isNonEmptyModulesPath(name) : "Invalid modules name: " + name; + + try { + // We only know if we're creating a resource of directory when we + // look up file attributes, and we only do that once. Thus, we can + // only reject "marker files" here, rather than by inspecting the + // given name string, since it doesn't apply to directories. + BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); + if (attrs.isRegularFile()) { + Path f = path.getFileName(); + if (f.toString().startsWith("_the.")) { + return null; } + } else if (!attrs.isDirectory()) { + return null; } + PathNode node = new PathNode(name, path, attrs); + nodes.put(name, node); + return node; + } catch (IOException x) { + // Since the path reference a file, any errors should not be ignored. + throw new UncheckedIOException(x); + } + } + + /** + * Returns the expected file path for name in the "/modules/..." namespace, + * or {@code null} if the name is not in the "/modules/..." namespace or the + * path does not reference a file. + */ + private Path underlyingModulesPath(String name) { + if (isNonEmptyModulesPath(name)) { + Path path = modulesDir.resolve(frontSlashToNativeSlash(name.substring(MODULES.length()))); + return Files.exists(path) ? path : null; } return null; } - // find a Node for a path that starts like "/modules/..." - Node findModulesNode(String str) { - PathNode node = nodes.get(str); - if (node != null) { - return node; - } - // lazily created "/modules/xyz/abc/" Node - // This is mapped to default file system path "/xyz/abc" - Path p = underlyingPath(str); - if (p != null) { - try { - BasicFileAttributes attrs = Files.readAttributes(p, BasicFileAttributes.class); - if (attrs.isRegularFile()) { - Path f = p.getFileName(); - if (f.toString().startsWith("_the.")) - return null; - } - node = new PathNode(str, p, attrs); - nodes.put(str, node); - return node; - } catch (IOException x) { - // does not exists or unable to determine - } - } - return null; - } - - Path underlyingPath(String str) { - if (str.startsWith(MODULES)) { - str = frontSlashToNativeSlash(str.substring("/modules".length())); - return defaultFS.getPath(explodedModulesDir.toString(), str); - } - return null; + private static boolean isNonEmptyModulesPath(String name) { + // Don't just check the prefix, there must be something after it too + // (otherwise you end up with an empty string after trimming). + return name.startsWith(MODULES) && name.length() > MODULES.length(); } // convert "/" to platform path separator @@ -249,24 +255,21 @@ class ExplodedImage extends SystemImage { // same package prefix may exist in multiple modules. This Map // is filled by walking "jdk modules" directory recursively! Map> packageToModules = new HashMap<>(); - try (DirectoryStream stream = Files.newDirectoryStream(explodedModulesDir)) { + try (DirectoryStream stream = Files.newDirectoryStream(modulesDir)) { for (Path module : stream) { if (Files.isDirectory(module)) { String moduleName = module.getFileName().toString(); // make sure "/modules/" is created - findModulesNode(MODULES + moduleName); + Objects.requireNonNull(createModulesNode(MODULES + moduleName, module)); try (Stream contentsStream = Files.walk(module)) { contentsStream.filter(Files::isDirectory).forEach((p) -> { p = module.relativize(p); String pkgName = slashesToDots(p.toString()); // skip META-INF and empty strings if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) { - List moduleNames = packageToModules.get(pkgName); - if (moduleNames == null) { - moduleNames = new ArrayList<>(); - packageToModules.put(pkgName, moduleNames); - } - moduleNames.add(moduleName); + packageToModules + .computeIfAbsent(pkgName, k -> new ArrayList<>()) + .add(moduleName); } }); } @@ -275,8 +278,8 @@ class ExplodedImage extends SystemImage { } // create "/modules" directory // "nodes" map contains only /modules/ nodes only so far and so add all as children of /modules - PathNode modulesDir = new PathNode("/modules", new ArrayList<>(nodes.values())); - nodes.put(modulesDir.getName(), modulesDir); + PathNode modulesRootNode = new PathNode("/modules", new ArrayList<>(nodes.values())); + nodes.put(modulesRootNode.getName(), modulesRootNode); // create children under "/packages" List packagesChildren = new ArrayList<>(packageToModules.size()); @@ -285,7 +288,7 @@ class ExplodedImage extends SystemImage { List moduleNameList = entry.getValue(); List moduleLinkNodes = new ArrayList<>(moduleNameList.size()); for (String moduleName : moduleNameList) { - Node moduleNode = findModulesNode(MODULES + moduleName); + Node moduleNode = Objects.requireNonNull(nodes.get(MODULES + moduleName)); PathNode linkNode = new PathNode(PACKAGES + pkgName + "/" + moduleName, moduleNode); nodes.put(linkNode.getName(), linkNode); moduleLinkNodes.add(linkNode); @@ -295,13 +298,13 @@ class ExplodedImage extends SystemImage { packagesChildren.add(pkgDir); } // "/packages" dir - PathNode packagesDir = new PathNode("/packages", packagesChildren); - nodes.put(packagesDir.getName(), packagesDir); + PathNode packagesRootNode = new PathNode("/packages", packagesChildren); + nodes.put(packagesRootNode.getName(), packagesRootNode); // finally "/" dir! List rootChildren = new ArrayList<>(); - rootChildren.add(packagesDir); - rootChildren.add(modulesDir); + rootChildren.add(packagesRootNode); + rootChildren.add(modulesRootNode); PathNode root = new PathNode("/", rootChildren); nodes.put(root.getName(), root); } diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java index 6813c7e627f..b38e953a5f9 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java @@ -78,13 +78,13 @@ abstract class SystemImage { return new ExplodedImage(explodedModulesDir); } - static final String RUNTIME_HOME; + private static final String RUNTIME_HOME; // "modules" jimage file Path - static final Path moduleImageFile; + private static final Path moduleImageFile; // "modules" jimage exists or not? - static final boolean modulesImageExists; + private static final boolean modulesImageExists; // /modules directory Path - static final Path explodedModulesDir; + private static final Path explodedModulesDir; static { PrivilegedAction pa = SystemImage::findHome; diff --git a/test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java b/test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java new file mode 100644 index 00000000000..884024454d4 --- /dev/null +++ b/test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 Whitebox tests for ExplodedImage to ensure compatibility with ImageReader. + * @modules java.base/jdk.internal.jrtfs java.base/jdk.internal.jimage + * @run junit/othervm java.base/jdk.internal.jrtfs.ExplodedImageTest + */ +public class ExplodedImageTestDriver {} \ No newline at end of file diff --git a/test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties b/test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties new file mode 100644 index 00000000000..6e60bee4991 --- /dev/null +++ b/test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties @@ -0,0 +1,4 @@ +modules = \ + java.base/jdk.internal.jimage \ + java.base/jdk.internal.jrtfs +bootclasspath.dirs=. diff --git a/test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java b/test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java new file mode 100644 index 00000000000..c63e163467b --- /dev/null +++ b/test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.internal.jrtfs; + +import jdk.internal.jimage.ImageReader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests an {@link ExplodedImage} view of a class-file hierarchy. + * + *

          For simplicity and performance, only a subset of the JRT files are copied + * to disk for testing. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ExplodedImageTest { + + private Path modulesRoot; + private SystemImage explodedImage; + private String pathSeparator; + + @BeforeAll + public void createTestDirectory(@TempDir Path modulesRoot) throws IOException { + this.modulesRoot = modulesRoot; + this.pathSeparator = modulesRoot.getFileSystem().getSeparator(); + // Copy only a useful subset of files for testing. Use at least two + // modules with "overlapping" packages to test /package links better. + unpackModulesDirectoriesFromJrtFileSystem(modulesRoot, + "java.base/java/util", + "java.base/java/util/zip", + "java.logging/java/util/logging"); + this.explodedImage = new ExplodedImage(modulesRoot); + } + + /** Unpacks a list of "/modules/..." directories non-recursively into the specified root directory. */ + private static void unpackModulesDirectoriesFromJrtFileSystem(Path modulesRoot, String... dirNames) + throws IOException { + FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/")); + List srcDirs = Arrays.stream(dirNames).map(s -> "/modules/" + s).map(jrtfs::getPath).toList(); + for (Path srcDir : srcDirs) { + // Skip-1 to remove "modules" segment (not part of the file system path). + Path dstDir = StreamSupport.stream(srcDir.spliterator(), false) + .skip(1) + .reduce(modulesRoot, (path, segment) -> path.resolve(segment.toString())); + Files.createDirectories(dstDir); + try (DirectoryStream files = Files.newDirectoryStream(srcDir)) { + for (Path srcFile : files) { + Files.copy(srcFile, dstDir.resolve(srcFile.getFileName().toString())); + } + } + } + } + + @Test + public void topLevelNodes() throws IOException { + ImageReader.Node root = explodedImage.findNode("/"); + ImageReader.Node modules = explodedImage.findNode("/modules"); + ImageReader.Node packages = explodedImage.findNode("/packages"); + assertEquals( + Set.of(modules.getName(), packages.getName()), + root.getChildNames().collect(Collectors.toSet())); + } + + @ParameterizedTest + @ValueSource(strings = { + "/modules/java.base/java/util/List.class", + "/modules/java.base/java/util/zip/ZipEntry.class", + "/modules/java.logging/java/util/logging/Logger.class"}) + public void basicLookupResource(String expectedResourceName) throws IOException { + ImageReader.Node node = assertResourceNode(expectedResourceName); + + Path fsRelPath = getRelativePath(expectedResourceName); + assertArrayEquals( + Files.readAllBytes(modulesRoot.resolve(fsRelPath)), + explodedImage.getResource(node)); + } + + @ParameterizedTest + @ValueSource(strings = { + "/modules/java.base", + "/modules/java.logging", + "/modules/java.base/java", + "/modules/java.base/java/util", + "/modules/java.logging/java/util", + }) + public void basicLookupDirectory(String expectedDirectoryName) throws IOException { + ImageReader.Node node = assertDirectoryNode(expectedDirectoryName); + + Path fsRelPath = getRelativePath(expectedDirectoryName); + List fsChildBaseNames; + try (DirectoryStream paths = Files.newDirectoryStream(modulesRoot.resolve(fsRelPath))) { + fsChildBaseNames = StreamSupport.stream(paths.spliterator(), false) + .map(Path::getFileName) + .map(Path::toString) + .toList(); + } + List nodeChildBaseNames = node.getChildNames() + .map(s -> s.substring(node.getName().length() + 1)) + .toList(); + assertEquals(fsChildBaseNames, nodeChildBaseNames, "expected same child names"); + } + + @ParameterizedTest + @ValueSource(strings = { + "/packages/java/java.base", + "/packages/java/java.logging", + "/packages/java.util/java.base", + "/packages/java.util/java.logging", + "/packages/java.util.zip/java.base"}) + public void basicLookupPackageLinks(String expectedLinkName) throws IOException { + ImageReader.Node node = assertLinkNode(expectedLinkName); + ImageReader.Node resolved = node.resolveLink(); + assertSame(explodedImage.findNode(resolved.getName()), resolved); + String moduleName = expectedLinkName.substring(expectedLinkName.lastIndexOf('/') + 1); + assertEquals("/modules/" + moduleName, resolved.getName()); + } + + @ParameterizedTest + @ValueSource(strings = { + "/packages/java", + "/packages/java.util", + "/packages/java.util.zip"}) + public void packageDirectories(String expectedDirectoryName) throws IOException { + ImageReader.Node node = assertDirectoryNode(expectedDirectoryName); + assertTrue(node.getChildNames().findFirst().isPresent(), + "Package directories should not be empty: " + node); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + ".", + "/.", + "modules", + "packages", + "/modules/", + "/modules/xxxx", + "/modules/java.base/java/lang/Xxxx.class", + "/packages/", + "/packages/xxxx", + "/packages/java.xxxx", + "/packages/java.util.", + // Mismatched module. + "/packages/java.util.logging/java.base", + "/packages/java.util.zip/java.logging", + // Links are not resolved as they are fetched (old/broken behaviour). + "/packages/java.util/java.base/java/util/Vector.class", + }) + public void invalidNames(String invalidName) throws IOException { + assertNull(explodedImage.findNode(invalidName), "No node expected for: " + invalidName); + } + + private ImageReader.Node assertResourceNode(String name) throws IOException { + ImageReader.Node node = explodedImage.findNode(name); + assertNotNull(node); + assertEquals(name, node.getName(), "expected node name: " + name); + assertTrue(node.isResource(), "expected a resource: " + node); + assertFalse(node.isDirectory(), "resources are not directories: " + node); + assertFalse(node.isLink(), "resources are not links: " + node); + return node; + } + + private ImageReader.Node assertDirectoryNode(String name) throws IOException { + ImageReader.Node node = explodedImage.findNode(name); + assertNotNull(node); + assertEquals(name, node.getName(), "expected node name: " + name); + assertTrue(node.isDirectory(), "expected a directory: " + node); + assertFalse(node.isResource(), "directories are not resources: " + node); + assertFalse(node.isLink(), "directories are not links: " + node); + return node; + } + + private ImageReader.Node assertLinkNode(String name) throws IOException { + ImageReader.Node node = explodedImage.findNode(name); + assertNotNull(node); + assertEquals(name, node.getName(), "expected node name: " + name); + assertTrue(node.isLink(), "expected a link: " + node); + assertFalse(node.isResource(), "links are not resources: " + node); + assertFalse(node.isDirectory(), "links are not directories: " + node); + return node; + } + + private Path getRelativePath(String name) { + return Path.of(name.substring("/modules/".length()).replace("/", pathSeparator)); + } +} From 79a1a98cabb579a5de504144abacb386486fba7e Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 16:19:35 +0000 Subject: [PATCH 135/295] 8366498: Simplify ClassFileParser::parse_super_class Reviewed-by: dholmes, coleenp --- .../share/classfile/classFileParser.cpp | 44 ++++++++----------- .../share/classfile/classFileParser.hpp | 8 ++-- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 6c019f7c612..617110203cd 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -3803,39 +3803,30 @@ AnnotationArray* ClassFileParser::allocate_annotations(const u1* const anno, return annotations; } -const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp, - const int super_class_index, - const bool need_verify, - TRAPS) { +void ClassFileParser::check_super_class(ConstantPool* const cp, + const int super_class_index, + const bool need_verify, + TRAPS) { assert(cp != nullptr, "invariant"); - const InstanceKlass* super_klass = nullptr; if (super_class_index == 0) { guarantee_property(_class_name == vmSymbols::java_lang_Object(), "Invalid superclass index %u in class file %s", super_class_index, - CHECK_NULL); + CHECK); } else { guarantee_property(valid_klass_reference_at(super_class_index), "Invalid superclass index %u in class file %s", super_class_index, - CHECK_NULL); + CHECK); + // The class name should be legal because it is checked when parsing constant pool. // However, make sure it is not an array type. - bool is_array = false; - if (cp->tag_at(super_class_index).is_klass()) { - super_klass = InstanceKlass::cast(cp->resolved_klass_at(super_class_index)); - if (need_verify) - is_array = super_klass->is_array_klass(); - } else if (need_verify) { - is_array = (cp->klass_name_at(super_class_index)->char_at(0) == JVM_SIGNATURE_ARRAY); - } if (need_verify) { - guarantee_property(!is_array, - "Bad superclass name in class file %s", CHECK_NULL); + guarantee_property(cp->klass_name_at(super_class_index)->char_at(0) != JVM_SIGNATURE_ARRAY, + "Bad superclass name in class file %s", CHECK); } } - return super_klass; } OopMapBlocksBuilder::OopMapBlocksBuilder(unsigned int max_blocks) { @@ -5667,10 +5658,10 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, // SUPERKLASS _super_class_index = stream->get_u2_fast(); - _super_klass = parse_super_class(cp, - _super_class_index, - _need_verify, - CHECK); + check_super_class(cp, + _super_class_index, + _need_verify, + CHECK); // Interfaces _itfs_len = stream->get_u2_fast(); @@ -5773,12 +5764,14 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st assert(_loader_data != nullptr, "invariant"); if (_class_name == vmSymbols::java_lang_Object()) { + precond(_super_class_index == 0); + precond(_super_klass == nullptr); guarantee_property(_local_interfaces == Universe::the_empty_instance_klass_array(), "java.lang.Object cannot implement an interface in class file %s", CHECK); - } - // We check super class after class file is parsed and format is checked - if (_super_class_index > 0 && nullptr == _super_klass) { + } else { + // Set _super_klass after class file is parsed and format is checked + assert(_super_class_index > 0, "any class other than Object must have a super class"); Symbol* const super_class_name = cp->klass_name_at(_super_class_index); if (_access_flags.is_interface()) { // Before attempting to resolve the superclass, check for class format @@ -5789,6 +5782,7 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st } Handle loader(THREAD, _loader_data->class_loader()); if (loader.is_null() && super_class_name == vmSymbols::java_lang_Object()) { + // fast path to avoid lookup _super_klass = vmClasses::Object_klass(); } else { _super_klass = (const InstanceKlass*) diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 2f5a1aef39f..e46dd4580bf 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -242,10 +242,10 @@ class ClassFileParser { bool* has_nonstatic_concrete_methods, TRAPS); - const InstanceKlass* parse_super_class(ConstantPool* const cp, - const int super_class_index, - const bool need_verify, - TRAPS); + void check_super_class(ConstantPool* const cp, + const int super_class_index, + const bool need_verify, + TRAPS); // Field parsing void parse_field_attributes(const ClassFileStream* const cfs, From f90d520308d5fa72497dc59bee7258931c2a3d95 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 16:23:46 +0000 Subject: [PATCH 136/295] 8366475: Rename MetaspaceShared class to AOTMetaspace Reviewed-by: kvn, asmehra --- src/hotspot/os/posix/vmError_posix.cpp | 4 +- src/hotspot/os/windows/vmError_windows.cpp | 4 +- .../bsd_aarch64/javaThread_bsd_aarch64.cpp | 2 +- src/hotspot/share/cds/aotCacheAccess.cpp | 4 +- src/hotspot/share/cds/aotClassLocation.cpp | 8 +- .../share/cds/aotLinkedClassBulkLoader.cpp | 2 +- src/hotspot/share/cds/aotMapLogger.cpp | 6 +- .../{metaspaceShared.cpp => aotMetaspace.cpp} | 166 +++++++++--------- .../{metaspaceShared.hpp => aotMetaspace.hpp} | 12 +- .../share/cds/aotReferenceObjSupport.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 38 ++-- src/hotspot/share/cds/archiveHeapLoader.cpp | 14 +- src/hotspot/share/cds/archiveUtils.cpp | 14 +- src/hotspot/share/cds/archiveUtils.inline.hpp | 4 +- src/hotspot/share/cds/cdsConfig.cpp | 2 +- src/hotspot/share/cds/cdsHeapVerifier.cpp | 2 +- src/hotspot/share/cds/cdsProtectionDomain.cpp | 2 +- src/hotspot/share/cds/classListParser.cpp | 6 +- src/hotspot/share/cds/cppVtables.cpp | 4 +- src/hotspot/share/cds/dumpTimeClassInfo.hpp | 4 +- src/hotspot/share/cds/dynamicArchive.cpp | 22 +-- src/hotspot/share/cds/dynamicArchive.hpp | 2 +- src/hotspot/share/cds/filemap.cpp | 164 ++++++++--------- src/hotspot/share/cds/filemap.hpp | 4 +- src/hotspot/share/cds/finalImageRecipes.cpp | 4 +- src/hotspot/share/cds/heapShared.cpp | 10 +- src/hotspot/share/cds/heapShared.hpp | 4 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 +- .../share/cds/lambdaProxyClassDictionary.hpp | 2 +- src/hotspot/share/cds/runTimeClassInfo.cpp | 2 +- src/hotspot/share/cds/runTimeClassInfo.hpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 2 +- src/hotspot/share/classfile/modules.cpp | 10 +- src/hotspot/share/classfile/stringTable.cpp | 2 +- src/hotspot/share/classfile/symbolTable.cpp | 4 +- .../share/classfile/systemDictionary.cpp | 2 +- .../classfile/systemDictionaryShared.cpp | 10 +- src/hotspot/share/code/aotCodeCache.cpp | 6 +- src/hotspot/share/include/cds.h | 4 +- .../share/interpreter/abstractInterpreter.cpp | 2 +- src/hotspot/share/interpreter/rewriter.cpp | 2 +- src/hotspot/share/memory/metaspace.cpp | 10 +- src/hotspot/share/memory/metaspace.hpp | 4 +- src/hotspot/share/memory/universe.cpp | 8 +- src/hotspot/share/memory/universe.hpp | 4 +- src/hotspot/share/oops/arrayKlass.cpp | 6 +- src/hotspot/share/oops/instanceKlass.cpp | 10 +- src/hotspot/share/oops/klassVtable.cpp | 8 +- src/hotspot/share/oops/method.cpp | 6 +- src/hotspot/share/oops/symbol.cpp | 1 - src/hotspot/share/oops/trainingData.cpp | 1 - src/hotspot/share/prims/jvm.cpp | 3 +- .../share/prims/jvmtiRedefineClasses.cpp | 4 +- src/hotspot/share/prims/whitebox.cpp | 10 +- src/hotspot/share/runtime/java.cpp | 3 +- src/hotspot/share/runtime/threads.cpp | 6 +- src/hotspot/share/utilities/vmError.cpp | 6 +- .../runtime/cds/SpaceUtilizationCheck.java | 4 +- .../cds/appcds/SharedArchiveConsistency.java | 2 +- .../lib/jdk/test/lib/cds/CDSArchiveUtils.java | 4 +- 60 files changed, 332 insertions(+), 332 deletions(-) rename src/hotspot/share/cds/{metaspaceShared.cpp => aotMetaspace.cpp} (93%) rename src/hotspot/share/cds/{metaspaceShared.hpp => aotMetaspace.hpp} (97%) diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp index 4bfd8efabe8..81eeea6c168 100644 --- a/src/hotspot/os/posix/vmError_posix.cpp +++ b/src/hotspot/os/posix/vmError_posix.cpp @@ -23,8 +23,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "os_posix.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" @@ -117,7 +117,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { if (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) { const void* const fault_addr = si->si_addr; if (fault_addr != nullptr) { - if (MetaspaceShared::in_aot_cache(fault_addr)) { + if (AOTMetaspace::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/os/windows/vmError_windows.cpp b/src/hotspot/os/windows/vmError_windows.cpp index fbd91309822..22df4d82cbf 100644 --- a/src/hotspot/os/windows/vmError_windows.cpp +++ b/src/hotspot/os/windows/vmError_windows.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "runtime/arguments.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" @@ -51,7 +51,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { er->NumberParameters >= 2) { const void* const fault_addr = (const void*) er->ExceptionInformation[1]; if (fault_addr != nullptr) { - if (MetaspaceShared::in_aot_cache(fault_addr)) { + if (AOTMetaspace::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp index fa40ef2b8f1..982605bbed4 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp @@ -24,7 +24,7 @@ * */ -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/cds/aotCacheAccess.cpp b/src/hotspot/share/cds/aotCacheAccess.cpp index b6c4a201da5..117979f41b5 100644 --- a/src/hotspot/share/cds/aotCacheAccess.cpp +++ b/src/hotspot/share/cds/aotCacheAccess.cpp @@ -23,11 +23,11 @@ */ #include "cds/aotCacheAccess.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/stringTable.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -45,7 +45,7 @@ size_t AOTCacheAccess::get_aot_code_region_size() { assert(CDSConfig::is_using_archive(), "must be"); FileMapInfo* mapinfo = FileMapInfo::current_info(); assert(mapinfo != nullptr, "must be"); - return mapinfo->region_at(MetaspaceShared::ac)->used_aligned(); + return mapinfo->region_at(AOTMetaspace::ac)->used_aligned(); } bool AOTCacheAccess::map_aot_code_region(ReservedSpace rs) { diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index f04c601ac86..f77aac3540c 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -24,11 +24,11 @@ #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" #include "cds/filemap.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/serializeClosure.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" @@ -246,7 +246,7 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa type = FileType::NOT_EXIST; } else { aot_log_error(aot)("Unable to open file %s.", path); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } ResourceMark rm(current); @@ -1028,10 +1028,10 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l vm_exit_during_initialization("Unable to use create AOT cache.", nullptr); } else { aot_log_error(aot)("%s%s", mismatch_msg, hint_msg); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } } else { - MetaspaceShared::report_loading_error("%s%s", mismatch_msg, hint_msg); + AOTMetaspace::report_loading_error("%s%s", mismatch_msg, hint_msg); } } return success; diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 99d7c26b293..11848b88300 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -221,7 +221,7 @@ void AOTLinkedClassBulkLoader::load_classes_impl(AOTLinkedClassCategory class_ca log_error(aot)("Unable to resolve %s class from %s: %s", category_name, CDSConfig::type_of_archive_being_loaded(), ik->external_name()); log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); log_error(aot)("JVMTI class retransformation is not supported when archive was generated with -XX:+AOTClassLinking."); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } assert(actual->is_loaded(), "must be"); } diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index 712901a71ca..a15d7f670d4 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -218,8 +218,8 @@ void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* r } void AOTMapLogger::runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap* objs) { - FileMapRegion* rw = mapinfo->region_at(MetaspaceShared::rw); - FileMapRegion* ro = mapinfo->region_at(MetaspaceShared::ro); + FileMapRegion* rw = mapinfo->region_at(AOTMetaspace::rw); + FileMapRegion* ro = mapinfo->region_at(AOTMetaspace::ro); address rw_base = address(rw->mapped_base()); address rw_end = address(rw->mapped_end()); @@ -782,7 +782,7 @@ void AOTMapLogger::dumptime_log_heap_region(ArchiveHeapInfo* heap_info) { void AOTMapLogger::runtime_log_heap_region(FileMapInfo* mapinfo) { ResourceMark rm; - int heap_region_index = MetaspaceShared::hp; + int heap_region_index = AOTMetaspace::hp; FileMapRegion* r = mapinfo->region_at(heap_region_index); size_t alignment = ObjectAlignmentInBytes; diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/aotMetaspace.cpp similarity index 93% rename from src/hotspot/share/cds/metaspaceShared.cpp rename to src/hotspot/share/cds/aotMetaspace.cpp index 92773c5be90..c2d9d0193f5 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -30,6 +30,7 @@ #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" #include "cds/aotMapLogger.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" @@ -47,7 +48,6 @@ #include "cds/heapShared.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderDataShared.hpp" #include "classfile/javaClasses.inline.hpp" @@ -104,15 +104,15 @@ #include -ReservedSpace MetaspaceShared::_symbol_rs; -VirtualSpace MetaspaceShared::_symbol_vs; -bool MetaspaceShared::_archive_loading_failed = false; -bool MetaspaceShared::_remapped_readwrite = false; -void* MetaspaceShared::_aot_metaspace_static_top = nullptr; -intx MetaspaceShared::_relocation_delta; -char* MetaspaceShared::_requested_base_address; -Array* MetaspaceShared::_archived_method_handle_intrinsics = nullptr; -bool MetaspaceShared::_use_optimized_module_handling = true; +ReservedSpace AOTMetaspace::_symbol_rs; +VirtualSpace AOTMetaspace::_symbol_vs; +bool AOTMetaspace::_archive_loading_failed = false; +bool AOTMetaspace::_remapped_readwrite = false; +void* AOTMetaspace::_aot_metaspace_static_top = nullptr; +intx AOTMetaspace::_relocation_delta; +char* AOTMetaspace::_requested_base_address; +Array* AOTMetaspace::_archived_method_handle_intrinsics = nullptr; +bool AOTMetaspace::_use_optimized_module_handling = true; // The CDS archive is divided into the following regions: // rw - read-write metadata @@ -121,10 +121,10 @@ bool MetaspaceShared::_use_optimized_module_handling = true; // bm - bitmap for relocating the above 7 regions. // // The rw and ro regions are linearly allocated, in the order of rw->ro. -// These regions are aligned with MetaspaceShared::core_region_alignment(). +// These regions are aligned with AOTMetaspace::core_region_alignment(). // // These 2 regions are populated in the following steps: -// [0] All classes are loaded in MetaspaceShared::preload_classes(). All metadata are +// [0] All classes are loaded in AOTMetaspace::preload_classes(). All metadata are // temporarily allocated outside of the shared regions. // [1] We enter a safepoint and allocate a buffer for the rw/ro regions. // [2] C++ vtables are copied into the rw region. @@ -139,7 +139,7 @@ bool MetaspaceShared::_use_optimized_module_handling = true; static DumpRegion _symbol_region("symbols"); -char* MetaspaceShared::symbol_space_alloc(size_t num_bytes) { +char* AOTMetaspace::symbol_space_alloc(size_t num_bytes) { return _symbol_region.allocate(num_bytes); } @@ -152,11 +152,11 @@ char* MetaspaceShared::symbol_space_alloc(size_t num_bytes) { // Upon successful configuration, the compactible alignment then can be defined in: // os_linux_aarch64.cpp // os_bsd_x86.cpp -size_t MetaspaceShared::core_region_alignment() { +size_t AOTMetaspace::core_region_alignment() { return os::cds_core_region_alignment(); } -size_t MetaspaceShared::protection_zone_size() { +size_t AOTMetaspace::protection_zone_size() { return os::cds_core_region_alignment(); } @@ -217,7 +217,7 @@ public: } }; -void MetaspaceShared::dump_loaded_classes(const char* file_name, TRAPS) { +void AOTMetaspace::dump_loaded_classes(const char* file_name, TRAPS) { fileStream stream(file_name, "w"); if (stream.is_open()) { MutexLocker lock(ClassLoaderDataGraph_lock); @@ -245,7 +245,7 @@ static bool shared_base_too_high(char* specified_base, char* aligned_base, size_ static char* compute_shared_base(size_t cds_max) { char* specified_base = (char*)SharedBaseAddress; - size_t alignment = MetaspaceShared::core_region_alignment(); + size_t alignment = AOTMetaspace::core_region_alignment(); if (UseCompressedClassPointers && CompressedKlassPointers::needs_class_space()) { alignment = MAX2(alignment, Metaspace::reserve_alignment()); } @@ -291,7 +291,7 @@ static char* compute_shared_base(size_t cds_max) { return aligned_base; } -void MetaspaceShared::initialize_for_static_dump() { +void AOTMetaspace::initialize_for_static_dump() { assert(CDSConfig::is_dumping_static_archive(), "sanity"); aot_log_info(aot)("Core region alignment: %zu", core_region_alignment()); // The max allowed size for CDS archive. We use this to limit SharedBaseAddress @@ -318,13 +318,13 @@ void MetaspaceShared::initialize_for_static_dump() { mtClassShared); if (!_symbol_rs.is_reserved()) { aot_log_error(aot)("Unable to reserve memory for symbols: %zu bytes.", symbol_rs_size); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } _symbol_region.init(&_symbol_rs, &_symbol_vs); } // Called by universe_post_init() -void MetaspaceShared::post_initialize(TRAPS) { +void AOTMetaspace::post_initialize(TRAPS) { if (CDSConfig::is_using_archive()) { FileMapInfo *static_mapinfo = FileMapInfo::current_info(); FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); @@ -337,11 +337,11 @@ void MetaspaceShared::post_initialize(TRAPS) { // Close any open file descriptors. However, mmap'ed pages will remain in memory. static_mapinfo->close(); - static_mapinfo->unmap_region(MetaspaceShared::bm); + static_mapinfo->unmap_region(AOTMetaspace::bm); if (dynamic_mapinfo != nullptr) { dynamic_mapinfo->close(); - dynamic_mapinfo->unmap_region(MetaspaceShared::bm); + dynamic_mapinfo->unmap_region(AOTMetaspace::bm); } int size = AOTClassLocationConfig::runtime()->length(); @@ -358,7 +358,7 @@ static GrowableArrayCHeap* _extra_symbols = nullptr; // Methods managed by SystemDictionary::find_method_handle_intrinsic() to be added to the archive static GrowableArray* _pending_method_handle_intrinsics = nullptr; -void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) { +void AOTMetaspace::read_extra_data(JavaThread* current, const char* filename) { _extra_interned_strings = new GrowableArrayCHeap(10000); _extra_symbols = new GrowableArrayCHeap(1000); @@ -372,7 +372,7 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) if (utf8_length == 0x7fffffff) { // buf_len will overflown 32-bit value. aot_log_error(aot)("string length too large: %d", utf8_length); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } int buf_len = utf8_length+1; char* utf8_buffer = NEW_RESOURCE_ARRAY(char, buf_len); @@ -407,7 +407,7 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) } } -void MetaspaceShared::make_method_handle_intrinsics_shareable() { +void AOTMetaspace::make_method_handle_intrinsics_shareable() { for (int i = 0; i < _pending_method_handle_intrinsics->length(); i++) { Method* m = ArchiveBuilder::current()->get_buffered_addr(_pending_method_handle_intrinsics->at(i)); m->remove_unshareable_info(); @@ -416,7 +416,7 @@ void MetaspaceShared::make_method_handle_intrinsics_shareable() { } } -void MetaspaceShared::write_method_handle_intrinsics() { +void AOTMetaspace::write_method_handle_intrinsics() { int len = _pending_method_handle_intrinsics->length(); _archived_method_handle_intrinsics = ArchiveBuilder::new_ro_array(len); int word_size = _archived_method_handle_intrinsics->size(); @@ -452,23 +452,23 @@ void MetaspaceShared::write_method_handle_intrinsics() { // Some of the xxx::serialize() functions may have side effects and assume that // the archive is already mapped. For example, SymbolTable::serialize_shared_table_header() // unconditionally makes the set of archived symbols available. Therefore, we put most -// of these xxx::serialize() functions inside MetaspaceShared::serialize(), which +// of these xxx::serialize() functions inside AOTMetaspace::serialize(), which // is called AFTER we made the decision to map the archive. // // However, some of the "serialized" data are used to decide whether an archive should // be mapped or not (e.g., for checking if the -Djdk.module.main property is compatible // with the archive). The xxx::serialize() functions for these data must be put inside -// MetaspaceShared::early_serialize(). Such functions must not produce side effects that +// AOTMetaspace::early_serialize(). Such functions must not produce side effects that // assume we will always decides to map the archive. -void MetaspaceShared::early_serialize(SerializeClosure* soc) { +void AOTMetaspace::early_serialize(SerializeClosure* soc) { int tag = 0; soc->do_tag(--tag); CDS_JAVA_HEAP_ONLY(Modules::serialize_archived_module_info(soc);) soc->do_tag(666); } -void MetaspaceShared::serialize(SerializeClosure* soc) { +void AOTMetaspace::serialize(SerializeClosure* soc) { int tag = 0; soc->do_tag(--tag); @@ -541,7 +541,7 @@ static void rewrite_nofast_bytecode(const methodHandle& method) { // [1] Rewrite all bytecodes as needed, so that the ConstMethod* will not be modified // at run time by RewriteBytecodes/RewriteFrequentPairs // [2] Assign a fingerprint, so one doesn't need to be assigned at run-time. -void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) { +void AOTMetaspace::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) { for (int i = 0; i < ik->methods()->length(); i++) { methodHandle m(thread, ik->methods()->at(i)); if (ik->can_be_verified_at_dumptime() && ik->is_linked()) { @@ -617,7 +617,7 @@ char* VM_PopulateDumpSharedSpace::dump_early_read_only_tables() { DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); WriteClosure wc(ro_region); - MetaspaceShared::early_serialize(&wc); + AOTMetaspace::early_serialize(&wc); return start; } @@ -633,7 +633,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& TrainingData::dump_training_data(); - MetaspaceShared::write_method_handle_intrinsics(); + AOTMetaspace::write_method_handle_intrinsics(); // Write lambform lines into archive LambdaFormInvokers::dump_static_archive_invokers(); @@ -646,7 +646,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); WriteClosure wc(ro_region); - MetaspaceShared::serialize(&wc); + AOTMetaspace::serialize(&wc); return start; } @@ -684,7 +684,7 @@ void VM_PopulateDumpSharedSpace::doit() { log_info(aot)("Make classes shareable"); _builder.make_klasses_shareable(); - MetaspaceShared::make_method_handle_intrinsics_shareable(); + AOTMetaspace::make_method_handle_intrinsics_shareable(); dump_java_heap_objects(); dump_shared_symbol_table(_builder.symbols()); @@ -712,7 +712,7 @@ void VM_PopulateDumpSharedSpace::doit() { const char* static_archive = CDSConfig::output_archive_path(); assert(static_archive != nullptr, "sanity"); _map_info = new FileMapInfo(static_archive, true); - _map_info->populate_header(MetaspaceShared::core_region_alignment()); + _map_info->populate_header(AOTMetaspace::core_region_alignment()); _map_info->set_early_serialized_data(early_serialized_data); _map_info->set_serialized_data(serialized_data); _map_info->set_cloned_vtables(CppVtables::vtables_serialized_base()); @@ -754,7 +754,7 @@ public: // Check if we can eagerly link this class at dump time, so we can avoid the // runtime linking overhead (especially verification) -bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) { +bool AOTMetaspace::may_be_eagerly_linked(InstanceKlass* ik) { if (!ik->can_be_verified_at_dumptime()) { // For old classes, try to leave them in the unlinked state, so // we can still store them in the archive. They must be @@ -773,7 +773,7 @@ bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) { return true; } -void MetaspaceShared::link_shared_classes(TRAPS) { +void AOTMetaspace::link_shared_classes(TRAPS) { AOTClassLinker::initialize(); AOTClassInitializer::init_test_class(CHECK); @@ -816,7 +816,7 @@ void MetaspaceShared::link_shared_classes(TRAPS) { // Preload classes from a list, populate the shared spaces and dump to a // file. -void MetaspaceShared::preload_and_dump(TRAPS) { +void AOTMetaspace::preload_and_dump(TRAPS) { CDSConfig::DumperThreadMark dumper_thread_mark(THREAD); ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -832,12 +832,12 @@ void MetaspaceShared::preload_and_dump(TRAPS) { if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { aot_log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " "%zuM", MaxHeapSize/M); - MetaspaceShared::writing_error(); + AOTMetaspace::writing_error(); } else { oop message = java_lang_Throwable::message(PENDING_EXCEPTION); aot_log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), message == nullptr ? "(null)" : java_lang_String::as_utf8_string(message)); - MetaspaceShared::writing_error(err_msg("Unexpected exception, use -Xlog:aot%s,exceptions=trace for detail", + AOTMetaspace::writing_error(err_msg("Unexpected exception, use -Xlog:aot%s,exceptions=trace for detail", CDSConfig::new_aot_flags_used() ? "" : ",cds")); } } @@ -864,7 +864,7 @@ void MetaspaceShared::preload_and_dump(TRAPS) { } #if INCLUDE_CDS_JAVA_HEAP && defined(_LP64) -void MetaspaceShared::adjust_heap_sizes_for_dumping() { +void AOTMetaspace::adjust_heap_sizes_for_dumping() { if (!CDSConfig::is_dumping_heap() || UseCompressedOops) { return; } @@ -887,13 +887,13 @@ void MetaspaceShared::adjust_heap_sizes_for_dumping() { } #endif // INCLUDE_CDS_JAVA_HEAP && _LP64 -void MetaspaceShared::get_default_classlist(char* default_classlist, const size_t buf_size) { +void AOTMetaspace::get_default_classlist(char* default_classlist, const size_t buf_size) { const char* filesep = os::file_separator(); jio_snprintf(default_classlist, buf_size, "%s%slib%sclasslist", Arguments::get_java_home(), filesep, filesep); } -void MetaspaceShared::preload_classes(TRAPS) { +void AOTMetaspace::preload_classes(TRAPS) { char default_classlist[JVM_MAXPATHLEN]; const char* classlist_path; @@ -928,7 +928,7 @@ void MetaspaceShared::preload_classes(TRAPS) { aot_log_info(aot)("Loading classes to share: done."); } -void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { +void AOTMetaspace::exercise_runtime_cds_code(TRAPS) { // Exercise the manifest processing code const char* dummy = "Manifest-Version: 1.0\n"; CDSProtectionDomain::create_jar_manifest(dummy, strlen(dummy), CHECK); @@ -937,7 +937,7 @@ void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK); } -void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { +void AOTMetaspace::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { if (CDSConfig::is_dumping_classic_static_archive()) { // We are running with -Xshare:dump preload_classes(CHECK); @@ -1058,8 +1058,8 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS } } -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() +bool AOTMetaspace::write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info) { + // relocate the data so that it can be mapped to AOTMetaspace::requested_base_address() // without runtime relocation. builder->relocate_to_requested(); @@ -1177,7 +1177,7 @@ static int exec_jvm_with_java_tool_options(const char* java_launcher_path, TRAPS return result.get_jint(); } -void MetaspaceShared::fork_and_dump_final_static_archive(TRAPS) { +void AOTMetaspace::fork_and_dump_final_static_archive(TRAPS) { assert(CDSConfig::is_dumping_preimage_static_archive(), "sanity"); ResourceMark rm; @@ -1203,7 +1203,7 @@ void MetaspaceShared::fork_and_dump_final_static_archive(TRAPS) { } // Returns true if the class's status has changed. -bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { +bool AOTMetaspace::try_link_class(JavaThread* current, InstanceKlass* ik) { ExceptionMark em(current); JavaThread* THREAD = current; // For exception macros. assert(CDSConfig::is_dumping_archive(), "sanity"); @@ -1252,13 +1252,13 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() { } } -void MetaspaceShared::set_aot_metaspace_range(void* base, void *static_top, void* top) { +void AOTMetaspace::set_aot_metaspace_range(void* base, void *static_top, void* top) { assert(base <= static_top && static_top <= top, "must be"); _aot_metaspace_static_top = static_top; MetaspaceObj::set_aot_metaspace_range(base, top); } -bool MetaspaceShared::in_aot_cache_dynamic_region(void* p) { +bool AOTMetaspace::in_aot_cache_dynamic_region(void* p) { if ((p < MetaspaceObj::aot_metaspace_top()) && (p >= _aot_metaspace_static_top)) { return true; @@ -1267,7 +1267,7 @@ bool MetaspaceShared::in_aot_cache_dynamic_region(void* p) { } } -bool MetaspaceShared::in_aot_cache_static_region(void* p) { +bool AOTMetaspace::in_aot_cache_static_region(void* p) { if (in_aot_cache(p) && !in_aot_cache_dynamic_region(p)) { return true; } else { @@ -1280,7 +1280,7 @@ bool MetaspaceShared::in_aot_cache_static_region(void* p) { // - There's an error that indicates that the archive(s) files were corrupt or otherwise damaged. // - When -XX:+RequireSharedSpaces is specified, AND the JVM cannot load the archive(s) due // to version or classpath mismatch. -void MetaspaceShared::unrecoverable_loading_error(const char* message) { +void AOTMetaspace::unrecoverable_loading_error(const char* message) { report_loading_error("%s", message); if (CDSConfig::is_dumping_final_static_archive()) { @@ -1292,7 +1292,7 @@ void MetaspaceShared::unrecoverable_loading_error(const char* message) { } } -void MetaspaceShared::report_loading_error(const char* format, ...) { +void AOTMetaspace::report_loading_error(const char* format, ...) { // When using AOT cache, errors messages are always printed on the error channel. LogStream ls_aot(LogLevel::Error, LogTagSetMapping::tagset()); @@ -1325,21 +1325,21 @@ void MetaspaceShared::report_loading_error(const char* format, ...) { // 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) { +void AOTMetaspace::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) { +void AOTMetaspace::writing_error(const char* message) { aot_log_error(aot)("An error has occurred while writing the shared archive file."); if (message != nullptr) { aot_log_error(aot)("%s", message); } } -void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { +void AOTMetaspace::initialize_runtime_shared_and_meta_spaces() { assert(CDSConfig::is_using_archive(), "Must be called when UseSharedSpaces is enabled"); MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE; @@ -1385,10 +1385,10 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { AutoCreateSharedArchive = false; CDSConfig::disable_dumping_dynamic_archive(); if (PrintSharedArchiveAndExit) { - MetaspaceShared::unrecoverable_loading_error("Unable to use shared archive."); + AOTMetaspace::unrecoverable_loading_error("Unable to use shared archive."); } else { if (RequireSharedSpaces) { - MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); + AOTMetaspace::unrecoverable_loading_error("Unable to map shared spaces"); } else { report_loading_error("Unable to map shared spaces"); } @@ -1406,11 +1406,11 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { delete dynamic_mapinfo; } if (RequireSharedSpaces && has_failed) { - MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); + AOTMetaspace::unrecoverable_loading_error("Unable to map shared spaces"); } } -FileMapInfo* MetaspaceShared::open_static_archive() { +FileMapInfo* AOTMetaspace::open_static_archive() { const char* static_archive = CDSConfig::input_static_archive_path(); assert(static_archive != nullptr, "sanity"); FileMapInfo* mapinfo = new FileMapInfo(static_archive, true); @@ -1421,7 +1421,7 @@ FileMapInfo* MetaspaceShared::open_static_archive() { return mapinfo; } -FileMapInfo* MetaspaceShared::open_dynamic_archive() { +FileMapInfo* AOTMetaspace::open_dynamic_archive() { if (CDSConfig::is_dumping_dynamic_archive()) { return nullptr; } @@ -1434,7 +1434,7 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { if (!mapinfo->open_as_input()) { delete(mapinfo); if (RequireSharedSpaces) { - MetaspaceShared::unrecoverable_loading_error("Failed to initialize dynamic archive"); + AOTMetaspace::unrecoverable_loading_error("Failed to initialize dynamic archive"); } return nullptr; } @@ -1444,8 +1444,8 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { // use_requested_addr: // true = map at FileMapHeader::_requested_base_address // false = map at an alternative address picked by OS. -MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo, - bool use_requested_addr) { +MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo, + bool use_requested_addr) { if (use_requested_addr && static_mapinfo->requested_base_address() == nullptr) { aot_log_info(aot)("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address."); return MAP_ARCHIVE_MMAP_FAILURE; @@ -1517,7 +1517,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File aot_log_info(aot)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size()); - if (MetaspaceShared::use_windows_memory_mapping()) { + if (AOTMetaspace::use_windows_memory_mapping()) { // We have now reserved address space for the archives, and will map in // the archive files into this space. // @@ -1721,12 +1721,12 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File // covers both spaces. // If UseCompressedClassPointers=0, class_space_rs remains unreserved. // - On error: null is returned and the spaces remain unreserved. -char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_mapinfo, - FileMapInfo* dynamic_mapinfo, - bool use_archive_base_addr, - ReservedSpace& total_space_rs, - ReservedSpace& archive_space_rs, - ReservedSpace& class_space_rs) { +char* AOTMetaspace::reserve_address_space_for_archives(FileMapInfo* static_mapinfo, + FileMapInfo* dynamic_mapinfo, + bool use_archive_base_addr, + ReservedSpace& total_space_rs, + ReservedSpace& archive_space_rs, + ReservedSpace& class_space_rs) { address const base_address = (address) (use_archive_base_addr ? static_mapinfo->requested_base_address() : nullptr); const size_t archive_space_alignment = core_region_alignment(); @@ -1879,9 +1879,9 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma } -void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs, - ReservedSpace& archive_space_rs, - ReservedSpace& class_space_rs) { +void AOTMetaspace::release_reserved_spaces(ReservedSpace& total_space_rs, + ReservedSpace& archive_space_rs, + ReservedSpace& class_space_rs) { if (total_space_rs.is_reserved()) { aot_log_debug(aot)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base())); MemoryReserver::release(total_space_rs); @@ -1900,10 +1900,10 @@ void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs, } } -static int archive_regions[] = { MetaspaceShared::rw, MetaspaceShared::ro }; +static int archive_regions[] = { AOTMetaspace::rw, AOTMetaspace::ro }; static int archive_regions_count = 2; -MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) { +MapArchiveResult AOTMetaspace::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) { assert(CDSConfig::is_using_archive(), "must be runtime"); if (mapinfo == nullptr) { return MAP_ARCHIVE_SUCCESS; // The dynamic archive has not been specified. No error has happened -- trivially succeeded. @@ -1946,11 +1946,11 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped return MAP_ARCHIVE_SUCCESS; } -void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) { +void AOTMetaspace::unmap_archive(FileMapInfo* mapinfo) { assert(CDSConfig::is_using_archive(), "must be runtime"); if (mapinfo != nullptr) { mapinfo->unmap_regions(archive_regions, archive_regions_count); - mapinfo->unmap_region(MetaspaceShared::bm); + mapinfo->unmap_region(AOTMetaspace::bm); mapinfo->set_is_mapped(false); } } @@ -1971,7 +1971,7 @@ class CountSharedSymbols : public SymbolClosure { // Read the miscellaneous data from the shared file, and // serialize it out to its various destinations. -void MetaspaceShared::initialize_shared_spaces() { +void AOTMetaspace::initialize_shared_spaces() { FileMapInfo *static_mapinfo = FileMapInfo::current_info(); FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); @@ -2052,7 +2052,7 @@ void MetaspaceShared::initialize_shared_spaces() { } // JVM/TI RedefineClasses() support: -bool MetaspaceShared::remap_shared_readonly_as_readwrite() { +bool AOTMetaspace::remap_shared_readonly_as_readwrite() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (CDSConfig::is_using_archive()) { @@ -2072,7 +2072,7 @@ bool MetaspaceShared::remap_shared_readonly_as_readwrite() { return true; } -void MetaspaceShared::print_on(outputStream* st) { +void AOTMetaspace::print_on(outputStream* st) { if (CDSConfig::is_using_archive()) { st->print("CDS archive(s) mapped at: "); address base = (address)MetaspaceObj::aot_metaspace_base(); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/aotMetaspace.hpp similarity index 97% rename from src/hotspot/share/cds/metaspaceShared.hpp rename to src/hotspot/share/cds/aotMetaspace.hpp index 7f0f1128f96..6c0ad37dbf7 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/aotMetaspace.hpp @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_CDS_METASPACESHARED_HPP -#define SHARE_CDS_METASPACESHARED_HPP +#ifndef SHARE_CDS_AOTMETASPACE_HPP +#define SHARE_CDS_AOTMETASPACE_HPP #include "memory/allocation.hpp" #include "memory/memRegion.hpp" @@ -49,7 +49,7 @@ enum MapArchiveResult { }; // Class Data Sharing Support -class MetaspaceShared : AllStatic { +class AOTMetaspace : AllStatic { static ReservedSpace _symbol_rs; // used only during -Xshare:dump static VirtualSpace _symbol_vs; // used only during -Xshare:dump static bool _archive_loading_failed; @@ -63,8 +63,8 @@ class MetaspaceShared : AllStatic { public: enum { // core archive spaces - rw = 0, // read-write shared space - ro = 1, // read-only shared space + rw = 0, // read-write + ro = 1, // read-only bm = 2, // relocation bitmaps (freed after file mapping is finished) hp = 3, // heap region ac = 4, // aot code @@ -202,4 +202,4 @@ private: static void unmap_archive(FileMapInfo* mapinfo); static void get_default_classlist(char* default_classlist, const size_t buf_size); }; -#endif // SHARE_CDS_METASPACESHARED_HPP +#endif // SHARE_CDS_AOTMETASPACE_HPP diff --git a/src/hotspot/share/cds/aotReferenceObjSupport.cpp b/src/hotspot/share/cds/aotReferenceObjSupport.cpp index b43c766b8db..e1598035d15 100644 --- a/src/hotspot/share/cds/aotReferenceObjSupport.cpp +++ b/src/hotspot/share/cds/aotReferenceObjSupport.cpp @@ -209,7 +209,7 @@ bool AOTReferenceObjSupport::check_if_ref_obj(oop obj) { log_error(aot, heap)("%s", (referent == nullptr) ? "referent cannot be null" : "referent is not registered with CDS.keepAlive()"); HeapShared::debug_trace(); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } if (log_is_enabled(Info, aot, ref)) { diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 00aca188f96..7a6c91e503e 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -27,6 +27,7 @@ #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" #include "cds/aotMapLogger.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" @@ -35,7 +36,6 @@ #include "cds/dumpAllocStats.hpp" #include "cds/dynamicArchive.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataShared.hpp" @@ -330,12 +330,12 @@ address ArchiveBuilder::reserve_buffer() { // AOTCodeCache::max_aot_code_size() accounts for aot code region. size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M) + AOTCodeCache::max_aot_code_size(); ReservedSpace rs = MemoryReserver::reserve(buffer_size, - MetaspaceShared::core_region_alignment(), + AOTMetaspace::core_region_alignment(), os::vm_page_size(), mtNone); if (!rs.is_reserved()) { aot_log_error(aot)("Failed to reserve %zu bytes of output buffer.", buffer_size); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when @@ -357,7 +357,7 @@ address ArchiveBuilder::reserve_buffer() { ArchivePtrMarker::initialize(&_ptrmap, &_shared_vs); // The bottom of the static archive should be mapped at this address by default. - _requested_static_archive_bottom = (address)MetaspaceShared::requested_base_address(); + _requested_static_archive_bottom = (address)AOTMetaspace::requested_base_address(); // The bottom of the archive (that I am writing now) should be mapped at this address by default. address my_archive_requested_bottom; @@ -372,7 +372,7 @@ address ArchiveBuilder::reserve_buffer() { // At run time, we will mmap the dynamic archive at my_archive_requested_bottom _requested_static_archive_top = _requested_static_archive_bottom + static_archive_size; - my_archive_requested_bottom = align_up(_requested_static_archive_top, MetaspaceShared::core_region_alignment()); + my_archive_requested_bottom = align_up(_requested_static_archive_top, AOTMetaspace::core_region_alignment()); _requested_dynamic_archive_bottom = my_archive_requested_bottom; } @@ -387,13 +387,13 @@ address ArchiveBuilder::reserve_buffer() { aot_log_error(aot)("my_archive_requested_top = " INTPTR_FORMAT, p2i(my_archive_requested_top)); aot_log_error(aot)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. " "Please rerun java -Xshare:dump with a lower value", p2i(_requested_static_archive_bottom)); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } if (CDSConfig::is_dumping_static_archive()) { // We don't want any valid object to be at the very bottom of the archive. // See ArchivePtrMarker::mark_pointer(). - _pz_region.allocate(MetaspaceShared::protection_zone_size()); + _pz_region.allocate(AOTMetaspace::protection_zone_size()); start_dump_region(&_rw_region); } @@ -540,7 +540,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { return SystemDictionaryShared::is_excluded_class(ik); } else if (klass->is_objArray_klass()) { Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache_static_region(bottom)) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache_static_region(bottom)) { // The bottom class is in the static archive so it's clearly not excluded. return false; } else if (bottom->is_instance_klass()) { @@ -553,7 +553,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) { address obj = ref->obj(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(obj)) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(obj)) { // Don't dump existing shared metadata again. return point_to_it; } else if (ref->msotype() == MetaspaceObj::MethodDataType || @@ -956,7 +956,7 @@ void ArchiveBuilder::make_klasses_shareable() { } } - MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); + AOTMetaspace::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); ik->remove_unshareable_info(); } @@ -1188,12 +1188,12 @@ void ArchiveBuilder::print_stats() { void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info) { // Make sure NUM_CDS_REGIONS (exported in cds.h) agrees with - // MetaspaceShared::n_regions (internal to hotspot). - assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity"); + // AOTMetaspace::n_regions (internal to hotspot). + assert(NUM_CDS_REGIONS == AOTMetaspace::n_regions, "sanity"); - write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); - write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); - write_region(mapinfo, MetaspaceShared::ac, &_ac_region, /*read_only=*/false,/*allow_exec=*/false); + write_region(mapinfo, AOTMetaspace::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); + write_region(mapinfo, AOTMetaspace::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); + write_region(mapinfo, AOTMetaspace::ac, &_ac_region, /*read_only=*/false,/*allow_exec=*/false); // Split pointer map into read-write and read-only bitmaps ArchivePtrMarker::initialize_rw_ro_maps(&_rw_ptrmap, &_ro_ptrmap); @@ -1208,7 +1208,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i print_region_stats(mapinfo, heap_info); - mapinfo->set_requested_base((char*)MetaspaceShared::requested_base_address()); + mapinfo->set_requested_base((char*)AOTMetaspace::requested_base_address()); mapinfo->set_header_crc(mapinfo->compute_header_crc()); // After this point, we should not write any data into mapinfo->header() since this // would corrupt its checksum we have calculated before. @@ -1239,8 +1239,8 @@ void ArchiveBuilder::count_relocated_pointer(bool tagged, bool nulled) { void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* heap_info) { // Print statistics of all the regions - const size_t bitmap_used = mapinfo->region_at(MetaspaceShared::bm)->used(); - const size_t bitmap_reserved = mapinfo->region_at(MetaspaceShared::bm)->used_aligned(); + const size_t bitmap_used = mapinfo->region_at(AOTMetaspace::bm)->used(); + const size_t bitmap_reserved = mapinfo->region_at(AOTMetaspace::bm)->used_aligned(); const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() + bitmap_reserved + _total_heap_region_size; @@ -1284,5 +1284,5 @@ void ArchiveBuilder::report_out_of_space(const char* name, size_t needed_bytes) _ro_region.print_out_of_space_msg(name, needed_bytes); log_error(aot)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 673c4baa6f6..6efc8f6fe1e 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -22,10 +22,10 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoaderDataShared.hpp" #include "classfile/systemDictionaryShared.hpp" #include "gc/shared/collectedHeap.hpp" @@ -261,7 +261,7 @@ class ArchiveHeapLoader::PatchLoadedRegionPointers: public BitMapClosure { bool ArchiveHeapLoader::init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region, MemRegion& archive_space) { size_t total_bytes = 0; - FileMapRegion* r = mapinfo->region_at(MetaspaceShared::hp); + FileMapRegion* r = mapinfo->region_at(AOTMetaspace::hp); r->assert_is_heap_region(); if (r->used() == 0) { return false; @@ -269,7 +269,7 @@ bool ArchiveHeapLoader::init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHe assert(is_aligned(r->used(), HeapWordSize), "must be"); total_bytes += r->used(); - loaded_region->_region_index = MetaspaceShared::hp; + loaded_region->_region_index = AOTMetaspace::hp; loaded_region->_region_size = r->used(); loaded_region->_dumptime_base = (uintptr_t)mapinfo->heap_region_dumptime_address(); @@ -447,20 +447,20 @@ class PatchNativePointers: public BitMapClosure { bool do_bit(size_t offset) { Metadata** p = _start + offset; - *p = (Metadata*)(address(*p) + MetaspaceShared::relocation_delta()); + *p = (Metadata*)(address(*p) + AOTMetaspace::relocation_delta()); return true; } }; void ArchiveHeapLoader::patch_native_pointers() { - if (MetaspaceShared::relocation_delta() == 0) { + if (AOTMetaspace::relocation_delta() == 0) { return; } - FileMapRegion* r = FileMapInfo::current_info()->region_at(MetaspaceShared::hp); + FileMapRegion* r = FileMapInfo::current_info()->region_at(AOTMetaspace::hp); if (r->mapped_base() != nullptr && r->has_ptrmap()) { log_info(aot, heap)("Patching native pointers in heap region"); - BitMapView bm = FileMapInfo::current_info()->ptrmap_view(MetaspaceShared::hp); + BitMapView bm = FileMapInfo::current_info()->ptrmap_view(AOTMetaspace::hp); PatchNativePointers patcher((Metadata**)r->mapped_base() + FileMapInfo::current_info()->heap_ptrmap_start_pos()); bm.iterate(&patcher); } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 3c900cad035..82d4379f631 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveUtils.hpp" @@ -33,7 +34,6 @@ #include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" #include "interpreter/bootstrapInfo.hpp" @@ -117,7 +117,7 @@ void ArchivePtrMarker::mark_pointer(address* ptr_loc) { if (ptr_base() <= ptr_loc && ptr_loc < ptr_end()) { address value = *ptr_loc; // We don't want any pointer that points to very bottom of the archive, otherwise when - // MetaspaceShared::default_base_address()==0, we can't distinguish between a pointer + // AOTMetaspace::default_base_address()==0, we can't distinguish between a pointer // to nothing (null) vs a pointer to an objects that happens to be at the very bottom // of the archive. assert(value != (address)ptr_base(), "don't point to the bottom of the archive"); @@ -209,7 +209,7 @@ char* DumpRegion::expand_top_to(char* newtop) { // happens only if you allocate more than 2GB of shared objects and would require // millions of shared classes. aot_log_error(aot)("Out of memory in the CDS archive: Please reduce the number of shared classes."); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } @@ -236,11 +236,11 @@ void DumpRegion::commit_to(char* newtop) { if (!_vs->expand_by(commit, false)) { aot_log_error(aot)("Failed to expand shared space to %zu bytes", need_committed_size); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } const char* which; - if (_rs->base() == (char*)MetaspaceShared::symbol_rs_base()) { + if (_rs->base() == (char*)AOTMetaspace::symbol_rs_base()) { which = "symbol"; } else { which = "shared"; @@ -298,10 +298,10 @@ void DumpRegion::init(ReservedSpace* rs, VirtualSpace* vs) { void DumpRegion::pack(DumpRegion* next) { if (!is_packed()) { - _end = (char*)align_up(_top, MetaspaceShared::core_region_alignment()); + _end = (char*)align_up(_top, AOTMetaspace::core_region_alignment()); _is_packed = true; } - _end = (char*)align_up(_top, MetaspaceShared::core_region_alignment()); + _end = (char*)align_up(_top, AOTMetaspace::core_region_alignment()); _is_packed = true; if (next != nullptr) { next->_rs = _rs; diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 70b91fb8900..6f635d01745 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.inline.hpp @@ -28,9 +28,9 @@ #include "cds/archiveUtils.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "oops/array.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/growableArray.hpp" @@ -80,7 +80,7 @@ Array* ArchiveUtils::archive_ptr_array(GrowableArray* tmp_array) { for (int i = 0; i < tmp_array->length(); i++) { T ptr = tmp_array->at(i); if (ptr != nullptr && !builder->is_in_buffer_space(ptr)) { - if (is_dynamic_dump && MetaspaceShared::in_aot_cache(ptr)) { + if (is_dynamic_dump && AOTMetaspace::in_aot_cache(ptr)) { // We have a pointer that lives in the dynamic archive but points into // the static archive. } else { diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 6922b66d7cd..90b802731f0 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -767,7 +767,7 @@ void CDSConfig::prepare_for_dumping() { #define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." if (RecordDynamicDumpInfo) { aot_log_error(aot)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } else { assert(ArchiveClassesAtExit != nullptr, "sanity"); aot_log_warning(aot)("-XX:ArchiveClassesAtExit" __THEMSG); diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp index 0da9e3f2c8d..a9f46c21ad3 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -157,7 +157,7 @@ CDSHeapVerifier::~CDSHeapVerifier() { "an object points to a static field that " "may hold a different value at runtime.", _archived_objs, _problems); log_error(aot, heap)("Please see cdsHeapVerifier.cpp and aotClassInitializer.cpp for details"); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index c95fd8b64df..ff15fdccabe 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -118,7 +118,7 @@ Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) { PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) { PackageEntry* pkg_entry = ik->package(); if (CDSConfig::is_using_full_module_graph() && ik->in_aot_cache() && pkg_entry != nullptr) { - assert(MetaspaceShared::in_aot_cache(pkg_entry), "must be"); + assert(AOTMetaspace::in_aot_cache(pkg_entry), "must be"); assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class"); return pkg_entry; } diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 75737b1432e..2405d0dc2ff 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -24,11 +24,11 @@ #include "cds/aotConstantPoolResolver.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" #include "cds/classListParser.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/unregisteredClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.inline.hpp" @@ -185,7 +185,7 @@ void ClassListParser::parse_class_name_and_attributes(TRAPS) { // cpcache to be created. The linking is done as soon as classes // are loaded in order that the related data structures (klass and // cpCache) are located together. - MetaspaceShared::try_link_class(THREAD, ik); + AOTMetaspace::try_link_class(THREAD, ik); } } @@ -674,7 +674,7 @@ void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) { Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, true, CHECK); if (klass->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(klass); - MetaspaceShared::try_link_class(THREAD, ik); + AOTMetaspace::try_link_class(THREAD, ik); if (!ik->is_linked()) { // Verification of ik has failed return; diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 261f5332526..f2862454286 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -22,11 +22,11 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" #include "cds/cppVtables.hpp" -#include "cds/metaspaceShared.hpp" #include "logging/log.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -321,7 +321,7 @@ void CppVtables::zero_archived_vtables() { } bool CppVtables::is_valid_shared_method(const Method* m) { - assert(MetaspaceShared::in_aot_cache(m), "must be"); + assert(AOTMetaspace::in_aot_cache(m), "must be"); return vtable_of(m) == _index[Method_Kind]->cloned_vtable() || vtable_of(m) == _archived_cpp_vtptrs[Method_Kind]; } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 0feed8682da..0bc0f8bedda 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_CDS_DUMPTIMECLASSINFO_HPP #define SHARE_CDS_DUMPTIMECLASSINFO_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "memory/metaspaceClosure.hpp" #include "oops/instanceKlass.hpp" @@ -231,7 +231,7 @@ template inline unsigned DumpTimeSharedClassTable_hash(T* const& k) { if (CDSConfig::is_dumping_static_archive()) { // Deterministic archive contents - uintx delta = k->name() - MetaspaceShared::symbol_rs_base(); + uintx delta = k->name() - AOTMetaspace::symbol_rs_base(); return primitive_hash(delta); } else { // Deterministic archive is not possible because classes can be loaded diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 8499dced126..d628a4e991f 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassLinker.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.inline.hpp" @@ -34,7 +35,6 @@ #include "cds/dynamicArchive.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -187,7 +187,7 @@ public: for (int i = T_BOOLEAN; i <= T_LONG; i++) { assert(is_java_primitive((BasicType)i), "sanity"); Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc - assert(MetaspaceShared::in_aot_cache_static_region((void*)k), + assert(AOTMetaspace::in_aot_cache_static_region((void*)k), "one-dimensional primitive array should be in static archive"); ArrayKlass* ak = ArrayKlass::cast(k); while (ak != nullptr && ak->in_aot_cache()) { @@ -216,7 +216,7 @@ void DynamicArchiveBuilder::init_header() { _header = mapinfo->dynamic_header(); _header->set_base_header_crc(base_info->crc()); - for (int i = 0; i < MetaspaceShared::n_regions; i++) { + for (int i = 0; i < AOTMetaspace::n_regions; i++) { _header->set_base_region_crc(i, base_info->region_crc(i)); } } @@ -253,7 +253,7 @@ void DynamicArchiveBuilder::sort_methods() { // klasses were created. Re-sort all the tables. See Method::sort_methods(). void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { assert(ik != nullptr, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); - if (MetaspaceShared::in_aot_cache(ik)) { + if (AOTMetaspace::in_aot_cache(ik)) { // We have reached a supertype that's already in the base archive return; } @@ -287,13 +287,13 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { if (ik->methods() != nullptr) { for (int m = 0; m < ik->methods()->length(); m++) { Symbol* name = ik->methods()->at(m)->name(); - assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); + assert(AOTMetaspace::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } if (ik->default_methods() != nullptr) { for (int m = 0; m < ik->default_methods()->length(); m++) { Symbol* name = ik->default_methods()->at(m)->name(); - assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); + assert(AOTMetaspace::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } #endif @@ -367,14 +367,14 @@ void DynamicArchiveBuilder::gather_array_klasses() { if (klasses()->at(i)->is_objArray_klass()) { ObjArrayKlass* oak = ObjArrayKlass::cast(klasses()->at(i)); Klass* elem = oak->element_klass(); - if (MetaspaceShared::in_aot_cache_static_region(elem)) { + if (AOTMetaspace::in_aot_cache_static_region(elem)) { // Only capture the array klass whose element_klass is in the static archive. // During run time, setup (see DynamicArchive::setup_array_klasses()) is needed // so that the element_klass can find its array klasses from the dynamic archive. DynamicArchive::append_array_klass(oak); } else { // The element_klass and its array klasses are in the same archive. - assert(!MetaspaceShared::in_aot_cache_static_region(oak), + assert(!AOTMetaspace::in_aot_cache_static_region(oak), "we should not gather klasses that are already in the static archive"); } } @@ -435,7 +435,7 @@ void DynamicArchive::setup_array_klasses() { assert(!oak->is_typeArray_klass(), "all type array classes must be in static archive"); Klass* elm = oak->element_klass(); - assert(MetaspaceShared::in_aot_cache_static_region((void*)elm), "must be"); + assert(AOTMetaspace::in_aot_cache_static_region((void*)elm), "must be"); if (elm->is_instance_klass()) { assert(InstanceKlass::cast(elm)->array_klasses() == nullptr, "must be"); @@ -476,7 +476,7 @@ int DynamicArchive::num_array_klasses() { } void DynamicArchive::dump_impl(bool jcmd_request, const char* archive_name, TRAPS) { - MetaspaceShared::link_shared_classes(CHECK); + AOTMetaspace::link_shared_classes(CHECK); if (!jcmd_request && CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { LambdaFormInvokers::regenerate_holder_classes(CHECK); } @@ -532,7 +532,7 @@ bool DynamicArchive::validate(FileMapInfo* dynamic_info) { } // Check each space's crc - for (int i = 0; i < MetaspaceShared::n_regions; i++) { + for (int i = 0; i < AOTMetaspace::n_regions; i++) { if (dynamic_header->base_region_crc(i) != base_info->region_crc(i)) { aot_log_warning(aot)("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); return false; diff --git a/src/hotspot/share/cds/dynamicArchive.hpp b/src/hotspot/share/cds/dynamicArchive.hpp index 8c23750734c..19086053d76 100644 --- a/src/hotspot/share/cds/dynamicArchive.hpp +++ b/src/hotspot/share/cds/dynamicArchive.hpp @@ -41,7 +41,7 @@ class DynamicArchiveHeader : public FileMapHeader { friend class CDSConstants; private: int _base_header_crc; - int _base_region_crc[MetaspaceShared::n_regions]; + int _base_region_crc[AOTMetaspace::n_regions]; public: int base_header_crc() const { return _base_header_crc; } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 78f02161477..409052eae6a 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -24,6 +24,7 @@ #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveHeapWriter.hpp" @@ -33,7 +34,6 @@ #include "cds/dynamicArchive.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" @@ -329,7 +329,7 @@ bool FileMapInfo::validate_class_location() { bool has_extra_module_paths = false; if (!config->validate(full_path(), header()->has_aot_linked_classes(), &has_extra_module_paths)) { if (PrintSharedArchiveAndExit) { - MetaspaceShared::set_archive_loading_failed(); + AOTMetaspace::set_archive_loading_failed(); return true; } else { return false; @@ -338,7 +338,7 @@ bool FileMapInfo::validate_class_location() { if (header()->has_full_module_graph() && has_extra_module_paths) { CDSConfig::stop_using_optimized_module_handling(); - MetaspaceShared::report_loading_error("optimized module handling: disabled because extra module path(s) are specified"); + AOTMetaspace::report_loading_error("optimized module handling: disabled because extra module path(s) are specified"); } if (CDSConfig::is_dumping_dynamic_archive()) { @@ -409,7 +409,7 @@ public: assert(_archive_name != nullptr, "Archive name is null"); _fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0); if (_fd < 0) { - MetaspaceShared::report_loading_error("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); + AOTMetaspace::report_loading_error("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); return false; } return initialize(_fd); @@ -694,7 +694,7 @@ bool FileMapInfo::init_from_file(int fd) { size_t len = os::lseek(fd, 0, SEEK_END); - for (int i = 0; i < MetaspaceShared::n_regions; i++) { + for (int i = 0; i < AOTMetaspace::n_regions; i++) { FileMapRegion* r = region_at(i); if (r->file_offset() > len || len - r->file_offset() < r->used()) { aot_log_warning(aot)("The %s has been truncated.", file_type); @@ -708,7 +708,7 @@ bool FileMapInfo::init_from_file(int fd) { void FileMapInfo::seek_to_position(size_t pos) { if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) { aot_log_error(aot)("Unable to seek to position %zu", pos); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } } @@ -763,7 +763,7 @@ void FileMapInfo::open_as_output() { if (fd < 0) { aot_log_error(aot)("Unable to create %s %s: (%s).", CDSConfig::type_of_archive_being_written(), _full_path, os::strerror(errno)); - MetaspaceShared::writing_error(); + AOTMetaspace::writing_error(); return; } _fd = fd; @@ -773,7 +773,7 @@ void FileMapInfo::open_as_output() { // and their CRCs computed. size_t header_bytes = header()->header_size(); - header_bytes = align_up(header_bytes, MetaspaceShared::core_region_alignment()); + header_bytes = align_up(header_bytes, AOTMetaspace::core_region_alignment()); _file_offset = header_bytes; seek_to_position(_file_offset); } @@ -788,13 +788,13 @@ void FileMapInfo::write_header() { } size_t FileMapRegion::used_aligned() const { - return align_up(used(), MetaspaceShared::core_region_alignment()); + return align_up(used(), AOTMetaspace::core_region_alignment()); } void FileMapRegion::init(int region_index, size_t mapping_offset, size_t size, bool read_only, bool allow_exec, int crc) { _is_heap_region = HeapShared::is_heap_region(region_index); - _is_bitmap_region = (region_index == MetaspaceShared::bm); + _is_bitmap_region = (region_index == AOTMetaspace::bm); _mapping_offset = mapping_offset; _used = size; _read_only = read_only; @@ -890,7 +890,7 @@ void FileMapInfo::write_region(int region, char* base, size_t size, char* requested_base; size_t mapping_offset = 0; - if (region == MetaspaceShared::bm) { + if (region == AOTMetaspace::bm) { requested_base = nullptr; // always null for bm region } else if (size == 0) { // This is an unused region (e.g., a heap region when !INCLUDE_CDS_JAVA_HEAP) @@ -908,7 +908,7 @@ void FileMapInfo::write_region(int region, char* base, size_t size, } #endif // INCLUDE_CDS_JAVA_HEAP } else { - char* requested_SharedBaseAddress = (char*)MetaspaceShared::requested_base_address(); + char* requested_SharedBaseAddress = (char*)AOTMetaspace::requested_base_address(); requested_base = ArchiveBuilder::current()->to_requested(base); assert(requested_base >= requested_SharedBaseAddress, "must be"); mapping_offset = requested_base - requested_SharedBaseAddress; @@ -984,14 +984,14 @@ char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_p char* buffer = NEW_C_HEAP_ARRAY(char, size_in_bytes, mtClassShared); size_t written = 0; - region_at(MetaspaceShared::rw)->init_ptrmap(0, rw_ptrmap->size()); + region_at(AOTMetaspace::rw)->init_ptrmap(0, rw_ptrmap->size()); written = write_bitmap(rw_ptrmap, buffer, written); - region_at(MetaspaceShared::ro)->init_ptrmap(written, ro_ptrmap->size()); + region_at(AOTMetaspace::ro)->init_ptrmap(written, ro_ptrmap->size()); written = write_bitmap(ro_ptrmap, buffer, written); if (heap_info->is_used()) { - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); r->init_oopmap(written, heap_info->oopmap()->size()); written = write_bitmap(heap_info->oopmap(), buffer, written); @@ -1000,14 +1000,14 @@ char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_p written = write_bitmap(heap_info->ptrmap(), buffer, written); } - write_region(MetaspaceShared::bm, (char*)buffer, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false); + write_region(AOTMetaspace::bm, (char*)buffer, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false); return buffer; } size_t FileMapInfo::write_heap_region(ArchiveHeapInfo* heap_info) { char* buffer_start = heap_info->buffer_start(); size_t buffer_size = heap_info->buffer_byte_size(); - write_region(MetaspaceShared::hp, buffer_start, buffer_size, false, false); + write_region(AOTMetaspace::hp, buffer_start, buffer_size, false, false); header()->set_heap_root_segments(heap_info->heap_root_segments()); return buffer_size; } @@ -1022,11 +1022,11 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { remove(_full_path); if (CDSConfig::is_dumping_preimage_static_archive()) { - MetaspaceShared::writing_error("Unable to write to AOT configuration file."); + AOTMetaspace::writing_error("Unable to write to AOT configuration file."); } else if (CDSConfig::new_aot_flags_used()) { - MetaspaceShared::writing_error("Unable to write to AOT cache."); + AOTMetaspace::writing_error("Unable to write to AOT cache."); } else { - MetaspaceShared::writing_error("Unable to write to shared archive."); + AOTMetaspace::writing_error("Unable to write to shared archive."); } } _file_offset += nbytes; @@ -1034,7 +1034,7 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { bool FileMapInfo::is_file_position_aligned() const { return _file_offset == align_up(_file_offset, - MetaspaceShared::core_region_alignment()); + AOTMetaspace::core_region_alignment()); } // Align file position to an allocation unit boundary. @@ -1042,7 +1042,7 @@ bool FileMapInfo::is_file_position_aligned() const { void FileMapInfo::align_file_position() { assert(_file_open, "must be"); size_t new_file_offset = align_up(_file_offset, - MetaspaceShared::core_region_alignment()); + AOTMetaspace::core_region_alignment()); if (new_file_offset != _file_offset) { _file_offset = new_file_offset; // Seek one byte back from the target and write a byte to insure @@ -1068,7 +1068,7 @@ void FileMapInfo::write_bytes_aligned(const void* buffer, size_t nbytes) { void FileMapInfo::close() { if (_file_open) { if (::close(_fd) < 0) { - MetaspaceShared::unrecoverable_loading_error("Unable to close the shared archive file."); + AOTMetaspace::unrecoverable_loading_error("Unable to close the shared archive file."); } _file_open = false; _fd = -1; @@ -1093,7 +1093,7 @@ static char* map_memory(int fd, const char* file_name, size_t file_offset, // JVM/TI RedefineClasses() support: // Remap the shared readonly space to shared readwrite, private. bool FileMapInfo::remap_shared_readonly_as_readwrite() { - int idx = MetaspaceShared::ro; + int idx = AOTMetaspace::ro; FileMapRegion* r = region_at(idx); if (!r->read_only()) { // the space is already readwrite so we are done @@ -1200,7 +1200,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba r->set_mapped_from_file(false); r->set_in_reserved_space(false); - if (MetaspaceShared::use_windows_memory_mapping()) { + if (AOTMetaspace::use_windows_memory_mapping()) { // Windows cannot remap read-only shared memory to read-write when required for // RedefineClasses, which is also used by JFR. Always map windows regions as RW. r->set_read_only(false); @@ -1212,13 +1212,13 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba r->set_read_only(false); // Need to patch the pointers } - if (MetaspaceShared::use_windows_memory_mapping() && rs.is_reserved()) { + if (AOTMetaspace::use_windows_memory_mapping() && rs.is_reserved()) { // This is the second time we try to map the archive(s). We have already created a ReservedSpace // that covers all the FileMapRegions to ensure all regions can be mapped. However, Windows // can't mmap into a ReservedSpace, so we just ::read() the data. We're going to patch all the // regions anyway, so there's no benefit for mmap anyway. if (!read_region(i, requested_addr, size, /* do_commit = */ true)) { - MetaspaceShared::report_loading_error("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, + AOTMetaspace::report_loading_error("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error. } else { @@ -1227,12 +1227,12 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba } else { // Note that this may either be a "fresh" mapping into unreserved address // space (Windows, first mapping attempt), or a mapping into pre-reserved - // space (Posix). See also comment in MetaspaceShared::map_archives(). + // space (Posix). See also comment in AOTMetaspace::map_archives(). char* base = map_memory(_fd, _full_path, r->file_offset(), requested_addr, size, r->read_only(), r->allow_exec(), mtClassShared); if (base != requested_addr) { - MetaspaceShared::report_loading_error("Unable to map %s shared space at " INTPTR_FORMAT, + AOTMetaspace::report_loading_error("Unable to map %s shared space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); _memory_mapping_failed = true; return MAP_ARCHIVE_MMAP_FAILURE; @@ -1258,7 +1258,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba // The return value is the location of the archive relocation bitmap. char* FileMapInfo::map_bitmap_region() { - FileMapRegion* r = region_at(MetaspaceShared::bm); + FileMapRegion* r = region_at(AOTMetaspace::bm); if (r->mapped_base() != nullptr) { return r->mapped_base(); } @@ -1267,7 +1267,7 @@ char* FileMapInfo::map_bitmap_region() { char* bitmap_base = map_memory(_fd, _full_path, r->file_offset(), requested_addr, r->used_aligned(), read_only, allow_exec, mtClassShared); if (bitmap_base == nullptr) { - MetaspaceShared::report_loading_error("failed to map relocation bitmap"); + AOTMetaspace::report_loading_error("failed to map relocation bitmap"); return nullptr; } @@ -1283,22 +1283,22 @@ char* FileMapInfo::map_bitmap_region() { r->set_mapped_base(bitmap_base); aot_log_info(aot)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", is_static() ? "static " : "dynamic", - MetaspaceShared::bm, p2i(r->mapped_base()), p2i(r->mapped_end()), - shared_region_name[MetaspaceShared::bm]); + AOTMetaspace::bm, p2i(r->mapped_base()), p2i(r->mapped_end()), + shared_region_name[AOTMetaspace::bm]); return bitmap_base; } bool FileMapInfo::map_aot_code_region(ReservedSpace rs) { - FileMapRegion* r = region_at(MetaspaceShared::ac); + FileMapRegion* r = region_at(AOTMetaspace::ac); assert(r->used() > 0 && r->used_aligned() == rs.size(), "must be"); char* requested_base = rs.base(); assert(requested_base != nullptr, "should be inside code cache"); char* mapped_base; - if (MetaspaceShared::use_windows_memory_mapping()) { - if (!read_region(MetaspaceShared::ac, requested_base, r->used_aligned(), /* do_commit = */ true)) { - MetaspaceShared::report_loading_error("Failed to read aot code shared space into reserved space at " INTPTR_FORMAT, + if (AOTMetaspace::use_windows_memory_mapping()) { + if (!read_region(AOTMetaspace::ac, requested_base, r->used_aligned(), /* do_commit = */ true)) { + AOTMetaspace::report_loading_error("Failed to read aot code shared space into reserved space at " INTPTR_FORMAT, p2i(requested_base)); return false; } @@ -1311,15 +1311,15 @@ bool FileMapInfo::map_aot_code_region(ReservedSpace rs) { requested_base, r->used_aligned(), read_only, allow_exec, mtClassShared); } if (mapped_base == nullptr) { - MetaspaceShared::report_loading_error("failed to map aot code region"); + AOTMetaspace::report_loading_error("failed to map aot code region"); return false; } else { assert(mapped_base == requested_base, "must be"); r->set_mapped_from_file(true); r->set_mapped_base(mapped_base); aot_log_info(aot)("Mapped static region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", - MetaspaceShared::ac, p2i(r->mapped_base()), p2i(r->mapped_end()), - shared_region_name[MetaspaceShared::ac]); + AOTMetaspace::ac, p2i(r->mapped_base()), p2i(r->mapped_end()), + shared_region_name[AOTMetaspace::ac]); return true; } } @@ -1359,8 +1359,8 @@ bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { if (bitmap_base == nullptr) { return false; // OOM, or CRC check failure } else { - BitMapView rw_ptrmap = ptrmap_view(MetaspaceShared::rw); - BitMapView ro_ptrmap = ptrmap_view(MetaspaceShared::ro); + BitMapView rw_ptrmap = ptrmap_view(AOTMetaspace::rw); + BitMapView ro_ptrmap = ptrmap_view(AOTMetaspace::ro); FileMapRegion* rw_region = first_core_region(); FileMapRegion* ro_region = last_core_region(); @@ -1398,7 +1398,7 @@ bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { ro_ptrmap.iterate(&ro_patcher); } - // The MetaspaceShared::bm region will be unmapped in MetaspaceShared::initialize_shared_spaces(). + // The AOTMetaspace::bm region will be unmapped in AOTMetaspace::initialize_shared_spaces(). aot_log_debug(aot, reloc)("runtime archive relocation done"); return true; @@ -1421,11 +1421,11 @@ size_t FileMapInfo::read_bytes(void* buffer, size_t count) { size_t FileMapInfo::readonly_total() { size_t total = 0; if (current_info() != nullptr) { - FileMapRegion* r = FileMapInfo::current_info()->region_at(MetaspaceShared::ro); + FileMapRegion* r = FileMapInfo::current_info()->region_at(AOTMetaspace::ro); if (r->read_only()) total += r->used(); } if (dynamic_info() != nullptr) { - FileMapRegion* r = FileMapInfo::dynamic_info()->region_at(MetaspaceShared::ro); + FileMapRegion* r = FileMapInfo::dynamic_info()->region_at(AOTMetaspace::ro); if (r->read_only()) total += r->used(); } return total; @@ -1435,7 +1435,7 @@ size_t FileMapInfo::readonly_total() { MemRegion FileMapInfo::_mapped_heap_memregion; bool FileMapInfo::has_heap_region() { - return (region_at(MetaspaceShared::hp)->used() > 0); + return (region_at(AOTMetaspace::hp)->used() > 0); } // Returns the address range of the archived heap region computed using the @@ -1443,7 +1443,7 @@ bool FileMapInfo::has_heap_region() { // dump time due to encoding mode differences. The result is used in determining // if/how these regions should be relocated at run time. MemRegion FileMapInfo::get_heap_region_requested_range() { - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); size_t size = r->used(); assert(size > 0, "must have non-empty heap region"); @@ -1465,9 +1465,9 @@ void FileMapInfo::map_or_load_heap_region() { success = ArchiveHeapLoader::load_heap_region(this); } else { if (!UseCompressedOops && !ArchiveHeapLoader::can_map()) { - MetaspaceShared::report_loading_error("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); + AOTMetaspace::report_loading_error("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); } else { - MetaspaceShared::report_loading_error("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); + AOTMetaspace::report_loading_error("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); } } } @@ -1482,7 +1482,7 @@ void FileMapInfo::map_or_load_heap_region() { aot_log_error(aot)("%s has aot-linked classes but the archived " "heap objects cannot be loaded. Try increasing your heap size.", CDSConfig::type_of_archive_being_loaded()); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } CDSConfig::stop_using_full_module_graph("archive heap loading failed"); } @@ -1575,7 +1575,7 @@ bool FileMapInfo::can_use_heap_region() { // The actual address of this region during dump time. address FileMapInfo::heap_region_dumptime_address() { - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); assert(CDSConfig::is_using_archive(), "runtime only"); assert(is_aligned(r->mapping_offset(), sizeof(HeapWord)), "must be"); if (UseCompressedOops) { @@ -1589,7 +1589,7 @@ address FileMapInfo::heap_region_dumptime_address() { // patching any of the pointers that are embedded in this region. address FileMapInfo::heap_region_requested_address() { assert(CDSConfig::is_using_archive(), "runtime only"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); assert(is_aligned(r->mapping_offset(), sizeof(HeapWord)), "must be"); assert(ArchiveHeapLoader::can_use(), "GC must support mapping or loading"); if (UseCompressedOops) { @@ -1643,7 +1643,7 @@ bool FileMapInfo::map_heap_region() { bool FileMapInfo::map_heap_region_impl() { assert(UseG1GC, "the following code assumes G1"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); size_t size = r->used(); if (size == 0) { return false; // no archived java heap data @@ -1657,7 +1657,7 @@ bool FileMapInfo::map_heap_region_impl() { // allocate from java heap HeapWord* start = G1CollectedHeap::heap()->alloc_archive_region(word_size, (HeapWord*)requested_start); if (start == nullptr) { - MetaspaceShared::report_loading_error("UseSharedSpaces: Unable to allocate java heap region for archive heap."); + AOTMetaspace::report_loading_error("UseSharedSpaces: Unable to allocate java heap region for archive heap."); return false; } @@ -1668,11 +1668,11 @@ bool FileMapInfo::map_heap_region_impl() { char* addr = (char*)_mapped_heap_memregion.start(); char* base; - if (MetaspaceShared::use_windows_memory_mapping() || UseLargePages) { + if (AOTMetaspace::use_windows_memory_mapping() || UseLargePages) { // With UseLargePages, memory mapping may fail on some OSes if the size is not // large page aligned, so let's use read() instead. In this case, the memory region // is already commited by G1 so we don't need to commit it again. - if (!read_region(MetaspaceShared::hp, addr, + if (!read_region(AOTMetaspace::hp, addr, align_up(_mapped_heap_memregion.byte_size(), os::vm_page_size()), /* do_commit = */ !UseLargePages)) { dealloc_heap_region(); @@ -1687,7 +1687,7 @@ bool FileMapInfo::map_heap_region_impl() { r->allow_exec(), mtJavaHeap); if (base == nullptr || base != addr) { dealloc_heap_region(); - MetaspaceShared::report_loading_error("UseSharedSpaces: Unable to map at required address in java heap. " + AOTMetaspace::report_loading_error("UseSharedSpaces: Unable to map at required address in java heap. " INTPTR_FORMAT ", size = %zu bytes", p2i(addr), _mapped_heap_memregion.byte_size()); return false; @@ -1695,7 +1695,7 @@ bool FileMapInfo::map_heap_region_impl() { if (VerifySharedSpaces && !r->check_region_crc(base)) { dealloc_heap_region(); - MetaspaceShared::report_loading_error("UseSharedSpaces: mapped heap region is corrupt"); + AOTMetaspace::report_loading_error("UseSharedSpaces: mapped heap region is corrupt"); return false; } } @@ -1719,7 +1719,7 @@ bool FileMapInfo::map_heap_region_impl() { if (_heap_pointers_need_patching) { char* bitmap_base = map_bitmap_region(); if (bitmap_base == nullptr) { - MetaspaceShared::report_loading_error("CDS heap cannot be used because bitmap region cannot be mapped"); + AOTMetaspace::report_loading_error("CDS heap cannot be used because bitmap region cannot be mapped"); dealloc_heap_region(); _heap_pointers_need_patching = false; return false; @@ -1734,7 +1734,7 @@ bool FileMapInfo::map_heap_region_impl() { narrowOop FileMapInfo::encoded_heap_region_dumptime_address() { assert(CDSConfig::is_using_archive(), "runtime only"); assert(UseCompressedOops, "sanity"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); return CompressedOops::narrow_oop_cast(r->mapping_offset() >> narrow_oop_shift()); } @@ -1746,10 +1746,10 @@ void FileMapInfo::patch_heap_embedded_pointers() { char* bitmap_base = map_bitmap_region(); assert(bitmap_base != nullptr, "must have already been mapped"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); ArchiveHeapLoader::patch_embedded_pointers( this, _mapped_heap_memregion, - (address)(region_at(MetaspaceShared::bm)->mapped_base()) + r->oopmap_offset(), + (address)(region_at(AOTMetaspace::bm)->mapped_base()) + r->oopmap_offset(), r->oopmap_size_in_bits()); } @@ -1805,7 +1805,7 @@ void FileMapInfo::unmap_region(int i) { void FileMapInfo::assert_mark(bool check) { if (!check) { - MetaspaceShared::unrecoverable_loading_error("Mark mismatch while restoring from shared file."); + AOTMetaspace::unrecoverable_loading_error("Mark mismatch while restoring from shared file."); } } @@ -1832,16 +1832,16 @@ bool FileMapInfo::open_as_input() { // are replaced at runtime by JVMTI ClassFileLoadHook. All of those classes are resolved // during the JVMTI "early" stage, so we can still use CDS if // JvmtiExport::has_early_class_hook_env() is false. - MetaspaceShared::report_loading_error("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); + AOTMetaspace::report_loading_error("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); return false; } if (!open_for_read() || !init_from_file(_fd) || !validate_header()) { if (_is_static) { - MetaspaceShared::report_loading_error("Loading static archive failed."); + AOTMetaspace::report_loading_error("Loading static archive failed."); return false; } else { - MetaspaceShared::report_loading_error("Loading dynamic archive failed."); + AOTMetaspace::report_loading_error("Loading dynamic archive failed."); if (AutoCreateSharedArchive) { CDSConfig::enable_dumping_dynamic_archive(_full_path); } @@ -1894,11 +1894,11 @@ bool FileMapInfo::validate_aot_class_linking() { // The 2 core spaces are RW->RO FileMapRegion* FileMapInfo::first_core_region() const { - return region_at(MetaspaceShared::rw); + return region_at(AOTMetaspace::rw); } FileMapRegion* FileMapInfo::last_core_region() const { - return region_at(MetaspaceShared::ro); + return region_at(AOTMetaspace::ro); } void FileMapInfo::print(outputStream* st) const { @@ -1925,13 +1925,13 @@ int FileMapHeader::compute_crc() { bool FileMapHeader::validate() { const char* file_type = CDSConfig::type_of_archive_being_loaded(); if (_obj_alignment != ObjectAlignmentInBytes) { - MetaspaceShared::report_loading_error("The %s's ObjectAlignmentInBytes of %d" + AOTMetaspace::report_loading_error("The %s's ObjectAlignmentInBytes of %d" " does not equal the current ObjectAlignmentInBytes of %d.", file_type, _obj_alignment, ObjectAlignmentInBytes); return false; } if (_compact_strings != CompactStrings) { - MetaspaceShared::report_loading_error("The %s's CompactStrings setting (%s)" + AOTMetaspace::report_loading_error("The %s's CompactStrings setting (%s)" " does not equal the current CompactStrings setting (%s).", file_type, _compact_strings ? "enabled" : "disabled", CompactStrings ? "enabled" : "disabled"); @@ -1949,46 +1949,46 @@ bool FileMapHeader::validate() { (compiler_type == CompilerType::compiler_none); if (!intepreter_is_used && jvmci_compiler_is_enabled != (archive_compiler_type == CompilerType::compiler_jvmci)) { - MetaspaceShared::report_loading_error("The %s's JIT compiler setting (%s)" + AOTMetaspace::report_loading_error("The %s's JIT compiler setting (%s)" " does not equal the current setting (%s).", file_type, compilertype2name(archive_compiler_type), compilertype2name(compiler_type)); return false; } if (TrainingData::have_data()) { if (_type_profile_level != TypeProfileLevel) { - MetaspaceShared::report_loading_error("The %s's TypeProfileLevel setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileLevel setting (%d)" " does not equal the current TypeProfileLevel setting (%d).", file_type, _type_profile_level, TypeProfileLevel); return false; } if (_type_profile_args_limit != TypeProfileArgsLimit) { - MetaspaceShared::report_loading_error("The %s's TypeProfileArgsLimit setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileArgsLimit setting (%d)" " does not equal the current TypeProfileArgsLimit setting (%d).", file_type, _type_profile_args_limit, TypeProfileArgsLimit); return false; } if (_type_profile_parms_limit != TypeProfileParmsLimit) { - MetaspaceShared::report_loading_error("The %s's TypeProfileParamsLimit setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileParamsLimit setting (%d)" " does not equal the current TypeProfileParamsLimit setting (%d).", file_type, _type_profile_args_limit, TypeProfileArgsLimit); return false; } if (_type_profile_width != TypeProfileWidth) { - MetaspaceShared::report_loading_error("The %s's TypeProfileWidth setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileWidth setting (%d)" " does not equal the current TypeProfileWidth setting (%d).", file_type, (int)_type_profile_width, (int)TypeProfileWidth); return false; } if (_bci_profile_width != BciProfileWidth) { - MetaspaceShared::report_loading_error("The %s's BciProfileWidth setting (%d)" + AOTMetaspace::report_loading_error("The %s's BciProfileWidth setting (%d)" " does not equal the current BciProfileWidth setting (%d).", file_type, (int)_bci_profile_width, (int)BciProfileWidth); return false; } if (_type_profile_casts != TypeProfileCasts) { - MetaspaceShared::report_loading_error("The %s's TypeProfileCasts setting (%s)" + AOTMetaspace::report_loading_error("The %s's TypeProfileCasts setting (%s)" " does not equal the current TypeProfileCasts setting (%s).", file_type, _type_profile_casts ? "enabled" : "disabled", TypeProfileCasts ? "enabled" : "disabled"); @@ -1997,7 +1997,7 @@ bool FileMapHeader::validate() { } if (_profile_traps != ProfileTraps) { - MetaspaceShared::report_loading_error("The %s's ProfileTraps setting (%s)" + AOTMetaspace::report_loading_error("The %s's ProfileTraps setting (%s)" " does not equal the current ProfileTraps setting (%s).", file_type, _profile_traps ? "enabled" : "disabled", ProfileTraps ? "enabled" : "disabled"); @@ -2005,7 +2005,7 @@ bool FileMapHeader::validate() { return false; } if (_spec_trap_limit_extra_entries != SpecTrapLimitExtraEntries) { - MetaspaceShared::report_loading_error("The %s's SpecTrapLimitExtraEntries setting (%d)" + AOTMetaspace::report_loading_error("The %s's SpecTrapLimitExtraEntries setting (%d)" " does not equal the current SpecTrapLimitExtraEntries setting (%d).", file_type, _spec_trap_limit_extra_entries, SpecTrapLimitExtraEntries); return false; @@ -2018,7 +2018,7 @@ bool FileMapHeader::validate() { const char* prop = Arguments::get_property("java.system.class.loader"); if (prop != nullptr) { if (has_aot_linked_classes()) { - MetaspaceShared::report_loading_error("%s has aot-linked classes. It cannot be used when the " + AOTMetaspace::report_loading_error("%s has aot-linked classes. It cannot be used when the " "java.system.class.loader property is specified.", CDSConfig::type_of_archive_being_loaded()); return false; @@ -2032,7 +2032,7 @@ bool FileMapHeader::validate() { if (!_verify_local && BytecodeVerificationLocal) { // we cannot load boot classes, so there's no point of using the CDS archive - MetaspaceShared::report_loading_error("The %s's BytecodeVerificationLocal setting (%s)" + AOTMetaspace::report_loading_error("The %s's BytecodeVerificationLocal setting (%s)" " does not equal the current BytecodeVerificationLocal setting (%s).", file_type, _verify_local ? "enabled" : "disabled", BytecodeVerificationLocal ? "enabled" : "disabled"); @@ -2056,7 +2056,7 @@ bool FileMapHeader::validate() { // Note: _allow_archiving_with_java_agent is set in the shared archive during dump time // while AllowArchivingWithJavaAgent is set during the current run. if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) { - MetaspaceShared::report_loading_error("The setting of the AllowArchivingWithJavaAgent is different " + AOTMetaspace::report_loading_error("The setting of the AllowArchivingWithJavaAgent is different " "from the setting in the %s.", file_type); return false; } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 02390874f39..b40e793a0fd 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_CDS_FILEMAP_HPP #define SHARE_CDS_FILEMAP_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" -#include "cds/metaspaceShared.hpp" #include "include/cds.h" #include "logging/logLevel.hpp" #include "memory/allocation.hpp" @@ -71,7 +71,7 @@ public: size_t mapping_offset() const { return _mapping_offset; } size_t mapping_end_offset() const { return _mapping_offset + used_aligned(); } size_t used() const { return _used; } - size_t used_aligned() const; // aligned up to MetaspaceShared::core_region_alignment() + size_t used_aligned() const; // aligned up to AOTMetaspace::core_region_alignment() char* mapped_base() const { return _mapped_base; } char* mapped_end() const { return mapped_base() + used_aligned(); } bool read_only() const { return _read_only != 0; } diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index 8fc01220a6f..2d237edfd2d 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -184,7 +184,7 @@ void FinalImageRecipes::load_all_classes(TRAPS) { log_error(aot)("Unable to resolve class from CDS archive: %s", ik->external_name()); log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); log_error(aot)("Please check if your VM command-line is the same as in the training run"); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } assert(ik->is_loaded(), "must be"); ik->link_class(CHECK); @@ -208,7 +208,7 @@ void FinalImageRecipes::apply_recipes(TRAPS) { log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); log_error(aot)("Please check if your VM command-line is the same as in the training run"); - MetaspaceShared::unrecoverable_writing_error("Unexpected exception, use -Xlog:aot,exceptions=trace for detail"); + AOTMetaspace::unrecoverable_writing_error("Unexpected exception, use -Xlog:aot,exceptions=trace for detail"); } } diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index cfa2944d974..6b7cffdf321 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassInitializer.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" @@ -35,7 +36,6 @@ #include "cds/cdsEnumKlass.hpp" #include "cds/cdsHeapVerifier.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.inline.hpp" @@ -873,7 +873,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) { ResourceMark rm; log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s%s", ik->external_name(), lambda_msg, testcls_msg); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } bool KlassSubGraphInfo::is_non_early_klass(Klass* k) { @@ -1509,7 +1509,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap ResourceMark rm; log_error(aot, heap)("Cannot archive object " PTR_FORMAT " of class %s", p2i(orig_obj), orig_obj->klass()->external_name()); debug_trace(); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } if (log_is_enabled(Debug, aot, heap) && java_lang_Class::is_instance(orig_obj)) { @@ -1562,7 +1562,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // defined at the top of this file. log_error(aot, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", level); debug_trace(); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } @@ -1592,7 +1592,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // We don't know how to handle an object that has been archived, but some of its reachable // objects cannot be archived. Bail out for now. We might need to fix this in the future if // we have a real use case. - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index c0e89809274..110cdef8796 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_CDS_HEAPSHARED_HPP #define SHARE_CDS_HEAPSHARED_HPP +#include "cds/aotMetaspace.hpp" #include "cds/dumpTimeClassInfo.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "gc/shared/gc_globals.hpp" @@ -432,7 +432,7 @@ private: static void init_scratch_objects_for_basic_type_mirrors(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void init_box_classes(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static bool is_heap_region(int idx) { - CDS_JAVA_HEAP_ONLY(return (idx == MetaspaceShared::hp);) + CDS_JAVA_HEAP_ONLY(return (idx == AOTMetaspace::hp);) NOT_CDS_JAVA_HEAP_RETURN_(false); } diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 4241619385e..966b3eab298 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -23,10 +23,10 @@ */ #include "cds/aotClassFilter.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/lambdaFormInvokers.inline.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoadInfo.hpp" @@ -219,7 +219,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, result->add_to_hierarchy(THREAD); // new class not linked yet. - MetaspaceShared::try_link_class(THREAD, result); + AOTMetaspace::try_link_class(THREAD, result); assert(!HAS_PENDING_EXCEPTION, "Invariant"); result->set_is_generated_shared_class(); diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp index ff7acb15292..91e508bfdc5 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP #define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/javaClasses.hpp" #include "memory/metaspaceClosure.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index 10d2fc35ea9..d93ef5e9c1d 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -75,7 +75,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { } InstanceKlass* RunTimeClassInfo::klass() const { - if (MetaspaceShared::in_aot_cache(this)) { + if (AOTMetaspace::in_aot_cache(this)) { // is inside a mmaped CDS archive. return ArchiveUtils::offset_to_archived_address(_klass_offset); } else { diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index bf41e05eee5..29670f5ec51 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_CDS_RUNTIMECLASSINFO_HPP #define SHARE_CDS_RUNTIMECLASSINFO_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cds_globals.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "memory/metaspaceClosure.hpp" diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 683fc22b27a..8cc00d1feb9 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -22,12 +22,12 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.inline.hpp" diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 132c1c4ca49..062521e7495 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -23,9 +23,9 @@ */ #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classFileParser.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -601,21 +601,21 @@ void Modules::ArchivedProperty::runtime_check() const { bool disable = false; if (runtime_value == nullptr) { if (_archived_value != nullptr) { - MetaspaceShared::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value); + AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value); disable = true; } } else { if (_archived_value == nullptr) { - MetaspaceShared::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value); + AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value); disable = true; } else if (strcmp(runtime_value, _archived_value) != 0) { - MetaspaceShared::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value); + AOTMetaspace::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value); disable = true; } } if (disable) { - MetaspaceShared::report_loading_error("Disabling optimized module handling"); + AOTMetaspace::report_loading_error("Disabling optimized module handling"); CDSConfig::stop_using_optimized_module_handling(); } } diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index cf5d98650ce..6f6409ee27a 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -993,7 +993,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern // but bail out for safety. log_error(aot)("Too many strings to be archived: %zu", items_count_acquire()); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK); diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index e6889e6248d..d0bcca87c14 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -146,7 +146,7 @@ public: "refcount %d", value.refcount()); #if INCLUDE_CDS if (CDSConfig::is_dumping_static_archive()) { - // We have allocated with MetaspaceShared::symbol_space_alloc(). No deallocation is needed. + // We have allocated with AOTMetaspace::symbol_space_alloc(). No deallocation is needed. // Unreferenced Symbols will not be copied into the archive. return; } @@ -185,7 +185,7 @@ private: // the archived symbol of "java/lang/Object" may sometimes be lower than "java/lang/String", and // sometimes be higher. This would cause non-deterministic contents in the archive. DEBUG_ONLY(static void* last = nullptr); - void* p = (void*)MetaspaceShared::symbol_space_alloc(alloc_size); + void* p = (void*)AOTMetaspace::symbol_space_alloc(alloc_size); assert(p > last, "must increase monotonically"); DEBUG_ONLY(last = p); return p; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 946fbc07f28..f4f7f694d6d 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -2001,7 +2001,7 @@ void SystemDictionary::restore_archived_method_handle_intrinsics() { } void SystemDictionary::restore_archived_method_handle_intrinsics_impl(TRAPS) { - Array* list = MetaspaceShared::archived_method_handle_intrinsics(); + Array* list = AOTMetaspace::archived_method_handle_intrinsics(); for (int i = 0; i < list->length(); i++) { methodHandle m(THREAD, list->at(i)); Method::restore_archived_method_handle_intrinsic(m, CHECK); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 7b52dfe46aa..df22db82165 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassFilter.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -38,7 +39,6 @@ #include "cds/heapShared.hpp" #include "cds/lambdaFormInvokers.inline.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/runTimeClassInfo.hpp" #include "cds/unregisteredClasses.hpp" #include "classfile/classFileStream.hpp" @@ -205,7 +205,7 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { } bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(k)) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { // We have reached a super type that's already in the base archive. Treat it // as "not excluded". return false; @@ -300,7 +300,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { if (has_class_failed_verification(k)) { return warn_excluded(k, "Failed verification"); } else if (CDSConfig::is_dumping_aot_linked_classes()) { - // Most loaded classes should have been speculatively linked by MetaspaceShared::link_class_for_cds(). + // Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds(). // However, we do not speculatively link old classes, as they are not recorded by // SystemDictionaryShared::record_linking_constraint(). As a result, such an unlinked // class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), @@ -691,7 +691,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { return check_for_exclusion(ik, p); } else { // No need to check for is_linked() as all eligible classes should have - // already been linked in MetaspaceShared::link_class_for_cds(). + // already been linked in AOTMetaspace::link_class_for_cds(). // Can't take the lock as we are in safepoint. DumpTimeClassInfo* p = _dumptime_table->get(ik); if (p->is_excluded()) { @@ -1124,7 +1124,7 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim } } - if (!MetaspaceShared::in_aot_cache_dynamic_region(name)) { + if (!AOTMetaspace::in_aot_cache_dynamic_region(name)) { // The names of all shared classes in the static dict must also be in the // static archive record = static_dict->lookup(name, hash, 0); diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 7e53f493c47..a24bae03137 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -25,10 +25,10 @@ #include "asm/macroAssembler.hpp" #include "cds/aotCacheAccess.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/javaAssertions.hpp" #include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" @@ -96,7 +96,7 @@ static void report_store_failure() { // where we set number of compiler threads for AOT assembly phase. // // 3. We determine presence of AOT code in AOT Cache in -// MetaspaceShared::open_static_archive() which is calles +// AOTMetaspace::open_static_archive() which is calles // after compilationPolicy_init() but before codeCache_init(). // // 4. AOTCodeCache::initialize() is called during universe_init() @@ -165,7 +165,7 @@ uint AOTCodeCache::max_aot_code_size() { return _max_aot_code_size; } -// It is called from MetaspaceShared::initialize_shared_spaces() +// It is called from AOTMetaspace::initialize_shared_spaces() // which is called from universe_init(). // At this point all AOT class linking seetings are finilized // and AOT cache is open so we can map AOT code region. diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index 685fba47349..a7bc896172c 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -35,7 +35,7 @@ // // Also, this is a C header file. Do not use C++ here. -#define NUM_CDS_REGIONS 5 // this must be the same as MetaspaceShared::n_regions +#define NUM_CDS_REGIONS 5 // this must be the same as AOTMetaspace::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 #define CDS_PREIMAGE_ARCHIVE_MAGIC 0xcafea07c @@ -72,7 +72,7 @@ typedef struct CDSFileMapRegion { size_t _ptrmap_size_in_bits; char* _mapped_base; // Actually mapped address used for mapping the core regions. At that address the // zero nklass protection zone is established; following that (at offset - // MetaspaceShared::protection_zone_size()) the lowest core region (rw for the + // AOTMetaspace::protection_zone_size()) the lowest core region (rw for the // static archive) is is mapped. bool _in_reserved_space; // Is this region in a ReservedSpace } CDSFileMapRegion; diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 05590add8ff..640e3ab3fff 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -23,7 +23,7 @@ */ #include "asm/macroAssembler.inline.hpp" -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "compiler/disassembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeStream.hpp" diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index 41a96eebfad..a9ee92cb570 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/vmClasses.hpp" #include "interpreter/bytecodes.hpp" #include "interpreter/bytecodeStream.hpp" diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 1983fbc870c..2a744c12c01 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -24,8 +24,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoaderData.hpp" #include "gc/shared/collectedHeap.hpp" #include "logging/log.hpp" @@ -721,7 +721,7 @@ void Metaspace::global_initialize() { metaspace::ChunkHeaderPool::initialize(); if (CDSConfig::is_dumping_static_archive()) { - MetaspaceShared::initialize_for_static_dump(); + AOTMetaspace::initialize_for_static_dump(); } // If UseCompressedClassPointers=1, we have two cases: @@ -740,7 +740,7 @@ void Metaspace::global_initialize() { if (!FLAG_IS_DEFAULT(CompressedClassSpaceBaseAddress)) { log_warning(metaspace)("CDS active - ignoring CompressedClassSpaceBaseAddress."); } - MetaspaceShared::initialize_runtime_shared_and_meta_spaces(); + AOTMetaspace::initialize_runtime_shared_and_meta_spaces(); // If any of the archived space fails to map, UseSharedSpaces // is reset to false. } @@ -853,7 +853,7 @@ void Metaspace::global_initialize() { LogTarget(Info, gc, metaspace) lt; if (lt.is_enabled()) { LogStream ls(lt); - CDS_ONLY(MetaspaceShared::print_on(&ls);) + CDS_ONLY(AOTMetaspace::print_on(&ls);) Metaspace::print_compressed_class_space(&ls); CompressedKlassPointers::print_mode(&ls); } @@ -1037,7 +1037,7 @@ void Metaspace::purge(bool classes_unloaded) { // Returns true if pointer points into one of the metaspace regions, or // into the class space. bool Metaspace::in_aot_cache(const void* ptr) { - return MetaspaceShared::in_aot_cache(ptr); + return AOTMetaspace::in_aot_cache(ptr); } // Returns true if pointer points into one of the non-class-space metaspace regions. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index b2c3c29a812..408dbf6d23f 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -31,7 +31,7 @@ #include "utilities/globalDefinitions.hpp" class ClassLoaderData; -class MetaspaceShared; +class AOTMetaspace; class MetaspaceTracer; class Mutex; class outputStream; @@ -43,7 +43,7 @@ class ReservedSpace; // (auxiliary stuff goes into MetaspaceUtils) class Metaspace : public AllStatic { - friend class MetaspaceShared; + friend class AOTMetaspace; public: enum MetadataType { diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 8afa17b0b3d..f34a771138d 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -22,11 +22,11 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderDataShared.hpp" @@ -878,7 +878,7 @@ jint universe_init() { ObjLayout::initialize(); #ifdef _LP64 - MetaspaceShared::adjust_heap_sizes_for_dumping(); + AOTMetaspace::adjust_heap_sizes_for_dumping(); #endif // _LP64 GCConfig::arguments()->initialize_heap_sizes(); @@ -904,7 +904,7 @@ jint universe_init() { if (CDSConfig::is_using_archive()) { // Read the data structures supporting the shared spaces (shared // system dictionary, symbol table, etc.) - MetaspaceShared::initialize_shared_spaces(); + AOTMetaspace::initialize_shared_spaces(); } #endif @@ -1161,7 +1161,7 @@ bool universe_post_init() { MemoryService::set_universe_heap(Universe::heap()); #if INCLUDE_CDS - MetaspaceShared::post_initialize(CHECK_false); + AOTMetaspace::post_initialize(CHECK_false); #endif return true; } diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index ee4c05e1e06..90874d2392d 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ class Universe: AllStatic { friend class VMStructs; friend class VM_PopulateDumpSharedSpace; friend class Metaspace; - friend class MetaspaceShared; + friend class AOTMetaspace; friend class vmClasses; friend jint universe_init(); diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 198ff1ef75e..32a86c7ab24 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/javaClasses.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/vmClasses.hpp" @@ -259,9 +259,9 @@ void ArrayKlass::log_array_class_load(Klass* k) { LogStream ls(lt); ResourceMark rm; ls.print("%s", k->name()->as_klass_external_name()); - if (MetaspaceShared::in_aot_cache_dynamic_region((void*)k)) { + if (AOTMetaspace::in_aot_cache_dynamic_region((void*)k)) { ls.print(" source: shared objects file (top)"); - } else if (MetaspaceShared::in_aot_cache_static_region((void*)k)) { + } else if (AOTMetaspace::in_aot_cache_static_region((void*)k)) { ls.print(" source: shared objects file"); } ls.cr(); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 568ccd72176..1afc59d8da1 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -23,12 +23,12 @@ */ #include "cds/aotClassInitializer.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" #include "cds/cdsEnumKlass.hpp" #include "cds/classListWriter.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classFileParser.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" @@ -2763,7 +2763,7 @@ void InstanceKlass::init_shared_package_entry() { } } else if (CDSConfig::is_dumping_dynamic_archive() && CDSConfig::is_using_full_module_graph() && - MetaspaceShared::in_aot_cache(_package_entry)) { + AOTMetaspace::in_aot_cache(_package_entry)) { // _package_entry is an archived package in the base archive. Leave it as is. } else { _package_entry = nullptr; @@ -2845,7 +2845,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl // retrieved during dump time. // Verification of archived old classes will be performed during run time. bool InstanceKlass::can_be_verified_at_dumptime() const { - if (MetaspaceShared::in_aot_cache(this)) { + if (AOTMetaspace::in_aot_cache(this)) { // This is a class that was dumped into the base archive, so we know // it was verified at dump time. return true; @@ -3088,7 +3088,7 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, PackageEntry* pkg_ if (in_aot_cache() && _package_entry != nullptr) { if (CDSConfig::is_using_full_module_graph() && _package_entry == pkg_entry) { // we can use the saved package - assert(MetaspaceShared::in_aot_cache(_package_entry), "must be"); + assert(AOTMetaspace::in_aot_cache(_package_entry), "must be"); return; } else { _package_entry = nullptr; @@ -3971,7 +3971,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, } } else { assert(this->in_aot_cache(), "must be"); - if (MetaspaceShared::in_aot_cache_dynamic_region((void*)this)) { + if (AOTMetaspace::in_aot_cache_dynamic_region((void*)this)) { info_stream.print(" source: shared objects file (top)"); } else { info_stream.print(" source: shared objects file"); diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index ce4e322930f..ead413dfa2c 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -22,7 +22,7 @@ * */ -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" @@ -50,7 +50,7 @@ inline InstanceKlass* klassVtable::ik() const { } bool klassVtable::is_preinitialized_vtable() { - return _klass->in_aot_cache() && !MetaspaceShared::remapped_readwrite() && _klass->verified_at_dump_time(); + return _klass->in_aot_cache() && !AOTMetaspace::remapped_readwrite() && _klass->verified_at_dump_time(); } @@ -1089,8 +1089,8 @@ void itableMethodEntry::initialize(InstanceKlass* klass, Method* m) { if (m == nullptr) return; #ifdef ASSERT - if (MetaspaceShared::in_aot_cache((void*)&_method) && - !MetaspaceShared::remapped_readwrite() && + if (AOTMetaspace::in_aot_cache((void*)&_method) && + !AOTMetaspace::remapped_readwrite() && m->method_holder()->verified_at_dump_time() && klass->verified_at_dump_time()) { // At runtime initialize_itable is rerun as part of link_class_impl() diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 03330aee209..69203189bb7 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -22,9 +22,9 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" #include "cds/cppVtables.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/metadataOnStackMark.hpp" @@ -446,7 +446,7 @@ void Method::restore_unshareable_info(TRAPS) { #endif void Method::set_vtable_index(int index) { - if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !AOTMetaspace::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_vtable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. @@ -457,7 +457,7 @@ void Method::set_vtable_index(int index) { } void Method::set_itable_index(int index) { - if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !AOTMetaspace::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_itable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. The dumptime diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index 0f2cd8e6e6b..3a24a78936b 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -23,7 +23,6 @@ */ #include "cds/archiveBuilder.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/vmSymbols.hpp" diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 49153b3e931..845dc20c0d0 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -23,7 +23,6 @@ */ #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "ci/ciEnv.hpp" #include "ci/ciMetadata.hpp" #include "classfile/classLoaderData.hpp" diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 511f9efdfb9..99c8a56c727 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotClassInitializer.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListParser.hpp" #include "cds/classListWriter.hpp" @@ -3503,7 +3504,7 @@ JVM_ENTRY(void, JVM_DumpClassListToFile(JNIEnv *env, jstring listFileName)) ResourceMark rm(THREAD); Handle file_handle(THREAD, JNIHandles::resolve_non_null(listFileName)); char* file_name = java_lang_String::as_utf8_string(file_handle()); - MetaspaceShared::dump_loaded_classes(file_name, THREAD); + AOTMetaspace::dump_loaded_classes(file_name, THREAD); #endif // INCLUDE_CDS JVM_END diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index dc2d621f694..d4ee34b881f 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoadInfo.hpp" @@ -254,7 +254,7 @@ void VM_RedefineClasses::doit() { // shared readwrite, private just in case we need to redefine // a shared class. We do the remap during the doit() phase of // the safepoint to be safer. - if (!MetaspaceShared::remap_shared_readonly_as_readwrite()) { + if (!AOTMetaspace::remap_shared_readonly_as_readwrite()) { log_info(redefine, class, load)("failed to remap shared readonly space to readwrite, private"); _res = JVMTI_ERROR_INTERNAL; _timer_vm_op_doit.stop(); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 63920583e18..cbb135a82d9 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -23,11 +23,11 @@ */ #include "cds.h" +#include "cds/aotMetaspace.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConstants.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderStats.hpp" @@ -1884,9 +1884,9 @@ WB_ENTRY(jlong, WB_MetaspaceCapacityUntilGC(JNIEnv* env, jobject wb)) WB_END // The function is only valid when CDS is available. -WB_ENTRY(jlong, WB_MetaspaceSharedRegionAlignment(JNIEnv* env, jobject wb)) +WB_ENTRY(jlong, WB_AOTMetaspaceRegionAlignment(JNIEnv* env, jobject wb)) #if INCLUDE_CDS - return (jlong)MetaspaceShared::core_region_alignment(); + return (jlong)AOTMetaspace::core_region_alignment(); #else ShouldNotReachHere(); return 0L; @@ -2154,7 +2154,7 @@ WB_ENTRY(jboolean, WB_IsSharedInternedString(JNIEnv* env, jobject wb, jobject st WB_END WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) - return (jboolean)MetaspaceShared::in_aot_cache(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + return (jboolean)AOTMetaspace::in_aot_cache(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); WB_END WB_ENTRY(jboolean, WB_AreSharedStringsMapped(JNIEnv* env)) @@ -2887,7 +2887,7 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/ClassLoader;J)J", (void*)&WB_AllocateMetaspace }, {CC"incMetaspaceCapacityUntilGC", CC"(J)J", (void*)&WB_IncMetaspaceCapacityUntilGC }, {CC"metaspaceCapacityUntilGC", CC"()J", (void*)&WB_MetaspaceCapacityUntilGC }, - {CC"metaspaceSharedRegionAlignment", CC"()J", (void*)&WB_MetaspaceSharedRegionAlignment }, + {CC"metaspaceSharedRegionAlignment", CC"()J", (void*)&WB_AOTMetaspaceRegionAlignment }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 351fd1ebb89..997dd1f802a 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" @@ -449,7 +450,7 @@ void before_exit(JavaThread* thread, bool halt) { ClassListWriter::write_resolved_constants(); if (CDSConfig::is_dumping_preimage_static_archive()) { - MetaspaceShared::preload_and_dump(thread); + AOTMetaspace::preload_and_dump(thread); } #endif diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 5ba3499efbe..3cf1058b6f7 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -25,10 +25,10 @@ */ #include "cds/aotLinkedClassBulkLoader.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" #include "classfile/javaThreadStatus.hpp" @@ -889,10 +889,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { if (CDSConfig::is_dumping_classic_static_archive()) { // Classic -Xshare:dump, aka "old workflow" - MetaspaceShared::preload_and_dump(CHECK_JNI_ERR); + AOTMetaspace::preload_and_dump(CHECK_JNI_ERR); } else if (CDSConfig::is_dumping_final_static_archive()) { tty->print_cr("Reading AOTConfiguration %s and writing AOTCache %s", AOTConfiguration, AOTCache); - MetaspaceShared::preload_and_dump(CHECK_JNI_ERR); + AOTMetaspace::preload_and_dump(CHECK_JNI_ERR); } if (log_is_enabled(Info, perf, class, link)) { diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 19c9773dfe5..a4d44a96878 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -24,7 +24,7 @@ * */ -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "code/codeCache.hpp" #include "compiler/compilationFailureInfo.hpp" #include "compiler/compilationMemoryStatistic.hpp" @@ -1199,7 +1199,7 @@ void VMError::report(outputStream* st, bool _verbose) { st->cr(); STEP_IF("printing compressed klass pointers mode", _verbose && UseCompressedClassPointers) - CDS_ONLY(MetaspaceShared::print_on(st);) + CDS_ONLY(AOTMetaspace::print_on(st);) Metaspace::print_compressed_class_space(st); CompressedKlassPointers::print_mode(st); st->cr(); @@ -1414,7 +1414,7 @@ void VMError::print_vm_info(outputStream* st) { // STEP("printing compressed class ptrs mode") if (UseCompressedClassPointers) { - CDS_ONLY(MetaspaceShared::print_on(st);) + CDS_ONLY(AOTMetaspace::print_on(st);) Metaspace::print_compressed_class_space(st); CompressedKlassPointers::print_mode(st); st->cr(); diff --git a/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java b/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java index 8184f272af7..e38273c0484 100644 --- a/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java +++ b/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java @@ -59,7 +59,7 @@ public class SpaceUtilizationCheck { Pattern pattern = Pattern.compile("(..) space: *([0-9]+).* out of *([0-9]+) bytes .* at 0x([0-9a0-f]+)"); WhiteBox wb = WhiteBox.getWhiteBox(); long reserve_alignment = wb.metaspaceSharedRegionAlignment(); - System.out.println("MetaspaceShared::core_region_alignment() = " + reserve_alignment); + System.out.println("AOTMetaspace::core_region_alignment() = " + reserve_alignment); // Look for output like this. The pattern will only match the first 2 regions, which is what we need to check // @@ -90,7 +90,7 @@ public class SpaceUtilizationCheck { } if (unused > reserve_alignment) { // [1] Check for unused space - throw new RuntimeException("Unused space (" + unused + ") must be smaller than MetaspaceShared::core_region_alignment() (" + + throw new RuntimeException("Unused space (" + unused + ") must be smaller than AOTMetaspace::core_region_alignment() (" + reserve_alignment + ")"); } if (last_region >= 0 && address != last_region) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index 2ed29454df7..f2d3575597f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java @@ -45,7 +45,7 @@ public class SharedArchiveConsistency { private static int genericHeaderMinVersion; // minimum supported CDS version private static int currentCDSArchiveVersion; // current CDS version in java process - // The following should be consistent with the enum in the C++ MetaspaceShared class + // The following should be consistent with the enum in the C++ AOTMetaspace class public static String[] shared_region_name = { "rw", // ReadWrite "ro", // ReadOnly diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index f616b22ef38..35cee750822 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java @@ -67,9 +67,9 @@ public class CDSArchiveUtils { private static int staticArchiveHeaderSize; // static archive file header size private static int dynamicArchiveHeaderSize; // dynamic archive file header size private static int cdsFileMapRegionSize; // size of CDSFileMapRegion - private static long alignment; // MetaspaceShared::core_region_alignment + private static long alignment; // AOTMetaspace::core_region_alignment - // The following should be consistent with the enum in the C++ MetaspaceShared class + // The following should be consistent with the enum in the C++ AOTMetaspace class private static String[] shared_region_name = { "rw", // ReadWrite "ro", // ReadOnly From 8520fd3f6a8d00d3ab0b01af6ce2307f74258fb6 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 4 Sep 2025 16:50:58 +0000 Subject: [PATCH 137/295] 8366365: [test] test/lib-test/jdk/test/whitebox/CPUInfoTest.java should be updated Reviewed-by: kvn, sviswanathan --- test/lib-test/jdk/test/whitebox/CPUInfoTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java index 8f0ef108885..809953a1263 100644 --- a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java +++ b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java @@ -66,7 +66,8 @@ public class CPUInfoTest { "hv", "fsrm", "avx512_bitalg", "gfni", "f16c", "pku", "ospke", "cet_ibt", "cet_ss", "avx512_ifma", "serialize", "avx_ifma", - "apx_f", "avx10_1", "avx10_2" + "apx_f", "avx10_1", "avx10_2", "avx512_fp16", + "sha512", "hybrid" ); // @formatter:on // Checkstyle: resume From 1dc1d56f79e10c9b4c5c8b42a80a191f7b14c738 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 4 Sep 2025 16:57:36 +0000 Subject: [PATCH 138/295] 8363858: [perf] OptimizeFill may use wide set of intrinsics Reviewed-by: roland, sviswanathan --- src/hotspot/cpu/x86/vm_version_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 1c9f8ed2e40..094ab370190 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1665,7 +1665,7 @@ void VM_Version::get_processor_features() { #ifdef COMPILER2 if (FLAG_IS_DEFAULT(OptimizeFill)) { - if (MaxVectorSize < 32 || !VM_Version::supports_avx512vlbw()) { + if (MaxVectorSize < 32 || (!EnableX86ECoreOpts && !VM_Version::supports_avx512vlbw())) { OptimizeFill = false; } } From 945aaf893219f9ead94fd8aae4994f7b520f64bf Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 4 Sep 2025 19:00:39 +0000 Subject: [PATCH 139/295] 8366897: RBTreeTest.IntrusiveCustomVerifyTest and RBTreeTest.CustomVerify tests fail on non-debug builds Reviewed-by: ayang --- src/hotspot/share/utilities/rbTree.inline.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 16150e41be8..f28923eb867 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -127,7 +127,8 @@ template inline void IntrusiveRBNode::verify( size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path, size_t& tree_depth, bool expect_visited, NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const { - assert(extra_verifier(static_cast(this)), "user provided verifier failed"); + bool extra_verifier_result = extra_verifier(static_cast(this)); + assert(extra_verifier_result, "user provided verifier failed"); assert(expect_visited != _visited, "node already visited"); DEBUG_ONLY(_visited = !_visited); From 581070715ab1ef081032b78ceb3c2cfbdbcff611 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 4 Sep 2025 21:58:08 +0000 Subject: [PATCH 140/295] 8366102: Clarification Needed: Symbolic Link Handling in File API Specifications Reviewed-by: alanb --- src/java.base/share/classes/java/io/File.java | 187 +++++++++--------- 1 file changed, 99 insertions(+), 88 deletions(-) diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index bb216366344..494dac7f51e 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -80,17 +80,22 @@ import jdk.internal.util.StaticProperty; * {@code user.dir}, and is typically the directory in which the Java * virtual machine was invoked. * - *

          Unless otherwise noted, {@linkplain java.nio.file##links symbolic links} - * are automatically redirected to the target of the link, whether they - * are provided by a pathname string or via a {@code File} object. + *

          Many operating systems and file systems have support for + * {@linkplain java.nio.file##links symbolic links}. + * A symbolic link is a special file that serves as a reference to another file. + * Unless otherwise specified, symbolic links are transparent to applications + * and operations on files that are symbolic links are automatically redirected + * to the target of the link. Methods that only operate on the abstract + * pathname do not access the file system and thus do not resolve symbolic + * links. * *

          The parent of an abstract pathname may be obtained by invoking * the {@link #getParent} method of this class and consists of the pathname's * prefix and each name in the pathname's name sequence except for the last. * Each directory's absolute pathname is an ancestor of any {@code File} * object with an absolute abstract pathname which begins with the directory's - * absolute pathname. For example, the directory denoted by the abstract - * pathname {@code "/usr"} is an ancestor of the directory denoted by the + * absolute pathname. For example, the directory located by the abstract + * pathname {@code "/usr"} is an ancestor of the directory located by the * pathname {@code "/usr/local/bin"}. * *

          The prefix concept is used to handle root directories on UNIX platforms, @@ -113,8 +118,8 @@ import jdk.internal.util.StaticProperty; * *

        * - *

        Instances of this class may or may not denote an actual file-system - * object such as a file or a directory. If it does denote such an object + *

        Instances of this class may or may not locate an actual file-system + * object such as a file or a directory. If it does locate such an object * then that object resides in a partition. A partition is an * operating system-specific portion of storage for a file system. A single * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may @@ -448,12 +453,12 @@ public class File /* -- Path-component accessors -- */ /** - * Returns the name of the file or directory denoted by this abstract + * Returns the name component of this abstract * pathname. This is just the last name in the pathname's name * sequence. If the pathname's name sequence is empty, then the empty * string is returned. * - * @return The name of the file or directory denoted by this abstract + * @return The name component of this abstract * pathname, or the empty string if this pathname's name sequence * is empty */ @@ -592,7 +597,7 @@ public class File * symbolic links, and converting drive letters to a standard case (on * Microsoft Windows platforms). * - *

        Every pathname that denotes an existing file or directory has a + *

        Every pathname that locates an existing file or directory has a * unique canonical form. Every pathname that denotes a nonexistent file * or directory also has a unique canonical form. The canonical form of * the pathname of a nonexistent file or directory may be different from @@ -601,7 +606,7 @@ public class File * file or directory may be different from the canonical form of the same * pathname after the file or directory is deleted. * - * @return The canonical pathname string denoting the same file or + * @return The canonical pathname string locating the same file or * directory as this abstract pathname * * @throws IOException @@ -623,7 +628,7 @@ public class File * Returns the canonical form of this abstract pathname. Equivalent to * new File(this.{@link #getCanonicalPath}). * - * @return The canonical pathname string denoting the same file or + * @return The canonical pathname string locating the same file or * directory as this abstract pathname * * @throws IOException @@ -656,7 +661,7 @@ public class File /** * Converts this abstract pathname into a {@code file:} URL. The * exact form of the URL is system-dependent. If it can be determined that - * the file denoted by this abstract pathname is a directory, then the + * the file located by this abstract pathname is a directory, then the * resulting URL will end with a slash. * * @return A URL object representing the equivalent file URL @@ -689,7 +694,7 @@ public class File * Constructs a {@code file:} URI that represents this abstract pathname. * *

        The exact form of the URI is system-dependent. If it can be - * determined that the file denoted by this abstract pathname is a + * determined that the file located by this abstract pathname is a * directory, then the resulting URI will end with a slash. * *

        For a given abstract pathname f, it is guaranteed that @@ -740,13 +745,13 @@ public class File /* -- Attribute accessors -- */ /** - * Tests whether the application can read the file denoted by this + * Tests whether the application can read the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to read * files that are marked as unreadable. Consequently, this method may return * {@code true} even though the file does not have read permissions. * - * @return {@code true} if and only if the file specified by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and can be read by the * application; {@code false} otherwise */ @@ -758,14 +763,14 @@ public class File } /** - * Tests whether the application can modify the file denoted by this + * Tests whether the application can modify the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to modify * files that are marked read-only. Consequently, this method may return * {@code true} even though the file is marked read-only. * * @return {@code true} if and only if the file system actually - * contains a file denoted by this abstract pathname and + * contains a file located by this abstract pathname and * the application is allowed to write to the file; * {@code false} otherwise. */ @@ -777,10 +782,10 @@ public class File } /** - * Tests whether the file or directory denoted by this abstract pathname + * Tests whether the file or directory located by this abstract pathname * exists. * - * @return {@code true} if and only if the file or directory denoted + * @return {@code true} if and only if the file or directory located * by this abstract pathname exists; {@code false} otherwise */ public boolean exists() { @@ -791,7 +796,7 @@ public class File } /** - * Tests whether the file denoted by this abstract pathname is a + * Tests whether the file located by this abstract pathname is a * directory. * *

        Where it is required to distinguish an I/O exception from the case @@ -800,7 +805,7 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and is a directory; * {@code false} otherwise */ @@ -812,7 +817,7 @@ public class File } /** - * Tests whether the file denoted by this abstract pathname is a normal + * Tests whether the file located by this abstract pathname is a normal * file. A file is normal if it is not a directory and, in * addition, satisfies other system-dependent criteria. Any non-directory * file created by a Java application is guaranteed to be a normal file. @@ -823,7 +828,7 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and is a normal file; * {@code false} otherwise */ @@ -835,7 +840,7 @@ public class File } /** - * Tests whether the file named by this abstract pathname is a hidden + * Tests whether the file located by this abstract pathname is a hidden * file. The exact definition of hidden is system-dependent. On * UNIX systems, a file is considered to be hidden if its name begins with * a period character ({@code '.'}). On Microsoft Windows systems, a file @@ -849,7 +854,7 @@ public class File * with a period character. On Windows systems, a symbolic link is * considered hidden if its target is so marked in the filesystem. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname is hidden according to the conventions of the * underlying platform * @@ -863,7 +868,7 @@ public class File } /** - * Returns the time that the file denoted by this abstract pathname was + * Returns the time that the file located by this abstract pathname was * last modified. * * @apiNote @@ -897,8 +902,8 @@ public class File } /** - * Returns the length of the file denoted by this abstract pathname. - * The return value is unspecified if this pathname denotes a directory. + * Returns the length of the file located by this abstract pathname. + * The return value is unspecified if this pathname locates a directory. * *

        Where it is required to distinguish an I/O exception from the case * that {@code 0L} is returned, or where several attributes of the same file @@ -906,10 +911,10 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return The length, in bytes, of the file denoted by this abstract + * @return The length, in bytes, of the file located by this abstract * pathname, or {@code 0L} if the file does not exist. Some * operating systems may return {@code 0L} for pathnames - * denoting system-dependent entities such as devices or pipes. + * locating system-dependent entities such as devices or pipes. */ public long length() { if (isInvalid()) { @@ -935,7 +940,7 @@ public class File * * @return {@code true} if the named file does not exist and was * successfully created; {@code false} if the named file - * already exists + * already exists, including if it is a symbolic link * * @throws IOException * If an I/O error occurred @@ -950,9 +955,9 @@ public class File } /** - * Deletes the file or directory denoted by this abstract pathname. If - * this pathname denotes a directory, then the directory must be empty in - * order to be deleted. If this pathname denotes a symbolic link, then the + * Deletes the file or directory located by this abstract pathname. If + * this pathname locates a directory, then the directory must be empty in + * order to be deleted. If this pathname locates a symbolic link, then the * link itself, not its target, will be deleted. * *

        Note that the {@link java.nio.file.Files} class defines the {@link @@ -971,9 +976,9 @@ public class File } /** - * Requests that the file or directory denoted by this abstract + * Requests that the file or directory located by this abstract * pathname be deleted when the virtual machine terminates. - * If this pathname denotes a symbolic link, then the + * If this pathname locates a symbolic link, then the * link itself, not its target, will be deleted. * Files (or directories) are deleted in the reverse order that * they are registered. Invoking this method to delete a file or @@ -1003,12 +1008,12 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname. + * directory located by this abstract pathname. * - *

        If this abstract pathname does not denote a directory, then this + *

        If this abstract pathname does not locate a directory, then this * method returns {@code null}. Otherwise an array of strings is * returned, one for each file or directory in the directory. Names - * denoting the directory itself and the directory's parent directory are + * locating the directory itself and the directory's parent directory are * not included in the result. Each string is a file name rather than a * complete path. * @@ -1023,9 +1028,9 @@ public class File * may be more responsive when working with remote directories. * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be + * directory located by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if - * this abstract pathname does not denote a directory, or if an + * this abstract pathname does not locate a directory, or if an * I/O error occurs. */ public String[] list() { @@ -1034,13 +1039,13 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The strings are + * directory located by this abstract pathname. The strings are * ensured to represent normalized paths. * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be + * directory located by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if - * this abstract pathname does not denote a directory, or if an + * this abstract pathname does not locate a directory, or if an * I/O error occurs. */ private final String[] normalizedList() { @@ -1060,7 +1065,7 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname that satisfy the specified + * directory located by this abstract pathname that satisfy the specified * filter. The behavior of this method is the same as that of the * {@link #list()} method, except that the strings in the returned array * must satisfy the filter. If the given {@code filter} is {@code null} @@ -1068,16 +1073,16 @@ public class File * and only if the value {@code true} results when the {@link * FilenameFilter#accept FilenameFilter.accept(File, String)} method * of the filter is invoked on this abstract pathname and the name of a - * file or directory in the directory that it denotes. + * file or directory in the directory that it locates. * * @param filter * A filename filter * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname that were accepted + * directory located by this abstract pathname that were accepted * by the given {@code filter}. The array will be empty if the * directory is empty or if no names were accepted by the filter. - * Returns {@code null} if this abstract pathname does not denote + * Returns {@code null} if this abstract pathname does not locate * a directory, or if an I/O error occurs. * * @see java.nio.file.Files#newDirectoryStream(Path,String) @@ -1097,13 +1102,13 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files in the - * directory denoted by this abstract pathname. + * Returns an array of abstract pathnames locating the files in the + * directory located by this abstract pathname. * - *

        If this abstract pathname does not denote a directory, then this + *

        If this abstract pathname does not locate a directory, then this * method returns {@code null}. Otherwise an array of {@code File} objects * is returned, one for each file or directory in the directory. Pathnames - * denoting the directory itself and the directory's parent directory are + * locating the directory itself and the directory's parent directory are * not included in the result. Each resulting abstract pathname is * constructed from this abstract pathname using the {@link #File(File, * String) File(File, String)} constructor. Therefore if this @@ -1121,10 +1126,10 @@ public class File * directory. This may use less resources when working with very large * directories. * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1141,8 +1146,8 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname that + * Returns an array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname that * satisfy the specified filter. The behavior of this method is the same * as that of the {@link #listFiles()} method, except that the pathnames in * the returned array must satisfy the filter. If the given {@code filter} @@ -1151,15 +1156,15 @@ public class File * the {@link FilenameFilter#accept * FilenameFilter.accept(File, String)} method of the filter is * invoked on this abstract pathname and the name of a file or directory in - * the directory that it denotes. + * the directory that it locates. * * @param filter * A filename filter * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1177,8 +1182,8 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname that + * Returns an array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname that * satisfy the specified filter. The behavior of this method is the same * as that of the {@link #listFiles()} method, except that the pathnames in * the returned array must satisfy the filter. If the given {@code filter} @@ -1190,10 +1195,10 @@ public class File * @param filter * A file filter * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1255,8 +1260,8 @@ public class File } /** - * Renames the file denoted by this abstract pathname. If this pathname - * denotes a symbolic link, then the link itself, not its target, will be + * Renames the file located by this abstract pathname. If this pathname + * locates a symbolic link, then the link itself, not its target, will be * renamed. * *

        Many aspects of the behavior of this method are inherently @@ -1291,7 +1296,7 @@ public class File } /** - * Sets the last-modified time of the file or directory named by this + * Sets the last-modified time of the file or directory located by this * abstract pathname. * *

        All platforms support file-modification times to the nearest second, @@ -1320,7 +1325,7 @@ public class File } /** - * Marks the file or directory named by this abstract pathname so that + * Marks the file or directory located by this abstract pathname so that * only read operations are allowed. After invoking this method the file * or directory will not change until it is either deleted or marked * to allow write access. On some platforms it may be possible to start the @@ -1341,7 +1346,8 @@ public class File } /** - * Sets the owner's or everybody's write permission for this abstract + * Sets the owner's or everybody's write permission of the file or + * directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to modify files that * disallow write operations. @@ -1375,7 +1381,8 @@ public class File } /** - * A convenience method to set the owner's write permission for this abstract + * A convenience method to set the owner's write permission for the file + * or directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to modify files that * disallow write operations. @@ -1402,7 +1409,8 @@ public class File } /** - * Sets the owner's or everybody's read permission for this abstract + * Sets the owner's or everybody's read permission for the file or directory + * located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to read files that are * marked as unreadable. @@ -1442,7 +1450,8 @@ public class File } /** - * A convenience method to set the owner's read permission for this abstract + * A convenience method to set the owner's read permission for the file + * or directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to read files that are * marked as unreadable. @@ -1475,7 +1484,8 @@ public class File } /** - * Sets the owner's or everybody's execute permission for this abstract + * Sets the owner's or everybody's execute permission for the file or + * directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to execute files that are * not marked executable. @@ -1515,7 +1525,8 @@ public class File } /** - * A convenience method to set the owner's execute permission for this + * A convenience method to set the owner's execute permission for the file + * or directory located by this * abstract pathname. On some platforms it may be possible to start the Java * virtual machine with special privileges that allow it to execute files * that are not marked executable. @@ -1548,7 +1559,7 @@ public class File } /** - * Tests whether the application can execute the file denoted by this + * Tests whether the application can execute the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to execute * files that are not marked executable. Consequently, this method may return @@ -1794,7 +1805,7 @@ public class File * returns successfully then it is guaranteed that: * *

          - *
        1. The file denoted by the returned abstract pathname did not exist + *
        2. The file located by the returned abstract pathname did not exist * before this method was invoked, and *
        3. Neither this method nor any of its variants will return the same * abstract pathname again in the current invocation of the virtual @@ -1837,7 +1848,7 @@ public class File * to have any effect upon the temporary directory used by this method. * *

          If the {@code directory} argument is not {@code null} and its - * abstract pathname is valid and denotes an existing, writable directory, + * abstract pathname is valid and locates an existing, writable directory, * then the file will be created in that directory. Otherwise the file will * not be created and an {@code IOException} will be thrown. Under no * circumstances will a directory be created at the location specified by @@ -1854,7 +1865,7 @@ public class File * {@code null} if the default temporary-file * directory is to be used * - * @return An abstract pathname denoting a newly-created empty file + * @return An abstract pathname locating a newly-created empty file * * @throws IllegalArgumentException * If the {@code prefix} argument contains fewer than three @@ -1911,7 +1922,7 @@ public class File * name; may be {@code null}, in which case the * suffix {@code ".tmp"} will be used * - * @return An abstract pathname denoting a newly-created empty file + * @return An abstract pathname locating a newly-created empty file * * @throws IllegalArgumentException * If the {@code prefix} argument contains fewer than three @@ -1934,7 +1945,9 @@ public class File * Compares two abstract pathnames lexicographically. The ordering * defined by this method depends upon the underlying system. On UNIX * systems, alphabetic case is significant in comparing pathnames; on - * Microsoft Windows systems it is not. + * Microsoft Windows systems it is not. This method only compares the + * abstract pathnames; it does not access the file system and the file is + * not required to exist. * * @param pathname The abstract pathname to be compared to this abstract * pathname @@ -1958,11 +1971,9 @@ public class File * abstract pathname. Whether or not two abstract * pathnames are equal depends upon the underlying operating system. * On UNIX systems, alphabetic case is significant in comparing pathnames; - * on Microsoft Windows systems it is not. - * - * @apiNote This method only tests whether the abstract pathnames are equal; - * it does not access the file system and the file is not required - * to exist. + * on Microsoft Windows systems it is not. This method only tests whether + * the abstract pathnames are equal; it does not access the file system and + * the file is not required to exist. * * @param obj The object to be compared with this abstract pathname * From b7b64bb6c800b45e32ff37b1b92b5927a3b3fb56 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 4 Sep 2025 22:35:21 +0000 Subject: [PATCH 141/295] 8365937: post_method_exit might incorrectly set was_popped_by_exception and value in the middle of stack unwinding Reviewed-by: dholmes, pchilanomate --- src/hotspot/share/prims/jvmtiExport.cpp | 29 ++-- .../TestMethodExitWithPendingException.java | 58 ++++++++ .../libTestMethodExitWithPendingException.cpp | 126 ++++++++++++++++++ .../TestPoppedByException.java | 50 +++++++ .../libTestPoppedByException.cpp | 86 ++++++++++++ 5 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 26284b41ef0..8c10a371e5a 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1836,25 +1836,20 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur return; } - // return a flag when a method terminates by throwing an exception - // i.e. if an exception is thrown and it's not caught by the current method - bool exception_exit = state->is_exception_detected() && !state->is_exception_caught(); Handle result; jvalue value; value.j = 0L; if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { - // if the method hasn't been popped because of an exception then we populate - // the return_value parameter for the callback. At this point we only have - // the address of a "raw result" and we just call into the interpreter to - // convert this into a jvalue. - if (!exception_exit) { - oop oop_result; - BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); - if (is_reference_type(type)) { - result = Handle(thread, oop_result); - value.l = JNIHandles::make_local(thread, result()); - } + // At this point we only have the address of a "raw result" and + // we just call into the interpreter to convert this into a jvalue. + oop oop_result; + BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); + assert(type == T_VOID || current_frame.interpreter_frame_expression_stack_size() > 0, + "Stack shouldn't be empty"); + if (is_reference_type(type)) { + result = Handle(thread, oop_result); + value.l = JNIHandles::make_local(thread, result()); } } @@ -1862,12 +1857,10 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur // depth 0 as it is already late in the method exiting dance. state->set_top_frame_is_exiting(); - // Deferred transition to VM, so we can stash away the return oop before GC - // Note that this transition is not needed when throwing an exception, because - // there is no oop to retain. + // Deferred transition to VM, so we can stash away the return oop before GC. JavaThread* current = thread; // for JRT_BLOCK JRT_BLOCK - post_method_exit_inner(thread, mh, state, exception_exit, current_frame, value); + post_method_exit_inner(thread, mh, state, false /* not exception exit */, current_frame, value); JRT_BLOCK_END // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava desctructor. Now it is safe to allow diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java new file mode 100644 index 00000000000..ebeb157d633 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 verifies that MethodExit event is correctly posted + * if method is called while there is a pending exception on this thread. + * + * @bug 8365937 + * @run main/othervm/native -agentlib:TestMethodExitWithPendingException TestMethodExitWithPendingException + */ +public class TestMethodExitWithPendingException { + + private static native void enable(); + private static native void disableAndCheck(); + + static String exceptionExit() { + throw new RuntimeException("MyRuntimeException"); + } + + + // Called from ExceptionExit MethodExit callback via JNI. + // So MyRuntimeException is thrown already and hasn't been caught yet + // when this method is called. + static String upCall() { + return "MyNewString"; + } + + public static void main(String[] args) throws InterruptedException { + System.loadLibrary("TestMethodExitWithPendingException"); + try { + enable(); + exceptionExit(); + } catch (RuntimeException e){ + disableAndCheck(); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp new file mode 100644 index 00000000000..55a6cf059a6 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +jvmtiEnv* jvmti_env; + +bool method_exit_posted = false; +// This method exit callback actually works only for 2 methods: +// 1) for ExceptionExit it verifies that method exit +// has been popped by exception and calls 'upCall' method using JNI. +// 2) for upCall method it verifies that event has correct +// return value and was not popped by exception. +// The event callback just exits for all other methods. +static void JNICALL +cbMethodExit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID method, + jboolean was_popped_by_exception, jvalue return_value) { + const char * mname = get_method_name(jvmti, jni, method); + if (strcmp("upCall", mname) == 0) { + if (was_popped_by_exception) { + fatal(jni, "The method's was_popped_by_exception value is incorrect."); + } + jstring upcall_result = (jstring) return_value.l; + const char *str = jni->GetStringUTFChars(upcall_result, nullptr); + if (str == nullptr) { + fatal(jni, "Failed to convert Java string to C string."); + } + if (strcmp("MyNewString", str) != 0) { + fatal(jni, "The upCall result value is incorrect."); + } + method_exit_posted = true; + } + if (strcmp("exceptionExit", mname) != 0) { + return; + } + if (!was_popped_by_exception) { + fatal(jni, "Should have was_popped_by_esxception = true."); + } + jclass main_class = jni->FindClass("TestMethodExitWithPendingException"); + if (main_class == nullptr) { + fatal(jni, "Can't find TestMethodExitWithPendingException class."); + return; + } + jmethodID upcall_method = jni->GetStaticMethodID(main_class, + "upCall", "()Ljava/lang/String;"); + if (upcall_method == nullptr) { + fatal(jni, "Can't find upCall method."); + } + // Call 'upCall' method while current thread has exception + // that has been thrown but hasn't been caught yet. + jstring upcall_result = (jstring) jni->CallStaticObjectMethod(main_class, upcall_method); + const char *str = jni->GetStringUTFChars(upcall_result, nullptr); + if (str == nullptr) { + fatal(jni, "Failed to convert Java string to C string."); + return; + } + if (strcmp("MyNewString", str) != 0) { + fatal(jni, "The upCall result value is incorrect."); + } + jni->ReleaseStringUTFChars(upcall_result, str); +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + jvmtiEnv *jvmti = nullptr; + jint res = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_21); + if (res != JNI_OK) { + return JNI_ERR; + } + jvmtiError err = JVMTI_ERROR_NONE; + jvmtiCapabilities capabilities; + (void) memset(&capabilities, 0, sizeof (capabilities)); + capabilities.can_generate_method_exit_events = true; + err = jvmti->AddCapabilities(&capabilities); + check_jvmti_error(err, "AddCapabilities"); + jvmtiEventCallbacks callbacks; + (void) memset(&callbacks, 0, sizeof (callbacks)); + callbacks.MethodExit = &cbMethodExit; + err = jvmti->SetEventCallbacks(&callbacks, (int) sizeof (jvmtiEventCallbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + jvmti_env = jvmti; + return JNI_OK; +} + + +extern "C" { + +JNIEXPORT void JNICALL +Java_TestMethodExitWithPendingException_enable(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, thread); +} + + +JNIEXPORT void JNICALL +Java_TestMethodExitWithPendingException_disableAndCheck(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thread); + if (!method_exit_posted) { + fatal(jni, "Failed to post method exit event."); + } +} + +} // extern "C" diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java new file mode 100644 index 00000000000..2ea3e0fc27b --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 + * @run main/othervm/native -agentlib:TestPoppedByException TestPoppedByException + */ +public class TestPoppedByException { + + private static native void enable(); + private static native void disableAndCheck(); + + static String exceptionExit() { + throw new RuntimeException("MyRuntimeException"); + } + + static String exceptionExitOuter() { + return exceptionExit(); + } + + public static void main(String[] args) throws InterruptedException { + System.loadLibrary("TestPoppedByException"); + try { + enable(); + exceptionExitOuter(); + } catch (RuntimeException e){ + disableAndCheck(); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp new file mode 100644 index 00000000000..645057e24eb --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +jvmtiEnv* jvmti_env; +bool method_exit_posted = false; +static void JNICALL +cbMethodExit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID method, + jboolean was_popped_by_exception, jvalue return_value) { + const char * mname = get_method_name(jvmti, jni, method); + if (strcmp("exceptionExitOuter", mname) == 0) { + if (!was_popped_by_exception) { + fatal(jni, "The method's was_popped_by_exception value is incorrect."); + } + if (return_value.l != nullptr) { + fatal(jni, "return_value should be nullptr."); + } + method_exit_posted = true; + } +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + jvmtiEnv *jvmti = nullptr; + jint res = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_21); + if (res != JNI_OK) { + return JNI_ERR; + } + jvmtiError err = JVMTI_ERROR_NONE; + jvmtiCapabilities capabilities; + (void) memset(&capabilities, 0, sizeof (capabilities)); + capabilities.can_generate_method_exit_events = true; + err = jvmti->AddCapabilities(&capabilities); + check_jvmti_error(err, "AddCapabilities"); + jvmtiEventCallbacks callbacks; + (void) memset(&callbacks, 0, sizeof (callbacks)); + callbacks.MethodExit = &cbMethodExit; + err = jvmti->SetEventCallbacks(&callbacks, (int) sizeof (jvmtiEventCallbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + jvmti_env = jvmti; + return JNI_OK; +} + + +extern "C" { +JNIEXPORT void JNICALL +Java_TestPoppedByException_enable(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, thread); +} + + +JNIEXPORT void JNICALL +Java_TestPoppedByException_disableAndCheck(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thread); + if (!method_exit_posted) { + fatal(jni, "Failed to post method exit event."); + } + printf("The expected method_exit posted.\n"); +} + +} From 40a602520ba1a4682213b74e6f2a6f5a6e35d839 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Fri, 5 Sep 2025 00:26:44 +0000 Subject: [PATCH 142/295] 8364735: [asan] heap-use-after-free error detected in defaultStream::writer during VM shutdown Reviewed-by: jsjolen, stuefe --- src/hotspot/share/utilities/ostream.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 532e540af9a..5e339a700cb 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -992,9 +992,13 @@ void ostream_exit() { if (tmp != &tty_preinit_stream && tmp != defaultStream::instance) { delete tmp; } - delete defaultStream::instance; - xtty = nullptr; + // Keep xtty usable as long as possible by ensuring we null it out before + // deleting anything. + defaultStream* ds = defaultStream::instance; defaultStream::instance = nullptr; + xtty = nullptr; + OrderAccess::fence(); // force visibility to concurrently executing threads + delete ds; } // ostream_abort() is called by os::abort() when VM is about to die. From 0d7f8f83c7a674f5da4b93d66a24f9ce5ba46011 Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Fri, 5 Sep 2025 06:13:44 +0000 Subject: [PATCH 143/295] 8366747: RISC-V: Improve VerifyMethodHandles for method handle linkers Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 55 +++++++++++++++++-- src/hotspot/cpu/riscv/methodHandles_riscv.hpp | 4 +- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index 39b6737631d..d770999df96 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -93,14 +93,60 @@ void MethodHandles::verify_klass(MacroAssembler* _masm, void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {} +void MethodHandles::verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) { + BLOCK_COMMENT("verify_method {"); + __ verify_method_ptr(method); + if (VerifyMethodHandles) { + Label L_ok; + assert_different_registers(method, t0, t1); + const Register method_holder = t1; + __ load_method_holder(method_holder, method); + + switch (iid) { + case vmIntrinsicID::_invokeBasic: + // Require compiled LambdaForm class to be fully initialized. + __ lbu(t0, Address(method_holder, InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ mv(t1, InstanceKlass::fully_initialized); + __ beq(t0, t1, L_ok); + break; + case vmIntrinsicID::_linkToStatic: + __ clinit_barrier(method_holder, t0, &L_ok); + break; + + case vmIntrinsicID::_linkToVirtual: + case vmIntrinsicID::_linkToSpecial: + case vmIntrinsicID::_linkToInterface: + // Class initialization check is too strong here. Just ensure that class initialization has been initiated. + __ lbu(t0, Address(method_holder, InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ mv(t1, InstanceKlass::being_initialized); + __ bge(t0, t1, L_ok); + + // init_state check failed, but it may be an abstract interface method + __ lhu(t0, Address(method, Method::access_flags_offset())); + __ test_bit(t1, t0, exact_log2(JVM_ACC_ABSTRACT)); + __ bnez(t1, L_ok); + break; + + default: + fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); + } + + // Method holder init state check failed for a concrete method. + __ stop("Method holder klass is not initialized"); + __ BIND(L_ok); + } + BLOCK_COMMENT("} verify_method"); +} #endif //ASSERT void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry) { + bool for_compiler_entry, vmIntrinsics::ID iid) { assert(method == xmethod, "interpreter calling convention"); Label L_no_such_method; __ beqz(xmethod, L_no_such_method); - __ verify_method_ptr(method); + verify_method(_masm, method, iid); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; @@ -158,7 +204,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, __ BIND(L); } - jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); + jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic); BLOCK_COMMENT("} jump_to_lambda_form"); } @@ -437,8 +483,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, // After figuring out which concrete method to call, jump into it. // Note that this works in the interpreter with no data motion. // But the compiled version will require that r2_recv be shifted out. - __ verify_method_ptr(xmethod); - jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry); + jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry, iid); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.hpp b/src/hotspot/cpu/riscv/methodHandles_riscv.hpp index 6017b26c66d..ffc3b3ab676 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.hpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.hpp @@ -39,6 +39,8 @@ public: Register obj, vmClassID klass_id, const char* error_message = "wrong klass") NOT_DEBUG_RETURN; + static void verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) NOT_DEBUG_RETURN; + static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) { verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle), "reference is a MH"); @@ -49,7 +51,7 @@ public: // Similar to InterpreterMacroAssembler::jump_from_interpreted. // Takes care of special dispatch from single stepping too. static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry); + bool for_compiler_entry, vmIntrinsics::ID iid); static void jump_to_lambda_form(MacroAssembler* _masm, Register recv, Register method_temp, From a2f8d3c4c25fdadf378313ef52185dceee98773d Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 5 Sep 2025 06:40:33 +0000 Subject: [PATCH 144/295] 8366765: [REDO] Rename JavaLangAccess::*NoRepl methods Reviewed-by: rriggs, liach, alanb --- .../share/classes/java/lang/String.java | 338 ++++++++++++------ .../share/classes/java/lang/System.java | 16 +- .../share/classes/java/nio/file/Files.java | 4 +- .../share/classes/java/util/zip/ZipCoder.java | 12 +- .../jdk/internal/access/JavaLangAccess.java | 25 +- .../jdk/internal/foreign/StringSupport.java | 6 +- .../unix/classes/sun/nio/fs/UnixPath.java | 2 +- .../{NoReplTest.java => OrThrowTest.java} | 20 +- 8 files changed, 273 insertions(+), 150 deletions(-) rename test/jdk/java/lang/String/{NoReplTest.java => OrThrowTest.java} (79%) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 15b8e98369e..24ead22e283 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -604,14 +604,14 @@ public final class String } byte[] utf16 = StringUTF16.newBytesFor(length); StringLatin1.inflate(latin1, 0, utf16, 0, dp); - dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp, true); + dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp); if (dp != length) { utf16 = Arrays.copyOf(utf16, dp << 1); } return new String(utf16, UTF16); } else { // !COMPACT_STRINGS byte[] dst = StringUTF16.newBytesFor(length); - int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } @@ -688,13 +688,25 @@ public final class String } } - /* - * Throws iae, instead of replacing, if malformed or unmappable. - * The byte array can be exclusively used to construct - * the string and is not modified or used for any other purpose. + /** + * {@return a new string by decoding from the given UTF-8 bytes array} + *

          + * WARNING: The caller of this method is assumed to have relinquished + * and transferred the ownership of the byte array. It can thus be + * exclusively used to construct the {@code String}. + * + * @param bytes byte array containing UTF-8 encoded characters + * @param offset the index of the first byte to decode + * @param length the number of bytes to decode + * @throws NullPointerException If {@code bytes} is null + * @throws StringIndexOutOfBoundsException If {@code offset} is negative, + * {@code length} is negative, or {@code offset} is greater than + * {@code bytes.length - length} + * @throws CharacterCodingException for malformed input or unmappable characters */ - private static String newStringUTF8NoRepl(byte[] bytes, int offset, int length) { - checkBoundsOffCount(offset, length, bytes.length); + private static String newStringUTF8OrThrow(byte[] bytes, int offset, int length) + throws CharacterCodingException { + checkBoundsOffCount(offset, length, bytes.length); // Implicit null check on `bytes` if (length == 0) { return ""; } @@ -745,10 +757,10 @@ public final class String StringLatin1.inflate(dst, 0, buf, 0, dp); dst = buf; } - dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, sl, dst, dp); } else { // !COMPACT_STRINGS dst = StringUTF16.newBytesFor(length); - dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, offset + length, dst, 0); } if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); @@ -783,27 +795,16 @@ public final class String * @param cs charset the byte array encoded in * * @throws CharacterCodingException for malformed input or unmappable characters + * @throws NullPointerException If {@code src} or {@code cs} is null */ - static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { - try { - return newStringNoRepl1(src, cs); - } catch (IllegalArgumentException e) { - //newStringNoRepl1 throws IAE with MalformedInputException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof MalformedInputException mie) { - throw mie; - } - throw (CharacterCodingException)cause; - } - } - - private static String newStringNoRepl1(byte[] src, Charset cs) { - int len = src.length; + static String newStringOrThrow(byte[] src, Charset cs) throws CharacterCodingException { + Objects.requireNonNull(cs); + int len = src.length; // Implicit null check on `src` if (len == 0) { return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8NoRepl(src, 0, src.length); + return newStringUTF8OrThrow(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -816,7 +817,7 @@ public final class String return new String(src, LATIN1); return new String(StringLatin1.inflate(src, 0, src.length), UTF16); } else { - throwMalformed(src); + throw malformedASCII(src); } } @@ -831,13 +832,7 @@ public final class String } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; - int caLen; - try { - caLen = decodeWithDecoder(cd, ca, src, 0, src.length); - } catch (CharacterCodingException x) { - // throw via IAE - throw new IllegalArgumentException(x); - } + int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); byte coder = StringUTF16.coderFromArrayLen(val, caLen); @@ -874,7 +869,7 @@ public final class String private static byte[] encode(Charset cs, byte coder, byte[] val) { if (cs == UTF_8.INSTANCE) { - return encodeUTF8(coder, val, true); + return encodeUTF8(coder, val); } if (cs == ISO_8859_1.INSTANCE) { return encode8859_1(coder, val); @@ -882,13 +877,30 @@ public final class String if (cs == US_ASCII.INSTANCE) { return encodeASCII(coder, val); } - return encodeWithEncoder(cs, coder, val, true); + return encodeWithEncoder(cs, coder, val, null); } - private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with the encoder of {@code + * cs}} + * + * @param cs a charset to obtain the encoder from + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeWithEncoder( + Charset cs, byte coder, byte[] val, Class exClass) + throws E { CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); + boolean doReplace = exClass == null; // fastpath with ArrayEncoder implies `doReplace`. if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible @@ -930,7 +942,9 @@ public final class String cr.throwException(); } catch (CharacterCodingException x) { if (!doReplace) { - throw new IllegalArgumentException(x); + @SuppressWarnings("unchecked") + E cce = (E) x; + throw cce; } else { throw new Error(x); } @@ -938,60 +952,69 @@ public final class String return trimArray(ba, bb.position()); } - /* - * Throws iae, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} + * + * @param s the string to encode + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesUTF8NoRepl(String s) { - return encodeUTF8(s.coder(), s.value(), false); + static byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return encodeUTF8OrThrow(s.coder(), s.value()); // Implicit null check on `s` } private static boolean isASCII(byte[] src) { return !StringCoding.hasNegatives(src, 0, src.length); } - /* - * Throws CCE, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} + *

          + * WARNING: This method returns the {@code byte[]} backing the provided + * {@code String}, if the input is ASCII. Hence, the returned byte array + * must not be modified. + * + * @param s the string to encode + * @param cs the charset + * @throws NullPointerException If {@code s} or {@code cs} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - try { - return getBytesNoRepl1(s, cs); - } catch (IllegalArgumentException e) { - //getBytesNoRepl1 throws IAE with UnmappableCharacterException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof UnmappableCharacterException) { - throw (UnmappableCharacterException)cause; - } - throw (CharacterCodingException)cause; - } - } - - private static byte[] getBytesNoRepl1(String s, Charset cs) { - byte[] val = s.value(); + static byte[] getBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + Objects.requireNonNull(cs); + byte[] val = s.value(); // Implicit null check on `s` byte coder = s.coder(); if (cs == UTF_8.INSTANCE) { if (coder == LATIN1 && isASCII(val)) { return val; } - return encodeUTF8(coder, val, false); + return encodeUTF8OrThrow(coder, val); } if (cs == ISO_8859_1.INSTANCE) { if (coder == LATIN1) { return val; } - return encode8859_1(coder, val, false); + return encode8859_1OrThrow(coder, val); } if (cs == US_ASCII.INSTANCE) { if (coder == LATIN1) { if (isASCII(val)) { return val; } else { - throwUnmappable(val); + throw unmappableASCII(val); } } } - return encodeWithEncoder(cs, coder, val, false); + return encodeWithEncoder(cs, coder, val, CharacterCodingException.class); } + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with US-ASCII} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + */ private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { int positives = StringCoding.countPositives(val, 0, val.length); @@ -1031,10 +1054,26 @@ public final class String } private static byte[] encode8859_1(byte coder, byte[] val) { - return encode8859_1(coder, val, true); + return encode8859_1(coder, val, null); } - private static byte[] encode8859_1(byte coder, byte[] val, boolean doReplace) { + private static byte[] encode8859_1OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encode8859_1(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with ISO-8859-1} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encode8859_1(byte coder, byte[] val, Class exClass) throws E { if (coder == LATIN1) { return val.clone(); } @@ -1048,8 +1087,8 @@ public final class String sp = sp + ret; dp = dp + ret; if (ret != len) { - if (!doReplace) { - throwUnmappable(sp); + if (exClass != null) { + throw String.unmappableCharacterException(sp); } char c = StringUTF16.getChar(val, sp++); if (Character.isHighSurrogate(c) && sp < sl && @@ -1143,7 +1182,26 @@ public final class String ((byte) 0x80 << 0)))); } - private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp, boolean doReplace) { + private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp) { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, null); + } + + private static int decodeUTF8_UTF16OrThrow( + byte[] src, int sp, int sl, byte[] dst, int dp) + throws MalformedInputException { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, MalformedInputException.class); + } + + /** + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static int decodeUTF8_UTF16( + byte[] src, int sp, int sl, byte[] dst, int dp, Class exClass) + throws E { while (sp < sl) { int b1 = src[sp++]; if (b1 >= 0) { @@ -1152,8 +1210,8 @@ public final class String if (sp < sl) { int b2 = src[sp++]; if (isNotContinuation(b2)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); sp--; @@ -1162,8 +1220,8 @@ public final class String } continue; } - if (!doReplace) { - throwMalformed(sp, 1); // underflow() + if (exClass != null) { + throw String.malformedInputException(sp, 1); // underflow() } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1172,8 +1230,8 @@ public final class String int b2 = src[sp++]; int b3 = src[sp++]; if (isMalformed3(b1, b2, b3)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); sp -= 3; @@ -1181,8 +1239,8 @@ public final class String } else { char c = decode3(b1, b2, b3); if (Character.isSurrogate(c)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); } else { @@ -1192,14 +1250,14 @@ public final class String continue; } if (sp < sl && isMalformed3_2(b1, src[sp])) { - if (!doReplace) { - throwMalformed(sp - 1, 2); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 2); } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp, 1); + if (exClass != null) { + throw String.malformedInputException(sp, 1); } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1211,8 +1269,8 @@ public final class String int uc = decode4(b1, b2, b3, b4); if (isMalformed4(b2, b3, b4) || !Character.isSupplementaryCodePoint(uc)) { // shortest form check - if (!doReplace) { - throwMalformed(sp - 4, 4); + if (exClass != null) { + throw String.malformedInputException(sp - 4, 4); } StringUTF16.putChar(dst, dp++, REPL); sp -= 4; @@ -1225,14 +1283,14 @@ public final class String } b1 &= 0xff; if (b1 > 0xf4 || sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); // or 2 + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); // or 2 } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } sp++; StringUTF16.putChar(dst, dp++, REPL); @@ -1241,8 +1299,8 @@ public final class String } break; } else { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); } @@ -1284,29 +1342,76 @@ public final class String return 3; } - private static void throwMalformed(int off, int nb) { - String msg = "malformed input off : " + off + ", length : " + nb; - throw new IllegalArgumentException(msg, new MalformedInputException(nb)); + /** + * {@return a new {@link MalformedInputException} for the sub-range denoted + * by specified {@code offset} and {@code length}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E malformedInputException(int offset, int length) { + MalformedInputException mie = new MalformedInputException(length); + String msg = "malformed input offset : " + offset + ", length : " + length; + mie.initCause(new IllegalArgumentException(msg)); + return (E) mie; } - private static void throwMalformed(byte[] val) { + /** + * {@return a new {@link MalformedInputException} for the given malformed + * ASCII string} + */ + private static MalformedInputException malformedASCII(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - throwMalformed(dp, 1); + return malformedInputException(dp, 1); } - private static void throwUnmappable(int off) { - String msg = "malformed input off : " + off + ", length : 1"; - throw new IllegalArgumentException(msg, new UnmappableCharacterException(1)); + /** + * {@return a new {@link UnmappableCharacterException} at given {@code offset}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E unmappableCharacterException(int offset) { + UnmappableCharacterException uce = new UnmappableCharacterException(1); + String msg = "malformed input offset : " + offset + ", length : 1"; + uce.initCause(new IllegalArgumentException(msg, uce)); + return (E) uce; } - private static void throwUnmappable(byte[] val) { + /** + * {@return a new {@link UnmappableCharacterException} for the given + * malformed ASCII string} + */ + private static UnmappableCharacterException unmappableASCII(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - throwUnmappable(dp); + return unmappableCharacterException(dp); } - private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { + private static byte[] encodeUTF8(byte coder, byte[] val) { + return encodeUTF8(coder, val, null); + } + + private static byte[] encodeUTF8OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encodeUTF8(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with UTF-8} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8(byte coder, byte[] val, Class exClass) throws E { if (coder == UTF16) { - return encodeUTF8_UTF16(val, doReplace); + return encodeUTF8_UTF16(val, exClass); } int positives = StringCoding.countPositives(val, 0, val.length); @@ -1334,13 +1439,24 @@ public final class String return Arrays.copyOf(dst, dp); } - private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * UTF-16, and then encoding the result with UTF-8} + * + * @param val a string byte array encoded with UTF-16 + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8_UTF16(byte[] val, Class exClass) throws E { int dp = 0; int sp = 0; int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; if (allocLen > (long)Integer.MAX_VALUE) { throw new OutOfMemoryError("Required length exceeds implementation limit"); } @@ -1369,10 +1485,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dst[dp++] = '?'; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dst[dp++] = (byte)(0xf0 | ((uc >> 18))); @@ -1396,10 +1512,14 @@ public final class String /** * {@return the exact size required to UTF_8 encode this UTF16 string} - * @param val UTF16 encoded byte array - * @param doReplace true to replace unmappable characters + * + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting discarded. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception */ - private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { + private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { long dp = 0L; int sp = 0; int sl = val.length >> 1; @@ -1418,10 +1538,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dp++; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dp += 4; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index a40c27bbf47..bb1775fbc6b 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2124,6 +2124,7 @@ public final class System { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } + public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } @@ -2132,21 +2133,24 @@ public final class System { return String.newStringWithLatin1Bytes(bytes); } - public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { - return String.newStringNoRepl(bytes, cs); + public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException { + return String.newStringOrThrow(bytes, cs); } + public char uncheckedGetUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } + public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) { StringUTF16.putChar(bytes, index, ch); } - public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - return String.getBytesNoRepl(s, cs); + + public byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + return String.getBytesOrThrow(s, cs); } - public byte[] getBytesUTF8NoRepl(String s) { - return String.getBytesUTF8NoRepl(s); + public byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return String.getBytesUTF8OrThrow(s); } public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index f8278fa2642..80c771f5306 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public final class Files { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.uncheckedNewStringNoRepl(ba, cs); + return JLA.uncheckedNewStringOrThrow(ba, cs); } /** @@ -3362,7 +3362,7 @@ public final class Files { Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesOrThrow(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 8b812eba202..b9906d348e3 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -256,7 +256,7 @@ class ZipCoder { try { // Copy subrange for exclusive use by the string being created byte[] bytes = Arrays.copyOfRange(ba, off, off + length); - return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8); + return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8); } catch (CharacterCodingException cce) { throw new IllegalArgumentException(cce); } @@ -264,7 +264,11 @@ class ZipCoder { @Override byte[] getBytes(String s) { - return JLA.getBytesUTF8NoRepl(s); + try { + return JLA.getBytesUTF8OrThrow(s); + } catch (CharacterCodingException cce) { + throw new IllegalArgumentException(cce); + } } @Override @@ -278,8 +282,6 @@ class ZipCoder { // Non-ASCII, fall back to decoding a String // We avoid using decoder() here since the UTF8ZipCoder is // shared and that decoder is not thread safe. - // We use the JLA.newStringUTF8NoRepl variant to throw - // exceptions eagerly when opening ZipFiles return hash(toString(a, off, len)); } int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0); @@ -296,7 +298,7 @@ class ZipCoder { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index aa5b6e438f5..e529e8ba350 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,7 +45,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; -import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -332,7 +331,7 @@ public interface JavaLangAccess { /** * Constructs a new {@code String} by decoding the specified byte array - * using the specified {@linkplain java.nio.charset.Charset charset}. + * using the specified {@code Charset}. *

          * WARNING: The caller of this method shall relinquish and transfer the * ownership of the byte array to the callee, since the latter will not @@ -342,26 +341,24 @@ public interface JavaLangAccess { * @param cs the Charset * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes + * @throws NullPointerException If {@code bytes} or {@code cs} is null */ - String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * Encode the given string into a sequence of bytes using the specified - * {@linkplain java.nio.charset.Charset charset}. + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} *

          * WARNING: This method returns the {@code byte[]} backing the provided * {@code String}, if the input is ASCII. Hence, the returned byte array * must not be modified. - *

          - * This method throws {@code CharacterCodingException} instead of replacing - * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset - * @return the encoded bytes + * @throws NullPointerException If {@code s} or {@code cs} is null * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException; /** * Get the {@code char} at {@code index} in a {@code byte[]} in internal @@ -387,13 +384,13 @@ public interface JavaLangAccess { void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** - * Encode the given string into a sequence of bytes using utf8. + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} * * @param s the string to encode - * @return the encoded bytes in utf8 - * @throws IllegalArgumentException for malformed surrogates + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - byte[] getBytesUTF8NoRepl(String s); + byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException; /** * Inflated copy from {@code byte[]} to {@code char[]}, as defined by diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index 2f842810aa7..bb6cb2d3915 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -73,7 +73,7 @@ public final class StringSupport { final byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); try { - return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + return JAVA_LANG_ACCESS.uncheckedNewStringOrThrow(bytes, charset); } catch (CharacterCodingException _) { // use replacement characters for malformed input return new String(bytes, charset); @@ -92,7 +92,7 @@ public final class StringSupport { byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); try { - return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + return JAVA_LANG_ACCESS.uncheckedNewStringOrThrow(bytes, charset); } catch (CharacterCodingException _) { // use replacement characters for malformed input return new String(bytes, charset); @@ -111,7 +111,7 @@ public final class StringSupport { byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); try { - return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + return JAVA_LANG_ACCESS.uncheckedNewStringOrThrow(bytes, charset); } catch (CharacterCodingException _) { // use replacement characters for malformed input return new String(bytes, charset); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 5dfc73f57aa..5a77bb0b935 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -126,7 +126,7 @@ class UnixPath implements Path { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesOrThrow(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/test/jdk/java/lang/String/NoReplTest.java b/test/jdk/java/lang/String/OrThrowTest.java similarity index 79% rename from test/jdk/java/lang/String/NoReplTest.java rename to test/jdk/java/lang/String/OrThrowTest.java index 1817a1ffe73..340a190b4eb 100644 --- a/test/jdk/java/lang/String/NoReplTest.java +++ b/test/jdk/java/lang/String/OrThrowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +24,8 @@ /* * @test * @bug 8286287 8288589 - * @summary Tests for *NoRepl() shared secret methods. - * @run testng NoReplTest + * @summary Tests for *OrThrow() shared secret methods. + * @run testng OrThrowTest * @modules jdk.charsets */ @@ -39,17 +39,17 @@ import static java.nio.charset.StandardCharsets.UTF_16; import org.testng.annotations.Test; @Test -public class NoReplTest { +public class OrThrowTest { private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); /** - * Verifies newStringNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.readString()` method. + * Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.readString()} method. */ @Test - public void newStringNoReplTest() throws IOException { + public void uncheckedNewStringOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try (var fos = Files.newOutputStream(f)) { fos.write(MALFORMED_UTF16); @@ -67,11 +67,11 @@ public class NoReplTest { } /** - * Verifies getBytesNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.writeString()` method. + * Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.writeString()} method. */ @Test - public void getBytesNoReplTest() throws IOException { + public void uncheckedGetBytesOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try { Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); From e6fa8aae6168ea5a8579cd0a38209ca71c32e704 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 5 Sep 2025 08:46:56 +0000 Subject: [PATCH 145/295] 8366845: C2 SuperWord: wrong VectorCast after VectorReinterpret with swapped src/dst type Reviewed-by: thartmann, galder, vlivanov --- src/hotspot/share/opto/vtransform.cpp | 2 +- .../superword/TestReinterpretAndCast.java | 225 ++++++++++++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index af4cb345e14..2f77c1c2e37 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -813,7 +813,7 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyStat } else if (VectorNode::is_reinterpret_opcode(opc)) { assert(first->req() == 2 && req() == 2, "only one input expected"); const TypeVect* vt = TypeVect::make(bt, vlen); - vn = new VectorReinterpretNode(in1, vt, in1->bottom_type()->is_vect()); + vn = new VectorReinterpretNode(in1, in1->bottom_type()->is_vect(), vt); } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { opc = Op_RShiftI; vn = VectorNode::make(opc, in1, in2, vlen, bt); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java new file mode 100644 index 00000000000..a72126ebad5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8366845 + * @summary Test Reinterpret with Cast cases, where the order of the src/dst types of Reinterpret matters. + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestReinterpretAndCast + */ + +package compiler.loopopts.superword; + +import jdk.incubator.vector.Float16; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.*; + +public class TestReinterpretAndCast { + static int SIZE = 1028 * 8; + + public static final Generator GEN_FLOAT = Generators.G.floats(); + public static final Generator GEN_DOUBLE = Generators.G.doubles(); + private static final Generator GEN_FLOAT16 = Generators.G.float16s(); + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + static long[] fillWithDoubles(long[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = Double.doubleToLongBits(GEN_DOUBLE.next()); + } + return a; + } + + static int[] fillWithFloats(int[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = Float.floatToIntBits(GEN_FLOAT.next()); + } + return a; + } + + static short[] fillWithFloat16s(short[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = GEN_FLOAT16.next(); + } + return a; + } + + static void verify(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + // Make sure we remove non-canonical NaN's. + long aa = Double.doubleToLongBits(Double.longBitsToDouble(a[i])); + long bb = Double.doubleToLongBits(Double.longBitsToDouble(b[i])); + if (aa != bb) { + throw new RuntimeException("Wrong value: " + aa + " vs " + bb + " - " + a[i] + " vs " + b[i]); + } + } + } + + static void verify(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + // Make sure we remove non-canonical NaN's. + int aa = Float.floatToIntBits(Float.intBitsToFloat(a[i])); + int bb = Float.floatToIntBits(Float.intBitsToFloat(b[i])); + if (aa != bb) { + throw new RuntimeException("Wrong value: " + aa + " vs " + bb + " - " + a[i] + " vs " + b[i]); + } + } + } + + static void verify(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + // Make sure we remove non-canonical NaN's. + int aa = Float.floatToIntBits(Float16.shortBitsToFloat16(a[i]).floatValue()); + int bb = Float.floatToIntBits(Float16.shortBitsToFloat16(b[i]).floatValue()); + if (aa != bb) { + throw new RuntimeException("Wrong value: " + aa + " vs " + bb + " - " + a[i] + " vs " + b[i]); + } + } + } + + // -------------- test1 + public static long[] test1_in = fillWithDoubles(new long[SIZE]); + public static int[] test1_gold = new int[SIZE]; + public static int[] test1_test = new int[SIZE]; + + // Esecute in interpreter, to compare to compiled results later. + static { test1(test1_in, test1_gold); } + + @Setup + public static Object[] setup1() { + return new Object[] {test1_in, test1_test}; + } + + @Test + @Arguments(setup = "setup1") + @IR(counts = {IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_double, max_long)", "> 0", + IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_double, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have both L2D and F2I + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public static void test1(long[] a, int[] b) { + for (int i = 0; i < SIZE; i++) { + long v0 = a[i]; + double v1 = Double.longBitsToDouble(v0); + // Reinterpret: long -> double + // Before fix: double -> long (no direct problem) + float v2 = (float)v1; + // Cast: double -> float + // Before fix: long -> float (wrong!) + int v3 = Float.floatToRawIntBits(v2); + b[i] = v3; + } + } + + @Check(test = "test1") + public static void check1() { + verify(test1_test, test1_gold); + } + + // -------------- test2 + public static int[] test2_in = fillWithFloats(new int[SIZE]); + public static short[] test2_gold = new short[SIZE]; + public static short[] test2_test = new short[SIZE]; + + // Esecute in interpreter, to compare to compiled results later. + static { test2(test2_in, test2_gold); } + + @Setup + public static Object[] setup2() { + return new Object[] {test2_in, test2_test}; + } + + @Test + @Arguments(setup = "setup2") + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public static void test2(int[] a, short[] b) { + for (int i = 0; i < SIZE; i++) { + int v0 = a[i]; + float v1 = Float.intBitsToFloat(v0); + // Reinterpret: int -> float + // Before fix: float -> int (no direct problem) + short v2 = Float.floatToFloat16(v1); + // Cast: float -> float16/short + // Before fix: int -> float16/short (wrong!) + b[i] = v2; + } + } + + @Check(test = "test2") + public static void check2() { + verify(test2_test, test2_gold); + } + + // -------------- test3 + public static short[] test3_in = fillWithFloat16s(new short[SIZE]); + public static long[] test3_gold = new long[SIZE]; + public static long[] test3_test = new long[SIZE]; + + // Esecute in interpreter, to compare to compiled results later. + static { test3(test3_in, test3_gold); } + + @Setup + public static Object[] setup3() { + return new Object[] {test3_in, test3_test}; + } + + @Test + @Arguments(setup = "setup3") + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public static void test3(short[] a, long[] b) { + for (int i = 0; i < SIZE; i++) { + short v0 = a[i]; + Float16 v1 = Float16.shortBitsToFloat16(v0); + float v2 = v1.floatValue(); + int v3 = Float.floatToRawIntBits(v2); + // Reinterpret: float -> int + // Before fix: int -> float + long v4 = v3; + // Cast: int -> long + // Before fix: float -> long (wrong!) + b[i] = v4; + } + } + + @Check(test = "test3") + public static void check3() { + verify(test3_test, test3_gold); + } +} From 0dad3f1ae8d0c35c4b7a8188ad7854d01c7cd6b4 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 5 Sep 2025 10:55:41 +0000 Subject: [PATCH 146/295] 8366893: java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java timed out on macos-aarch64 Reviewed-by: alanb, jpai --- .../Thread/virtual/stress/GetStackTraceALotWhenBlocking.java | 4 ++-- .../Thread/virtual/stress/GetStackTraceALotWhenPinned.java | 4 ++-- test/jdk/java/lang/Thread/virtual/stress/ParkALot.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java index fa4d16d9f82..733ee261b09 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java @@ -53,8 +53,8 @@ public class GetStackTraceALotWhenBlocking { int iterations; int value = Integer.parseInt(args[0]); - if (Platform.isOSX() && Platform.isX64()) { - // reduced iterations on macosx-x64 + if (Platform.isOSX()) { + // reduced iterations on macosx iterations = Math.max(value / 4, 1); } else { iterations = value; diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java index f68b595eed4..ef385e47e21 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -56,8 +56,8 @@ public class GetStackTraceALotWhenPinned { int iterations; int value = Integer.parseInt(args[0]); - if (Platform.isOSX() && Platform.isX64()) { - // reduced iterations on macosx-x64 + if (Platform.isOSX()) { + // reduced iterations on macosx iterations = Math.max(value / 4, 1); } else { iterations = value; diff --git a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java index 29704fd8975..ceed243f009 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java @@ -49,8 +49,8 @@ public class ParkALot { public static void main(String[] args) throws Exception { int iterations; int value = Integer.parseInt(args[0]); - if (Platform.isOSX() && Platform.isX64()) { - // reduced iterations on macosx-x64 + if (Platform.isOSX()) { + // reduced iterations on macosx iterations = Math.max(value / 4, 1); } else { iterations = value; From 124fcf1d9abb6cafe34637ba357617c7c7be56c8 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 5 Sep 2025 13:31:23 +0000 Subject: [PATCH 147/295] 8233115: Protect ExecuteWithLog from running with redirection without a subshell Reviewed-by: erikj --- make/RunTests.gmk | 28 ++++++++++++++-------------- make/StaticLibs.gmk | 2 +- make/common/MakeBase.gmk | 26 +++++++++++++++++--------- make/common/ProcessMarkdown.gmk | 2 +- make/hotspot/gensrc/GensrcDtrace.gmk | 5 +++-- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 10f0a2f87ed..b44243dae76 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -509,7 +509,7 @@ define SetupRunGtestTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ $$(CD) $$($1_TEST_SUPPORT_DIR) && \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ -jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \ @@ -520,7 +520,7 @@ define SetupRunGtestTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt @@ -644,7 +644,7 @@ define SetupRunMicroTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \ $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ @@ -655,7 +655,7 @@ define SetupRunMicroTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt @@ -758,34 +758,34 @@ define SetupAOTBody ifeq ($$($1_TRAINING), onestep) $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) else $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - )) + ) endif @@ -1085,9 +1085,9 @@ define SetupRunJtregTestBody $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1204,12 +1204,12 @@ define SetupRunSpecialTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \ $$($1_TEST_COMMAND_LINE) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) # We can not parse the various "special" tests. parse-test-$1: run-test-$1 diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk index 3cf2a4dd136..80d6b4538c8 100644 --- a/make/StaticLibs.gmk +++ b/make/StaticLibs.gmk @@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true) INFO := Generating export list for $(notdir $(lib)), \ DEPS := $(lib), \ OUTPUT_FILE := $(lib).exp, \ - COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \ + COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \ )) \ $(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \ ) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index d1bb0396943..97ef88932cb 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -284,6 +284,12 @@ else LogCmdlines = endif +# Check if the command line contains redirection, that is <, > or >>, +# and if so, return a value that is interpreted as true in a make $(if) +# construct. +is_redirect = \ + $(if $(filter < > >>, $1), true) + ################################################################################ # ExecuteWithLog will run a command and log the output appropriately. This is # meant to be used by commands that do "real" work, like a compilation. @@ -291,21 +297,23 @@ endif # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # -# NOTE: If the command redirects stdout, the caller needs to wrap it in a -# subshell (by adding parentheses around it), otherwise the redirect to the -# subshell tee process will create a race condition where the target file may -# not be fully written when the make recipe is done. -# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ - $(call LogCmdlines, Executing: [$(strip $2)]) \ + $(call LogCmdlines, Executing: \ + [$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN))]) \ $(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ + ( $(RM) $(strip $1).log && \ + $(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN)) \ + > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ - $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ - $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ + $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ + $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ exit $(DOLLAR)exitcode ) ) ################################################################################ diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index 1b4a5b76ea1..c60b49ae85f 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -109,7 +109,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) + $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index e71c3cb961d..7a80bf47285 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -47,8 +47,9 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - ($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) - $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $@, \ + $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: # hotspot_jni.d hotspot.d hs_private.d From 33794d161467635eb32591fee189e5409cd2d114 Mon Sep 17 00:00:00 2001 From: Guoxiong Li Date: Fri, 5 Sep 2025 13:34:45 +0000 Subject: [PATCH 148/295] 8357188: Remove the field MemAllocator::Allocation::_overhead_limit_exceeded and the related code Reviewed-by: ayang, shade --- src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 3 +-- src/hotspot/share/gc/epsilon/epsilonHeap.hpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +-- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 3 +-- .../share/gc/parallel/parallelScavengeHeap.cpp | 13 ++++--------- .../share/gc/parallel/parallelScavengeHeap.hpp | 12 +++--------- src/hotspot/share/gc/serial/serialHeap.cpp | 3 +-- src/hotspot/share/gc/serial/serialHeap.hpp | 2 +- src/hotspot/share/gc/shared/collectedHeap.hpp | 3 +-- src/hotspot/share/gc/shared/memAllocator.cpp | 11 +++-------- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 3 +-- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 2 +- src/hotspot/share/gc/z/zCollectedHeap.cpp | 2 +- src/hotspot/share/gc/z/zCollectedHeap.hpp | 2 +- 14 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 693e915b98e..c324aa9baff 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -260,8 +260,7 @@ HeapWord* EpsilonHeap::allocate_new_tlab(size_t min_size, return res; } -HeapWord* EpsilonHeap::mem_allocate(size_t size, bool *gc_overhead_limit_was_exceeded) { - *gc_overhead_limit_was_exceeded = false; +HeapWord* EpsilonHeap::mem_allocate(size_t size) { return allocate_work(size); } diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index 24b43fe3541..f8aa9d7dbf1 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -85,7 +85,7 @@ public: // Allocation HeapWord* allocate_work(size_t size, bool verbose = true); - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t size) override; HeapWord* allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) override; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 618e9b055fe..de3fc0f5da5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -396,8 +396,7 @@ HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size, } HeapWord* -G1CollectedHeap::mem_allocate(size_t word_size, - bool* gc_overhead_limit_was_exceeded) { +G1CollectedHeap::mem_allocate(size_t word_size) { assert_heap_not_locked_and_not_at_safepoint(); if (is_humongous(word_size)) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 49bbcf888be..0bb16edaf78 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -442,8 +442,7 @@ private: size_t requested_size, size_t* actual_size) override; - HeapWord* mem_allocate(size_t word_size, - bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t word_size) override; // First-level mutator allocation attempt: try to allocate out of // the mutator alloc region without taking the Heap_lock. This diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 3b530895eb1..9b40475288d 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -266,19 +266,16 @@ bool ParallelScavengeHeap::requires_barriers(stackChunkOop p) const { // and the rest will not be executed. For that reason, this method loops // during failed allocation attempts. If the java heap becomes exhausted, // we rely on the size_policy object to force a bail out. -HeapWord* ParallelScavengeHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* ParallelScavengeHeap::mem_allocate(size_t size) { assert(!SafepointSynchronize::is_at_safepoint(), "should not be at safepoint"); assert(Thread::current() != (Thread*)VMThread::vm_thread(), "should not be in vm thread"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); bool is_tlab = false; - return mem_allocate_work(size, is_tlab, gc_overhead_limit_was_exceeded); + return mem_allocate_work(size, is_tlab); } -HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, - bool is_tlab, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { for (uint loop_count = 0; /* empty */; ++loop_count) { // Try young-gen first. HeapWord* result = young_gen()->allocate(size); @@ -442,10 +439,8 @@ size_t ParallelScavengeHeap::unsafe_max_tlab_alloc(Thread* thr) const { } HeapWord* ParallelScavengeHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) { - bool dummy; HeapWord* result = mem_allocate_work(requested_size /* size */, - true /* is_tlab */, - &dummy); + true /* is_tlab */); if (result != nullptr) { *actual_size = requested_size; } diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index b0e804edb70..bd701ae8be3 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -102,9 +102,7 @@ class ParallelScavengeHeap : public CollectedHeap { inline bool should_alloc_in_eden(size_t size) const; - HeapWord* mem_allocate_work(size_t size, - bool is_tlab, - bool* gc_overhead_limit_was_exceeded); + HeapWord* mem_allocate_work(size_t size, bool is_tlab); HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); @@ -192,12 +190,8 @@ public: MemRegion reserved_region() const { return _reserved; } HeapWord* base() const { return _reserved.start(); } - // Memory allocation. "gc_time_limit_was_exceeded" will - // be set to true if the adaptive size policy determine that - // an excessive amount of time is being spent doing collections - // and caused a null to be returned. If a null is not returned, - // "gc_time_limit_was_exceeded" has an undefined meaning. - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + // Memory allocation. + HeapWord* mem_allocate(size_t size) override; HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index f97cd4e3b70..662a6be695b 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -335,8 +335,7 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { return result; } -HeapWord* SerialHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* SerialHeap::mem_allocate(size_t size) { return mem_allocate_work(size, false /* is_tlab */); } diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index f0194f1a4a2..72778981eee 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -133,7 +133,7 @@ public: size_t max_capacity() const override; - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t size) override; // Callback from VM_SerialCollectForAllocation operation. // This function does everything necessary/possible to satisfy an diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 33d2fad8bba..57bd9316731 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -162,8 +162,7 @@ class CollectedHeap : public CHeapObj { // The obj and array allocate methods are covers for these methods. // mem_allocate() should never be // called to allocate TLABs, only individual objects. - virtual HeapWord* mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) = 0; + virtual HeapWord* mem_allocate(size_t size) = 0; // Filler object utilities. static inline size_t filler_array_hdr_size(); diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index 741b0ffb020..265c01b3683 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -48,7 +48,6 @@ class MemAllocator::Allocation: StackObj { const MemAllocator& _allocator; JavaThread* _thread; oop* _obj_ptr; - bool _overhead_limit_exceeded; bool _allocated_outside_tlab; size_t _allocated_tlab_size; @@ -71,7 +70,6 @@ public: : _allocator(allocator), _thread(JavaThread::cast(allocator._thread)), // Do not use Allocation in non-JavaThreads. _obj_ptr(obj_ptr), - _overhead_limit_exceeded(false), _allocated_outside_tlab(false), _allocated_tlab_size(0) { @@ -119,7 +117,7 @@ bool MemAllocator::Allocation::check_out_of_memory() { return false; } - const char* message = _overhead_limit_exceeded ? "GC overhead limit exceeded" : "Java heap space"; + const char* message = "Java heap space"; if (!_thread->is_in_internal_oome_mark()) { // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support report_java_out_of_memory(message); @@ -133,10 +131,7 @@ bool MemAllocator::Allocation::check_out_of_memory() { message); } - oop exception = _overhead_limit_exceeded ? - Universe::out_of_memory_error_gc_overhead_limit() : - Universe::out_of_memory_error_java_heap(); - THROW_OOP_(exception, true); + THROW_OOP_(Universe::out_of_memory_error_java_heap(), true); } else { THROW_OOP_(Universe::out_of_memory_error_java_heap_without_backtrace(), true); } @@ -238,7 +233,7 @@ void MemAllocator::Allocation::notify_allocation() { HeapWord* MemAllocator::mem_allocate_outside_tlab(Allocation& allocation) const { allocation._allocated_outside_tlab = true; - HeapWord* mem = Universe::heap()->mem_allocate(_word_size, &allocation._overhead_limit_exceeded); + HeapWord* mem = Universe::heap()->mem_allocate(_word_size); if (mem == nullptr) { return mem; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index b662aeb7eb7..927c9e15dc5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1094,8 +1094,7 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req return result; } -HeapWord* ShenandoahHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* ShenandoahHeap::mem_allocate(size_t size) { ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared(size); return allocate_memory(req); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index bec1235e941..eafd1b28b3a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -704,7 +704,7 @@ private: public: HeapWord* allocate_memory(ShenandoahAllocRequest& request); - HeapWord* mem_allocate(size_t size, bool* what) override; + HeapWord* mem_allocate(size_t size) override; MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) override; diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 238b5b06683..ae60219139c 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -149,7 +149,7 @@ oop ZCollectedHeap::array_allocate(Klass* klass, size_t size, int length, bool d return allocator.allocate(); } -HeapWord* ZCollectedHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) { +HeapWord* ZCollectedHeap::mem_allocate(size_t size) { const size_t size_in_bytes = ZUtils::words_to_bytes(align_object_size(size)); return (HeapWord*)ZHeap::heap()->alloc_object(size_in_bytes); } diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 3d466564b54..c124976c80f 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -76,7 +76,7 @@ public: bool requires_barriers(stackChunkOop obj) const override; oop array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS) override; - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t size) override; MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) override; From 1e90af08abb74df9ec4ab94b67deeae5c1c9fee1 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Fri, 5 Sep 2025 14:30:40 +0000 Subject: [PATCH 149/295] 8359383: Incorrect starting positions for implicitly typed variables Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 7 +- .../sun/tools/javac/parser/JavacParser.java | 27 +++--- .../com/sun/tools/javac/tree/JCTree.java | 27 ++++-- .../com/sun/tools/javac/tree/Pretty.java | 5 +- .../com/sun/tools/javac/tree/TreeCopier.java | 2 +- .../com/sun/tools/javac/tree/TreeInfo.java | 13 +-- .../com/sun/tools/javac/tree/TreeMaker.java | 5 +- .../javac/parser/DeclarationEndPositions.java | 93 +++++++++++++++---- .../tools/javac/patterns/PrettyTest.java | 10 +- test/langtools/tools/javac/tree/VarTree.java | 6 ++ .../tools/javac/tree/VarWarnPosition.java | 3 + .../tools/javac/tree/VarWarnPosition.out | 4 +- 12 files changed, 143 insertions(+), 59 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 45ece909ad7..9f32e7f6186 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 @@ -1261,14 +1261,14 @@ public class Attr extends JCTree.Visitor { if (tree.init == null) { //cannot use 'var' without initializer log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit)); - tree.vartype = make.Erroneous(); + tree.vartype = make.at(tree.pos()).Erroneous(); } else { Fragment msg = canInferLocalVarType(tree); if (msg != null) { //cannot use 'var' with initializer which require an explicit target //(e.g. lambda, method reference, array initializer). log.error(tree, Errors.CantInferLocalVarType(tree.name, msg)); - tree.vartype = make.Erroneous(); + tree.vartype = make.at(tree.pos()).Erroneous(); } } } @@ -5707,6 +5707,9 @@ public class Attr extends JCTree.Visitor { private void setSyntheticVariableType(JCVariableDecl tree, Type type) { if (type.isErroneous()) { tree.vartype = make.at(tree.pos()).Erroneous(); + } else if (tree.declaredUsingVar()) { + Assert.check(tree.typePos != Position.NOPOS); + tree.vartype = make.at(tree.typePos).Type(type); } else { tree.vartype = make.at(tree.pos()).Type(type); } 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 4a990701315..fb8d3aaeecd 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 @@ -990,10 +990,12 @@ public class JavacParser implements Parser { pattern = toP(F.at(token.pos).AnyPattern()); } else { + int varTypePos = Position.NOPOS; if (parsedType == null) { boolean var = token.kind == IDENTIFIER && token.name() == names.var; e = unannotatedType(allowVar, TYPE | NOLAMBDA); if (var) { + varTypePos = e.pos; e = null; } } else { @@ -1031,9 +1033,10 @@ public class JavacParser implements Parser { if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) { name = names.empty; } - JCVariableDecl var = toP(F.at(varPos).VarDef(mods, name, e, null)); + JCVariableDecl var = toP(F.at(varPos).VarDef(mods, name, e, null, + varTypePos != Position.NOPOS ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT, + varTypePos)); if (e == null) { - var.startPos = pos; if (var.name == names.underscore && !allowVar) { log.error(DiagnosticFlag.SYNTAX, varPos, Errors.UseOfUnderscoreNotAllowed); } @@ -2175,7 +2178,8 @@ public class JavacParser implements Parser { if (param.vartype != null && restrictedTypeName(param.vartype, true) != null) { checkSourceLevel(param.pos, Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS); - param.startPos = TreeInfo.getStartPos(param.vartype); + param.declKind = JCVariableDecl.DeclKind.VAR; + param.typePos = TreeInfo.getStartPos(param.vartype); param.vartype = null; } } @@ -3815,7 +3819,7 @@ public class JavacParser implements Parser { syntaxError(token.pos, Errors.Expected(EQ)); } - int startPos = Position.NOPOS; + int varTypePos = Position.NOPOS; JCTree elemType = TreeInfo.innermostType(type, true); if (elemType.hasTag(IDENT)) { Name typeName = ((JCIdent) elemType).name; @@ -3827,19 +3831,17 @@ public class JavacParser implements Parser { reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedArray(typeName)); } else { declaredUsingVar = true; + varTypePos = elemType.pos; if (compound) //error - 'var' in compound local var decl reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedCompound(typeName)); - startPos = TreeInfo.getStartPos(mods); - if (startPos == Position.NOPOS) - startPos = TreeInfo.getStartPos(type); //implicit type type = null; } } } - JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init, declaredUsingVar)); - result.startPos = startPos; + JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init, + declaredUsingVar ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT, varTypePos)); return attach(result, dc); } @@ -3953,8 +3955,11 @@ public class JavacParser implements Parser { name = names.empty; } - return toP(F.at(pos).VarDef(mods, name, type, null, - type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var)); + boolean declaredUsingVar = type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var; + JCVariableDecl.DeclKind declKind = declaredUsingVar ? JCVariableDecl.DeclKind.VAR : + type != null ? JCVariableDecl.DeclKind.EXPLICIT : JCVariableDecl.DeclKind.IMPLICIT; + int typePos = type != null ? type.pos : pos; + return toP(F.at(pos).VarDef(mods, name, type, null, declKind, typePos)); } /** Resources = Resource { ";" Resources } 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 debc10c9ff8..0436f68b9e3 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 @@ -1002,6 +1002,13 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { * A variable definition. */ public static class JCVariableDecl extends JCStatement implements VariableTree { + + public enum DeclKind { + EXPLICIT, // "SomeType name" + IMPLICIT, // "name" + VAR, // "var name" + } + /** variable modifiers */ public JCModifiers mods; /** variable name */ @@ -1014,17 +1021,17 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public JCExpression init; /** symbol */ public VarSymbol sym; - /** explicit start pos */ - public int startPos = Position.NOPOS; - /** declared using `var` */ - private boolean declaredUsingVar; + /** how the variable's type was declared */ + public DeclKind declKind; + /** a source code position to use for "vartype" when null (can happen if declKind != EXPLICIT) */ + public int typePos; protected JCVariableDecl(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, VarSymbol sym) { - this(mods, name, vartype, init, sym, false); + this(mods, name, vartype, init, sym, DeclKind.EXPLICIT, Position.NOPOS); } protected JCVariableDecl(JCModifiers mods, @@ -1032,19 +1039,21 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { JCExpression vartype, JCExpression init, VarSymbol sym, - boolean declaredUsingVar) { + DeclKind declKind, + int typePos) { this.mods = mods; this.name = name; this.vartype = vartype; this.init = init; this.sym = sym; - this.declaredUsingVar = declaredUsingVar; + this.declKind = declKind; + this.typePos = typePos; } protected JCVariableDecl(JCModifiers mods, JCExpression nameexpr, JCExpression vartype) { - this(mods, null, vartype, null, null, false); + this(mods, null, vartype, null, null, DeclKind.EXPLICIT, Position.NOPOS); this.nameexpr = nameexpr; if (nameexpr.hasTag(Tag.IDENT)) { this.name = ((JCIdent)nameexpr).name; @@ -1059,7 +1068,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } public boolean declaredUsingVar() { - return declaredUsingVar; + return declKind == DeclKind.VAR; } @Override diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index 919b2325ef6..d953663a6d7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -724,7 +724,10 @@ public class Pretty extends JCTree.Visitor { print("... "); print(tree.name); } else { - printExpr(tree.vartype); + if (tree.vartype == null && tree.declaredUsingVar()) + print("var"); + else + printExpr(tree.vartype); print(' '); if (tree.name.isEmpty()) { print('_'); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java index 9c3ed3bbcd2..9efc6a9d895 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -551,7 +551,7 @@ public class TreeCopier

          implements TreeVisitor { JCExpression vartype = copy(t.vartype, p); if (t.nameexpr == null) { JCExpression init = copy(t.init, p); - return M.at(t.pos).VarDef(mods, t.name, vartype, init); + return M.at(t.pos).VarDef(mods, t.name, vartype, init, t.declKind, t.typePos); } else { JCExpression nameexpr = copy(t.nameexpr, p); return M.at(t.pos).ReceiverVarDef(mods, nameexpr, vartype); 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 ae946c5b6d6..a66dcaad851 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 @@ -610,17 +610,14 @@ public class TreeInfo { } case VARDEF: { JCVariableDecl node = (JCVariableDecl)tree; - if (node.startPos != Position.NOPOS) { - return node.startPos; - } else if (node.mods.pos != Position.NOPOS) { + if (node.mods.pos != Position.NOPOS) { return node.mods.pos; - } else if (node.vartype == null || node.vartype.pos == Position.NOPOS) { - //if there's no type (partially typed lambda parameter) - //simply return node position - return node.pos; - } else { + } else if (node.vartype != null) { return getStartPos(node.vartype); + } else if (node.typePos != Position.NOPOS) { + return node.typePos; } + break; } case BINDINGPATTERN: { JCBindingPattern node = (JCBindingPattern)tree; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 0d0852cb91b..0e71df99bdc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -237,8 +237,9 @@ public class TreeMaker implements JCTree.Factory { return tree; } - public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, boolean declaredUsingVar) { - JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, declaredUsingVar); + public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, + JCVariableDecl.DeclKind declKind, int typePos) { + JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, declKind, typePos); tree.pos = pos; return tree; } diff --git a/test/langtools/tools/javac/parser/DeclarationEndPositions.java b/test/langtools/tools/javac/parser/DeclarationEndPositions.java index 473d6bc2712..226b77769d1 100644 --- a/test/langtools/tools/javac/parser/DeclarationEndPositions.java +++ b/test/langtools/tools/javac/parser/DeclarationEndPositions.java @@ -49,7 +49,7 @@ import javax.tools.ToolProvider; public class DeclarationEndPositions { - public static void checkEndPosition(Class nodeType, String input, String marker) throws IOException { + public static void checkPositions(Class nodeType, String input, String markers) throws IOException { // Create source var source = new SimpleJavaFileObject(URI.create("file://T.java"), JavaFileObject.Kind.SOURCE) { @@ -71,11 +71,26 @@ public class DeclarationEndPositions { public Void scan(Tree node, Void aVoid) { if (nodeType.isInstance(node)) { JCTree tree = (JCTree)node; - int actual = TreeInfo.getEndPos(tree, unit.endPositions); - int expected = marker.indexOf('^') + 1; - if (actual != expected) { + + // Verify declaration start and end positions + int start = tree.getStartPosition(); + if (markers.charAt(start) != '<') { throw new AssertionError(String.format( - "wrong end pos %d != %d for \"%s\" @ %d", actual, expected, input, tree.pos)); + "wrong %s pos %d for \"%s\" in \"%s\"", "start", start, tree, input)); + } + int end = TreeInfo.getEndPos(tree, unit.endPositions); + if (markers.charAt(end - 1) != '>') { + throw new AssertionError(String.format( + "wrong %s pos %d for \"%s\" in \"%s\"", "end", end, tree, input)); + } + + // For variable declarations using "var", verify the "var" position + if (tree instanceof JCVariableDecl varDecl && varDecl.declaredUsingVar()) { + int vpos = varDecl.typePos; + if (!input.substring(vpos).startsWith("var")) { + throw new AssertionError(String.format( + "wrong %s pos %d for \"%s\" in \"%s\"", "var", vpos, tree, input)); + } } } return super.scan(node, aVoid); @@ -86,34 +101,74 @@ public class DeclarationEndPositions { public static void main(String... args) throws Exception { // JCModuleDecl - checkEndPosition(JCModuleDecl.class, + checkPositions(JCModuleDecl.class, "/* comment */ module fred { /* comment */ } /* comment */", - " ^ "); + " <---------------------------> "); // JCPackageDecl - checkEndPosition(JCPackageDecl.class, + checkPositions(JCPackageDecl.class, "/* comment */ package fred; /* comment */", - " ^ "); + " <-----------> "); // JCClassDecl - checkEndPosition(JCClassDecl.class, + checkPositions(JCClassDecl.class, "/* comment */ class Fred { /* comment */ } /* comment */", - " ^ "); + " <--------------------------> "); // JCMethodDecl - checkEndPosition(JCMethodDecl.class, + checkPositions(JCMethodDecl.class, "/* comment */ class Fred { void m() { /* comment */ } } /* comment */", - " ^ "); + " <------------------------> "); // JCVariableDecl - checkEndPosition(JCVariableDecl.class, + checkPositions(JCVariableDecl.class, "/* comment */ class Fred { int x; } /* comment */", - " ^ "); - checkEndPosition(JCVariableDecl.class, + " <----> "); + checkPositions(JCVariableDecl.class, "/* comment */ class Fred { int x = 123; } /* comment */", - " ^ "); - checkEndPosition(JCVariableDecl.class, + " <----------> "); + checkPositions(JCVariableDecl.class, "/* comment */ class A { try {} catch (Error err) {} } /* comment */", - " ^ "); + " <-------> "); + checkPositions(JCVariableDecl.class, + "/* comment */ class Fred { final int x = 123; } /* comment */", + " <----------------> "); + checkPositions(JCVariableDecl.class, + "/* comment */ class Fred { final int x = 123, y = 456; } /* comment */", + " <---------------->--------> "); + checkPositions(JCVariableDecl.class, + "/* comment */ class A { void m() { try {} catch (Error err) {} } } /* comment */", + " <-------> "); + + // JCVariableDecl with "var" declarations + checkPositions(JCVariableDecl.class, + "class A { void m() { var foo; } }", + " <------> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { var foo = 42; } }", + " <-----------> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { final var foo = 42; } }", + " <-----------------> "); + + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = foo -> { } } }", + " <-> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = (foo) -> { } } }", + " <-> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = (var foo) -> { } } }", + " <-----> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = (final var foo) -> { } } }", + " <-----------> "); + + checkPositions(JCVariableDecl.class, + "class A { record R(int x) { } void m() { switch (null) { case R(var x) -> {} default -> {} } } }", + " <---> <---> "); + checkPositions(JCVariableDecl.class, + "class A { record R(int x) { } void m() { switch (null) { case R(final var x) -> {} default -> {} } } }", + " <---> <---------> "); } } diff --git a/test/langtools/tools/javac/patterns/PrettyTest.java b/test/langtools/tools/javac/patterns/PrettyTest.java index 5425127e91b..5f9c74b760e 100644 --- a/test/langtools/tools/javac/patterns/PrettyTest.java +++ b/test/langtools/tools/javac/patterns/PrettyTest.java @@ -72,12 +72,12 @@ public class PrettyTest { boolean _ = true; b = o instanceof String s; b = o instanceof R(String s); - b = o instanceof R(/*missing*/ s); - b = o instanceof R2(R(/*missing*/ s), String t); - b = o instanceof R2(R(/*missing*/ s), /*missing*/ t); + b = o instanceof R(var s); + b = o instanceof R2(R(var s), String t); + b = o instanceof R2(R(var s), var t); b = o instanceof R(String _); - b = o instanceof R2(R(/*missing*/ _), /*missing*/ _); - b = o instanceof R2(R(_), /*missing*/ t); + b = o instanceof R2(R(var _), var _); + b = o instanceof R2(R(_), var t); } \n\ class R { diff --git a/test/langtools/tools/javac/tree/VarTree.java b/test/langtools/tools/javac/tree/VarTree.java index 5ce7ec07541..2c70d5eb317 100644 --- a/test/langtools/tools/javac/tree/VarTree.java +++ b/test/langtools/tools/javac/tree/VarTree.java @@ -67,6 +67,12 @@ public class VarTree { "java.lang.String testVar"); test.run("java.util.function.Consumer c = (|var testVar|) -> {};", "java.lang.String testVar"); + test.run("java.util.function.Consumer c = (|final var testVar|) -> {};", + "final java.lang.String testVar"); + test.run("record Rec(int x) { }; switch (null) { case Rec(|var testVar|) -> {} default -> {} };", + "int testVar"); + test.run("record Rec(int x) { }; switch (null) { case Rec(|final var testVar|) -> {} default -> {} };", + "final int testVar"); } void run(String code, String expected) throws IOException { diff --git a/test/langtools/tools/javac/tree/VarWarnPosition.java b/test/langtools/tools/javac/tree/VarWarnPosition.java index 7dae84f3542..f1d5f4346d0 100644 --- a/test/langtools/tools/javac/tree/VarWarnPosition.java +++ b/test/langtools/tools/javac/tree/VarWarnPosition.java @@ -22,6 +22,9 @@ public class VarWarnPosition { // Test 3 Consumer c2 = (var d) -> { }; + + // Test 4 + Consumer c3 = (final var d) -> { }; } } diff --git a/test/langtools/tools/javac/tree/VarWarnPosition.out b/test/langtools/tools/javac/tree/VarWarnPosition.out index 2200c8b4ae0..87a4ca3a1fd 100644 --- a/test/langtools/tools/javac/tree/VarWarnPosition.out +++ b/test/langtools/tools/javac/tree/VarWarnPosition.out @@ -3,4 +3,6 @@ VarWarnPosition.java:21:18: compiler.warn.has.been.deprecated: Depr, compiler.mi VarWarnPosition.java:21:28: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package VarWarnPosition.java:24:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package VarWarnPosition.java:24:30: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package -5 warnings +VarWarnPosition.java:27:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +VarWarnPosition.java:27:36: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +7 warnings From ceacf6f7852514dc9877cfe284f9550c179d913a Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 5 Sep 2025 15:26:13 +0000 Subject: [PATCH 150/295] 8366890: C2: Split through phi printing with TraceLoopOpts misses line break Reviewed-by: rcastanedalo, mhaessig, epeter --- src/hotspot/share/opto/loopopts.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index a09eef0bb81..66404b44b86 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -230,8 +230,8 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { #ifndef PRODUCT if (TraceLoopOpts) { - tty->print("Split %d %s through %d Phi in %d %s", - n->_idx, n->Name(), phi->_idx, region->_idx, region->Name()); + tty->print_cr("Split %d %s through %d Phi in %d %s", + n->_idx, n->Name(), phi->_idx, region->_idx, region->Name()); } #endif // !PRODUCT From 9f4d5b2398cb925ec1a66f9f7676b76c99ff7b62 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 5 Sep 2025 15:55:19 +0000 Subject: [PATCH 151/295] 8365428: Unclear comments on java.lang.invoke Holder classes Reviewed-by: iklam, jvernee --- .../java/lang/invoke/BoundMethodHandle.java | 40 ++++---- .../lang/invoke/DelegatingMethodHandle.java | 8 +- .../java/lang/invoke/DirectMethodHandle.java | 8 +- .../lang/invoke/GenerateJLIClassesHelper.java | 95 ++++++++++++++++--- .../lang/invoke/InvokerBytecodeGenerator.java | 1 + .../classes/java/lang/invoke/Invokers.java | 8 +- .../classes/java/lang/invoke/LambdaForm.java | 17 +++- 7 files changed, 139 insertions(+), 38 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java index e7cbed61522..f8f62394095 100644 --- a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -38,13 +38,23 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newInternalError; import static java.lang.invoke.MethodHandleStatics.uncaughtException; -/** - * The flavor of method handle which emulates an invoke instruction - * on a predetermined argument. The JVM dispatches to the correct method - * when the handle is created, not when it is invoked. - * - * All bound arguments are encapsulated in dedicated species. - */ +/// The flavor of method handle which is constructed with unmodifiable bound values, +/// usable by lambda forms. For example, they can carry a configuration object +/// for its lambda form, or carry an underlying method handle and its bound +/// arguments for currying. +/// +/// Each BMH class supports a number of values, each of a particular [BasicType]. +/// This per-class value type and count information is recorded by [SpeciesData]. +/// A [Specializer] manages lookup for any species. +/// +/// Factories are provided by [BoundMethodHandle.SpeciesData#factory()]. +/// Getters are exposed as [BoundMethodHandle.SpeciesData#getter(int)], +/// which can be included as names in lambda forms. +/// +/// [SimpleMethodHandle] (with no bound value) and [Species_L] (with a bound +/// reference value) are explicitly provided to prevent bootstrap loops; the +/// rest may be generated on demand, or may be pregenerated by +/// [GenerateJLIClassesHelper]. @AOTSafeClassInitializer /*non-public*/ abstract non-sealed class BoundMethodHandle extends MethodHandle { @@ -465,18 +475,10 @@ abstract non-sealed class BoundMethodHandle extends MethodHandle { assert(BMH_TRANSFORMS.size() == TYPE_LIMIT); } - /** - * Generation of concrete BMH classes. - * - * A concrete BMH species is fit for binding a number of values adhering to a - * given type pattern. Reference types are erased. - * - * BMH species are cached by type pattern. - * - * A BMH species has a number of fields with the concrete (possibly erased) types of - * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs, - * which can be included as names in lambda forms. - */ + /// Generates concrete BMH classes. + /// + /// [GenerateJLIClassesHelper] can pre-generate species that are known + /// to be loaded from [MethodHandleStatics#traceSpeciesType]. class Factory extends ClassSpecializer.Factory { @Override protected String chooseFieldName(Class type, int index) { diff --git a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java index 992c011ae98..f0d98c6dca6 100644 --- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java @@ -196,7 +196,13 @@ abstract sealed class DelegatingMethodHandle extends MethodHandle UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for DelegatingMethodHandles generated ahead of time */ + /// Holds pre-generated bytecode for lambda forms used by DelegatingMethodHandle. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} } diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index b60304dcd7b..b5738ad6fba 100644 --- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -939,7 +939,13 @@ sealed class DirectMethodHandle extends MethodHandle { UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for DirectMethodHandles generated ahead of time */ + /// Holds pre-generated bytecode for lambda forms used by DirectMethodHandle. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} } diff --git a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java index 6d9f32575c8..c8d910e7456 100644 --- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java +++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java @@ -47,11 +47,72 @@ import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.LambdaForm.Kind.*; import static java.lang.invoke.MethodTypeForm.*; -/** - * Helper class to assist the GenerateJLIClassesPlugin to get access to - * generate classes ahead of time. - */ -class GenerateJLIClassesHelper { +/// Generates bound method handle species classes, and classes with methods that +/// hold compiled lambda form bytecode ahead of time, so certain lambda forms +/// no longer need to spin classes because they can find existing bytecode. +/// Bytecode pre-generation reduces static initialization costs, footprint costs, +/// and circular dependencies that may arise if a class is generated per +/// LambdaForm by [InvokerBytecodeGenerator]. +/// +/// Since lambda forms and bound method handle species are closely tied to +/// method types, which have many varieties, this generator needs *traces* to +/// detect which method types are used, so generation matches the actual usage. +/// See the main entrypoint [#generateHolderClasses(Stream)] for more details +/// about *traces*. +/// +/// Note this pregeneration does not cover all lambda forms that can be created. +/// For example, forms created by [LambdaFormEditor] are not captured. +/// +/// Pregenerated species classes are resolved in [ClassSpecializer.Factory#loadSpecies] +/// and behave identically to on-demand generated ones. Pregenerated lambda +/// forms are resolved in [InvokerBytecodeGenerator#lookupPregenerated], which +/// looks up methods for code from the following 4 possibly-generated classes: +/// - [Invokers.Holder] +/// - [DirectMethodHandle.Holder] +/// - [DelegatingMethodHandle.Holder] +/// - [LambdaForm.Holder] +/// +/// [VarHandle] linker forms, analogous to invoker forms in [Invokers.Holder], +/// have a similar pre-generation system except it is done at source generation; +/// they reside in [VarHandleGuards]. +/// +/// ## Usages of this generator +/// Currently, `GenerateJLIClassesHelper` is invoked when creating a modular JDK +/// image or generating an AOT cache. +/// +/// #### Modular Image +/// When creating a modular JDK image, +/// `jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin` passes the +/// *traces* in the file `jdk/tools/jlink/internal/plugins/default_jli_trace.txt` +/// in `$JAVA_HOME/lib/modules` to this generator. The *traces* are generated +/// from the execution of `build.tools.classlist.HelloClasslist` in the build +/// process of the JDK. +/// +/// > To list all the Species classes in a JDK image: +/// > ``` +/// > jimage list $JAVA_HOME/lib/modules | grep BoundMethodHandle.Species_ +/// > ``` +/// +/// > All these pregenerated classes can be examined by javap in the same image: +/// > (Note to escape `$` in bash) +/// > ``` +/// > javap -c -p -v java.lang.invoke.LambdaForm\$Holder +/// > ``` +/// +/// #### AOT Cache +/// When creating an AOT cache, *traces* generated from the training run are +/// captured and stored inside the AOT configuration file, and are accessed with +/// the C++ `FinalImageRecipes` class. Classes regenerated from these *traces* +/// are linked in assembly phase; see `regeneratedClasses.hpp`. +/// +/// @see #generateHolderClasses(Stream) +/// @see BoundMethodHandle.Specializer +/// @see DelegatingMethodHandle.Holder +/// @see DirectMethodHandle.Holder +/// @see Invokers.Holder +/// @see LambdaForm.Holder +/// @see VarHandleGuards +final class GenerateJLIClassesHelper { // Map from DirectMethodHandle method type name to index to LambdaForms static final Map DMH_METHOD_TYPE_MAP = Map.of( @@ -321,13 +382,23 @@ class GenerateJLIClassesHelper { } } - /* - * Returns a map of class name in internal form to the corresponding class bytes - * per the given stream of SPECIES_RESOLVE and LF_RESOLVE trace logs. - * - * Used by GenerateJLIClassesPlugin to pre-generate holder classes during - * jlink phase. - */ + /// Returns a map from class names in internal form to the corresponding + /// class bytes. + /// + /// A few known lambda forms, such as field accessors, can be comprehensively + /// generated. Most others lambda forms are associated with unique method + /// types; thus they are generated per the given stream of SPECIES_RESOLVE + /// and LF_RESOLVE *trace* logs, which are created according to {@link + /// MethodHandleStatics#TRACE_RESOLVE} configuration. + /// + /// The names of methods in the generated classes are internal tokens + /// recognized by [InvokerBytecodeGenerator#lookupPregenerated] and are + /// subject to change. + /// + /// @param traces the *traces* to determine the lambda forms and species + /// to generate + /// @see MethodHandleStatics#traceLambdaForm + /// @see MethodHandleStatics#traceSpeciesType static Map generateHolderClasses(Stream traces) { Objects.requireNonNull(traces); HolderClassBuilder builder = new HolderClassBuilder(); diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index b3d2ff2c880..2ac9f15272f 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -445,6 +445,7 @@ class InvokerBytecodeGenerator { return resolvedMember; } + /// Look up a method that may have been generated by [GenerateJLIClassesHelper]. private static MemberName lookupPregenerated(LambdaForm form, MethodType invokerType) { if (form.customized != null) { // No pre-generated version for customized LF diff --git a/src/java.base/share/classes/java/lang/invoke/Invokers.java b/src/java.base/share/classes/java/lang/invoke/Invokers.java index 478ef2b9068..bd97307ac27 100644 --- a/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -697,7 +697,13 @@ class Invokers { UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for Invokers generated ahead of time */ + /// Holds pre-generated bytecode for lambda forms used by method type invokers. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} } diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 9030a063fad..f36d3feba9c 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -139,13 +139,16 @@ class LambdaForm { public static final int VOID_RESULT = -1, LAST_RESULT = -2; + /// Represents the "basic" types that exist in the JVM linkage and stack/locals. + /// All objects are erased to a reference. + /// All subwords (boolean, byte, char, short) are promoted to int. enum BasicType { - L_TYPE('L', Object.class, Wrapper.OBJECT, TypeKind.REFERENCE), // all reference types + L_TYPE('L', Object.class, Wrapper.OBJECT, TypeKind.REFERENCE), I_TYPE('I', int.class, Wrapper.INT, TypeKind.INT), J_TYPE('J', long.class, Wrapper.LONG, TypeKind.LONG), F_TYPE('F', float.class, Wrapper.FLOAT, TypeKind.FLOAT), - D_TYPE('D', double.class, Wrapper.DOUBLE, TypeKind.DOUBLE), // all primitive types - V_TYPE('V', void.class, Wrapper.VOID, TypeKind.VOID); // not valid in all contexts + D_TYPE('D', double.class, Wrapper.DOUBLE, TypeKind.DOUBLE), // end arg types + V_TYPE('V', void.class, Wrapper.VOID, TypeKind.VOID); // only valid in method return static final @Stable BasicType[] ALL_TYPES = BasicType.values(); static final @Stable BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1); @@ -1730,7 +1733,13 @@ class LambdaForm { UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for identity and constant forms generated ahead of time */ + /// Holds pre-generated bytecode for common lambda forms. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} From 9cca4f7c760bea9bf79f7c03f37a70449acad51e Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 5 Sep 2025 16:44:08 +0000 Subject: [PATCH 152/295] 8358751: C2: Recursive inlining check for compiled lambda forms is broken Reviewed-by: dlong, roland --- src/hotspot/share/opto/bytecodeInfo.cpp | 33 ++++++++++-------- src/hotspot/share/opto/callnode.cpp | 23 +++++++++++-- src/hotspot/share/opto/callnode.hpp | 46 ++++++++++++++++--------- src/hotspot/share/opto/parse1.cpp | 7 ++++ 4 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/opto/bytecodeInfo.cpp b/src/hotspot/share/opto/bytecodeInfo.cpp index 547cf2f6a38..5b48b33aa46 100644 --- a/src/hotspot/share/opto/bytecodeInfo.cpp +++ b/src/hotspot/share/opto/bytecodeInfo.cpp @@ -60,6 +60,7 @@ InlineTree::InlineTree(Compile* c, // Keep a private copy of the caller_jvms: _caller_jvms = new (C) JVMState(caller_jvms->method(), caller_tree->caller_jvms()); _caller_jvms->set_bci(caller_jvms->bci()); + _caller_jvms->set_receiver_info(caller_jvms->receiver_info()); assert(!caller_jvms->should_reexecute(), "there should be no reexecute bytecode with inlining"); assert(_caller_jvms->same_calls_as(caller_jvms), "consistent JVMS"); } @@ -437,24 +438,26 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, // detect direct and indirect recursive inlining { - // count the current method and the callee const bool is_compiled_lambda_form = callee_method->is_compiled_lambda_form(); - int inline_level = 0; - if (!is_compiled_lambda_form) { - if (method() == callee_method) { - inline_level++; - } + const bool is_method_handle_invoker = is_compiled_lambda_form && !jvms->method()->is_compiled_lambda_form(); + + ciInstance* lform_callee_recv = nullptr; + if (is_compiled_lambda_form && !is_method_handle_invoker) { // MH invokers don't have a receiver + lform_callee_recv = jvms->compute_receiver_info(callee_method); } - // count callers of current method and callee - Node* callee_argument0 = is_compiled_lambda_form ? jvms->map()->argument(jvms, 0)->uncast() : nullptr; - for (JVMState* j = jvms->caller(); j != nullptr && j->has_method(); j = j->caller()) { + + int inline_level = 0; + for (JVMState* j = jvms; j != nullptr && j->has_method(); j = j->caller()) { if (j->method() == callee_method) { - if (is_compiled_lambda_form) { - // Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly - // a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the - // compiler stack. - Node* caller_argument0 = j->map()->argument(j, 0)->uncast(); - if (caller_argument0 == callee_argument0) { + // Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly + // a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the + // compiler stack. + if (lform_callee_recv != nullptr) { + ciInstance* lform_caller_recv = j->receiver_info(); + assert(lform_caller_recv != nullptr || j->depth() == 1 || + !j->caller()->method()->is_compiled_lambda_form(), // MH invoker + "missing receiver info"); + if (lform_caller_recv == lform_callee_recv || lform_caller_recv == nullptr) { inline_level++; } } else { diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 728093851b0..995208ba24f 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -262,7 +262,8 @@ uint TailJumpNode::match_edge(uint idx) const { //============================================================================= JVMState::JVMState(ciMethod* method, JVMState* caller) : - _method(method) { + _method(method), + _receiver_info(nullptr) { assert(method != nullptr, "must be valid call site"); _bci = InvocationEntryBci; _reexecute = Reexecute_Undefined; @@ -278,7 +279,8 @@ JVMState::JVMState(ciMethod* method, JVMState* caller) : _sp = 0; } JVMState::JVMState(int stack_size) : - _method(nullptr) { + _method(nullptr), + _receiver_info(nullptr) { _bci = InvocationEntryBci; _reexecute = Reexecute_Undefined; DEBUG_ONLY(_map = (SafePointNode*)-1); @@ -613,6 +615,7 @@ JVMState* JVMState::clone_shallow(Compile* C) const { n->set_endoff(_endoff); n->set_sp(_sp); n->set_map(_map); + n->set_receiver_info(_receiver_info); return n; } @@ -687,6 +690,20 @@ int JVMState::interpreter_frame_size() const { return size + Deoptimization::last_frame_adjust(0, callee_locals) * BytesPerWord; } +// Compute receiver info for a compiled lambda form at call site. +ciInstance* JVMState::compute_receiver_info(ciMethod* callee) const { + assert(callee != nullptr && callee->is_compiled_lambda_form(), ""); + if (has_method() && method()->is_compiled_lambda_form()) { // callee is not a MH invoker + Node* recv = map()->argument(this, 0); + assert(recv != nullptr, ""); + const TypeOopPtr* recv_toop = recv->bottom_type()->isa_oopptr(); + if (recv_toop != nullptr && recv_toop->const_oop() != nullptr) { + return recv_toop->const_oop()->as_instance(); + } + } + return nullptr; +} + //============================================================================= bool CallNode::cmp( const Node &n ) const { return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; } @@ -1364,7 +1381,7 @@ void CallLeafNode::dump_spec(outputStream *st) const { //============================================================================= -void SafePointNode::set_local(JVMState* jvms, uint idx, Node *c) { +void SafePointNode::set_local(const JVMState* jvms, uint idx, Node *c) { assert(verify_jvms(jvms), "jvms must match"); int loc = jvms->locoff() + idx; if (in(loc)->is_top() && idx > 0 && !c->is_top() ) { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 96706683f51..093c47194ef 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -217,6 +217,7 @@ private: int _bci; // Byte Code Index of this JVM point ReexecuteState _reexecute; // Whether this bytecode need to be re-executed ciMethod* _method; // Method Pointer + ciInstance* _receiver_info; // Constant receiver instance for compiled lambda forms SafePointNode* _map; // Map node associated with this scope public: friend class Compile; @@ -259,6 +260,7 @@ public: bool is_reexecute_undefined() const { return _reexecute==Reexecute_Undefined; } bool has_method() const { return _method != nullptr; } ciMethod* method() const { assert(has_method(), ""); return _method; } + ciInstance* receiver_info() const { assert(has_method(), ""); return _receiver_info; } JVMState* caller() const { return _caller; } SafePointNode* map() const { return _map; } uint depth() const { return _depth; } @@ -304,6 +306,7 @@ public: // _reexecute is initialized to "undefined" for a new bci void set_bci(int bci) {if(_bci != bci)_reexecute=Reexecute_Undefined; _bci = bci; } void set_should_reexecute(bool reexec) {_reexecute = reexec ? Reexecute_True : Reexecute_False;} + void set_receiver_info(ciInstance* recv) { assert(has_method() || recv == nullptr, ""); _receiver_info = recv; } // Miscellaneous utility functions JVMState* clone_deep(Compile* C) const; // recursively clones caller chain @@ -311,6 +314,7 @@ public: void set_map_deep(SafePointNode *map);// reset map for all callers void adapt_position(int delta); // Adapt offsets in in-array after adding an edge. int interpreter_frame_size() const; + ciInstance* compute_receiver_info(ciMethod* callee) const; #ifndef PRODUCT void print_method_with_lineno(outputStream* st, bool show_name) const; @@ -374,7 +378,7 @@ public: } private: - void verify_input(JVMState* jvms, uint idx) const { + void verify_input(const JVMState* jvms, uint idx) const { assert(verify_jvms(jvms), "jvms must match"); Node* n = in(idx); assert((!n->bottom_type()->isa_long() && !n->bottom_type()->isa_double()) || @@ -383,34 +387,44 @@ public: public: // Functionality from old debug nodes which has changed - Node *local(JVMState* jvms, uint idx) const { - verify_input(jvms, jvms->locoff() + idx); - return in(jvms->locoff() + idx); + Node* local(const JVMState* jvms, uint idx) const { + uint loc_idx = jvms->locoff() + idx; + assert(jvms->is_loc(loc_idx), "not a local slot"); + verify_input(jvms, loc_idx); + return in(loc_idx); } - Node *stack(JVMState* jvms, uint idx) const { - verify_input(jvms, jvms->stkoff() + idx); - return in(jvms->stkoff() + idx); + Node* stack(const JVMState* jvms, uint idx) const { + uint stk_idx = jvms->stkoff() + idx; + assert(jvms->is_stk(stk_idx), "not a stack slot"); + verify_input(jvms, stk_idx); + return in(stk_idx); } - Node *argument(JVMState* jvms, uint idx) const { - verify_input(jvms, jvms->argoff() + idx); + Node* argument(const JVMState* jvms, uint idx) const { + uint arg_idx = jvms->argoff() + idx; + assert(jvms->is_stk(arg_idx), "not an argument slot"); + verify_input(jvms, arg_idx); return in(jvms->argoff() + idx); } - Node *monitor_box(JVMState* jvms, uint idx) const { + Node* monitor_box(const JVMState* jvms, uint idx) const { assert(verify_jvms(jvms), "jvms must match"); - return in(jvms->monitor_box_offset(idx)); + uint mon_box_idx = jvms->monitor_box_offset(idx); + assert(jvms->is_monitor_box(mon_box_idx), "not a monitor box offset"); + return in(mon_box_idx); } - Node *monitor_obj(JVMState* jvms, uint idx) const { + Node* monitor_obj(const JVMState* jvms, uint idx) const { assert(verify_jvms(jvms), "jvms must match"); - return in(jvms->monitor_obj_offset(idx)); + uint mon_obj_idx = jvms->monitor_obj_offset(idx); + assert(jvms->is_mon(mon_obj_idx) && !jvms->is_monitor_box(mon_obj_idx), "not a monitor obj offset"); + return in(mon_obj_idx); } - void set_local(JVMState* jvms, uint idx, Node *c); + void set_local(const JVMState* jvms, uint idx, Node *c); - void set_stack(JVMState* jvms, uint idx, Node *c) { + void set_stack(const JVMState* jvms, uint idx, Node *c) { assert(verify_jvms(jvms), "jvms must match"); set_req(jvms->stkoff() + idx, c); } - void set_argument(JVMState* jvms, uint idx, Node *c) { + void set_argument(const JVMState* jvms, uint idx, Node *c) { assert(verify_jvms(jvms), "jvms must match"); set_req(jvms->argoff() + idx, c); } diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index f7e11f0d213..7aa96d2ace3 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1149,6 +1149,13 @@ SafePointNode* Parse::create_entry_map() { // Create an initial safepoint to hold JVM state during parsing JVMState* jvms = new (C) JVMState(method(), _caller->has_method() ? _caller : nullptr); set_map(new SafePointNode(len, jvms)); + + // Capture receiver info for compiled lambda forms. + if (method()->is_compiled_lambda_form()) { + ciInstance* recv_info = _caller->compute_receiver_info(method()); + jvms->set_receiver_info(recv_info); + } + jvms->set_map(map()); record_for_igvn(map()); assert(jvms->endoff() == len, "correct jvms sizing"); From a17058b5bb2dcc89ed276600ceac905e7e986426 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 5 Sep 2025 17:45:37 +0000 Subject: [PATCH 153/295] 8365569: Remove finalize from JavaSoundAudioClip.java Reviewed-by: kizune, tr --- .../sun/media/sound/JavaSoundAudioClip.java | 430 ++--------------- .../sound/JavaSoundAudioClipDelegate.java | 455 ++++++++++++++++++ 2 files changed, 490 insertions(+), 395 deletions(-) create mode 100644 src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java index 6b81eaf008e..9eb32f9b439 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java @@ -25,82 +25,25 @@ package com.sun.media.sound; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.net.URLConnection; -import javax.sound.SoundClip; -import javax.sound.midi.InvalidMidiDataException; -import javax.sound.midi.MetaEventListener; -import javax.sound.midi.MetaMessage; -import javax.sound.midi.MidiFileFormat; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Sequence; import javax.sound.midi.Sequencer; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.SoundClip; +import sun.java2d.Disposer; +import sun.java2d.DisposerRecord; /** * Java Sound audio clip; * - * @author Arthur van Hoff, Kara Kytle, Jan Borgersen - * @author Florian Bomers */ -public final class JavaSoundAudioClip implements MetaEventListener, LineListener { - - private long lastPlayCall = 0; - private static final int MINIMUM_PLAY_DELAY = 30; - - private byte[] loadedAudio = null; - private int loadedAudioByteLength = 0; - private AudioFormat loadedAudioFormat = null; - - private AutoClosingClip clip = null; - private boolean clipLooping = false; - private boolean clipPlaying = false; - - private DataPusher datapusher = null; - private boolean daemonThread = false; - - private Sequencer sequencer = null; - private Sequence sequence = null; - private boolean sequencerloop = false; - private volatile boolean success; - - /** - * used for determining how many samples is the - * threshold between playing as a Clip and streaming - * from the file. - * - * $$jb: 11.07.99: the engine has a limit of 1M - * samples to play as a Clip, so compare this number - * with the number of samples in the stream. - * - */ - private static final long CLIP_THRESHOLD = 1048576; - private static final int STREAM_BUFFER_SIZE = 1024; +public final class JavaSoundAudioClip { public static JavaSoundAudioClip create(final File file) throws IOException { - JavaSoundAudioClip clip = new JavaSoundAudioClip(); - clip.daemonThread = true; // used only by javax.sound.SoundClip - try (FileInputStream stream = new FileInputStream(file)) { - clip.init(stream); - } - return clip; + return new JavaSoundAudioClip(file); } /* Used [only] by sun.awt.www.content.MultiMediaContentHandlers */ @@ -127,192 +70,32 @@ public final class JavaSoundAudioClip implements MetaEventListener, LineListener return null; } - private void init(InputStream in) throws IOException { - BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE); - bis.mark(STREAM_BUFFER_SIZE); - try { - AudioInputStream as = AudioSystem.getAudioInputStream(bis); - // load the stream data into memory - success = loadAudioData(as); + private JavaSoundAudioClipDelegate delegate; - if (success) { - success = false; - if (loadedAudioByteLength < CLIP_THRESHOLD) { - success = createClip(); - } - if (!success) { - success = createSourceDataLine(); - } - } - } catch (UnsupportedAudioFileException e) { - try { - MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis); - success = createSequencer(bis); - } catch (InvalidMidiDataException e1) { - success = false; - } - } + public JavaSoundAudioClip(final File file) throws IOException { + disposerRecord = new AudioClipDisposerRecord(); + Disposer.addRecord(this, disposerRecord); + delegate = new JavaSoundAudioClipDelegate(file, disposerRecord); } public synchronized boolean canPlay() { - return success; + return delegate.canPlay(); } public synchronized boolean isPlaying() { - if (!canPlay()) { - return false; - } else if (clip != null) { - return clipPlaying; - } else if (datapusher != null) { - return datapusher.isPlaying(); - } else if (sequencer != null) { - return sequencer.isRunning(); - } - return false; + return delegate.isPlaying(); } public synchronized void play() { - if (!success) { - return; - } - startImpl(false); + delegate.play(); } public synchronized void loop() { - if (!success) { - return; - } - startImpl(true); - } - - private synchronized void startImpl(boolean loop) { - // hack for some applications that call the start method very rapidly... - long currentTime = System.currentTimeMillis(); - long diff = currentTime - lastPlayCall; - if (diff < MINIMUM_PLAY_DELAY) { - return; - } - lastPlayCall = currentTime; - try { - if (clip != null) { - // We need to disable autoclosing mechanism otherwise the clip - // can be closed after "!clip.isOpen()" check, because of - // previous inactivity. - clip.setAutoClosing(false); - try { - if (!clip.isOpen()) { - clip.open(loadedAudioFormat, loadedAudio, 0, - loadedAudioByteLength); - } else { - clip.flush(); - if (loop != clipLooping) { - // need to stop in case the looped status changed - clip.stop(); - } - } - clip.setFramePosition(0); - if (loop) { - clip.loop(Clip.LOOP_CONTINUOUSLY); - } else { - clip.start(); - } - clipLooping = loop; - } finally { - clip.setAutoClosing(true); - } - } else if (datapusher != null ) { - datapusher.start(loop); - - } else if (sequencer != null) { - sequencerloop = loop; - if (sequencer.isRunning()) { - sequencer.setMicrosecondPosition(0); - } - if (!sequencer.isOpen()) { - try { - sequencer.open(); - sequencer.setSequence(sequence); - - } catch (InvalidMidiDataException | MidiUnavailableException e) { - if (Printer.err) e.printStackTrace(); - } - } - sequencer.addMetaEventListener(this); - try { - sequencer.start(); - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - } - } - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - } + delegate.loop(); } public synchronized void stop() { - if (!success) { - return; - } - lastPlayCall = 0; - - if (clip != null) { - try { - clip.flush(); - } catch (Exception e1) { - if (Printer.err) e1.printStackTrace(); - } - try { - clip.stop(); - } catch (Exception e2) { - if (Printer.err) e2.printStackTrace(); - } - } else if (datapusher != null) { - datapusher.stop(); - } else if (sequencer != null) { - try { - sequencerloop = false; - sequencer.removeMetaEventListener(this); - sequencer.stop(); - } catch (Exception e3) { - if (Printer.err) e3.printStackTrace(); - } - try { - sequencer.close(); - } catch (Exception e4) { - if (Printer.err) e4.printStackTrace(); - } - } - } - - // Event handlers (for debugging) - - @Override - public synchronized void update(LineEvent event) { - if (clip != null) { - if (clip == event.getSource()) { - if (event.getType() == LineEvent.Type.START) { - clipPlaying = true; - } else if ((event.getType() == LineEvent.Type.STOP) || - (event.getType() == LineEvent.Type.CLOSE)) { - clipPlaying = false; - } - } - } - } - - // handle MIDI track end meta events for looping - - @Override - public synchronized void meta(MetaMessage message) { - if( message.getType() == 47 ) { - if (sequencerloop){ - //notifyAll(); - sequencer.setMicrosecondPosition(0); - loop(); - } else { - stop(); - } - } + delegate.stop(); } @Override @@ -320,180 +103,37 @@ public final class JavaSoundAudioClip implements MetaEventListener, LineListener return getClass().toString(); } - @Override - @SuppressWarnings("removal") - protected void finalize() { + private AudioClipDisposerRecord disposerRecord; + static class AudioClipDisposerRecord implements DisposerRecord { - if (clip != null) { - clip.close(); + private volatile AutoClosingClip clip; + private volatile DataPusher datapusher; + private volatile Sequencer sequencer; + + void setClip(AutoClosingClip clip) { + this.clip = clip; } - //$$fb 2001-09-26: may improve situation related to bug #4302884 - if (datapusher != null) { - datapusher.close(); + void setDataPusher(DataPusher datapusher) { + this.datapusher = datapusher; } - if (sequencer != null) { - sequencer.close(); - } - } - - // FILE LOADING METHODS - - private boolean loadAudioData(AudioInputStream as) throws IOException, UnsupportedAudioFileException { - // first possibly convert this stream to PCM - as = Toolkit.getPCMConvertedAudioInputStream(as); - if (as == null) { - return false; + void setSequencer(Sequencer sequencer) { + this.sequencer = sequencer; } - loadedAudioFormat = as.getFormat(); - long frameLen = as.getFrameLength(); - int frameSize = loadedAudioFormat.getFrameSize(); - long byteLen = AudioSystem.NOT_SPECIFIED; - if (frameLen != AudioSystem.NOT_SPECIFIED - && frameLen > 0 - && frameSize != AudioSystem.NOT_SPECIFIED - && frameSize > 0) { - byteLen = frameLen * frameSize; - } - if (byteLen != AudioSystem.NOT_SPECIFIED) { - // if the stream length is known, it can be efficiently loaded into memory - readStream(as, byteLen); - } else { - // otherwise we use a ByteArrayOutputStream to load it into memory - readStream(as); - } - - // if everything went fine, we have now the audio data in - // loadedAudio, and the byte length in loadedAudioByteLength - return true; - } - - private void readStream(AudioInputStream as, long byteLen) throws IOException { - // arrays "only" max. 2GB - int intLen; - if (byteLen > 2147483647) { - intLen = 2147483647; - } else { - intLen = (int) byteLen; - } - loadedAudio = new byte[intLen]; - loadedAudioByteLength = 0; - - // this loop may throw an IOException - while (true) { - int bytesRead = as.read(loadedAudio, loadedAudioByteLength, intLen - loadedAudioByteLength); - if (bytesRead <= 0) { - as.close(); - break; + public void dispose() { + if (clip != null) { + clip.close(); } - loadedAudioByteLength += bytesRead; - } - } - private void readStream(AudioInputStream as) throws IOException { - - DirectBAOS baos = new DirectBAOS(); - int totalBytesRead; - try (as) { - totalBytesRead = (int) as.transferTo(baos); - } - loadedAudio = baos.getInternalBuffer(); - loadedAudioByteLength = totalBytesRead; - } - - // METHODS FOR CREATING THE DEVICE - - private boolean createClip() { - try { - DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat); - if (!(AudioSystem.isLineSupported(info)) ) { - if (Printer.err) Printer.err("Clip not supported: "+loadedAudioFormat); - // fail silently - return false; + if (datapusher != null) { + datapusher.close(); } - Object line = AudioSystem.getLine(info); - if (!(line instanceof AutoClosingClip)) { - if (Printer.err) Printer.err("Clip is not auto closing!"+clip); - // fail -> will try with SourceDataLine - return false; + + if (sequencer != null) { + sequencer.close(); } - clip = (AutoClosingClip) line; - clip.setAutoClosing(true); - clip.addLineListener(this); - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - // fail silently - return false; } - - if (clip==null) { - // fail silently - return false; - } - return true; } - - private boolean createSourceDataLine() { - try { - DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat); - if (!(AudioSystem.isLineSupported(info)) ) { - if (Printer.err) Printer.err("Line not supported: "+loadedAudioFormat); - // fail silently - return false; - } - SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info); - datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength, daemonThread); - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - // fail silently - return false; - } - - if (datapusher==null) { - // fail silently - return false; - } - return true; - } - - private boolean createSequencer(BufferedInputStream in) throws IOException { - // get the sequencer - try { - sequencer = MidiSystem.getSequencer( ); - } catch(MidiUnavailableException me) { - if (Printer.err) me.printStackTrace(); - return false; - } - if (sequencer==null) { - return false; - } - - try { - sequence = MidiSystem.getSequence(in); - if (sequence == null) { - return false; - } - } catch (InvalidMidiDataException e) { - if (Printer.err) e.printStackTrace(); - return false; - } - return true; - } - - /* - * private inner class representing a ByteArrayOutputStream - * which allows retrieval of the internal array - */ - private static class DirectBAOS extends ByteArrayOutputStream { - DirectBAOS() { - super(); - } - - public byte[] getInternalBuffer() { - return buf; - } - - } // class DirectBAOS } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java new file mode 100644 index 00000000000..1bd9987aaaf --- /dev/null +++ b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * 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.media.sound; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.SoundClip; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiFileFormat; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.UnsupportedAudioFileException; +import com.sun.media.sound.JavaSoundAudioClip.AudioClipDisposerRecord; + +/** + * Java Sound audio clip; + * + */ +public final class JavaSoundAudioClipDelegate implements MetaEventListener, LineListener { + + private long lastPlayCall = 0; + private static final int MINIMUM_PLAY_DELAY = 30; + + private byte[] loadedAudio = null; + private int loadedAudioByteLength = 0; + private AudioFormat loadedAudioFormat = null; + + private AutoClosingClip clip = null; + private boolean clipLooping = false; + private boolean clipPlaying = false; + + private DataPusher datapusher = null; + + private Sequencer sequencer = null; + private Sequence sequence = null; + private boolean sequencerloop = false; + private volatile boolean success; + + /** + * used for determining how many samples is the + * threshold between playing as a Clip and streaming + * from the file. + * + * $$jb: 11.07.99: the engine has a limit of 1M + * samples to play as a Clip, so compare this number + * with the number of samples in the stream. + * + */ + private static final long CLIP_THRESHOLD = 1048576; + private static final int STREAM_BUFFER_SIZE = 1024; + + private AudioClipDisposerRecord disposerRecord; + JavaSoundAudioClipDelegate(File file, AudioClipDisposerRecord record) throws IOException { + this.disposerRecord = record; + try (FileInputStream stream = new FileInputStream(file)) { + init(stream); + } + + } + + private void init(InputStream in) throws IOException { + BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE); + bis.mark(STREAM_BUFFER_SIZE); + try { + AudioInputStream as = AudioSystem.getAudioInputStream(bis); + // load the stream data into memory + success = loadAudioData(as); + + if (success) { + success = false; + if (loadedAudioByteLength < CLIP_THRESHOLD) { + success = createClip(); + } + if (!success) { + success = createSourceDataLine(); + } + } + } catch (UnsupportedAudioFileException e) { + try { + MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis); + success = createSequencer(bis); + } catch (InvalidMidiDataException e1) { + success = false; + } + } + } + + public synchronized boolean canPlay() { + return success; + } + + public synchronized boolean isPlaying() { + if (!canPlay()) { + return false; + } else if (clip != null) { + return clipPlaying; + } else if (datapusher != null) { + return datapusher.isPlaying(); + } else if (sequencer != null) { + return sequencer.isRunning(); + } + return false; + } + + public synchronized void play() { + if (!success) { + return; + } + startImpl(false); + } + + public synchronized void loop() { + if (!success) { + return; + } + startImpl(true); + } + + private synchronized void startImpl(boolean loop) { + // hack for some applications that call the start method very rapidly... + long currentTime = System.currentTimeMillis(); + long diff = currentTime - lastPlayCall; + if (diff < MINIMUM_PLAY_DELAY) { + return; + } + lastPlayCall = currentTime; + try { + if (clip != null) { + // We need to disable autoclosing mechanism otherwise the clip + // can be closed after "!clip.isOpen()" check, because of + // previous inactivity. + clip.setAutoClosing(false); + try { + if (!clip.isOpen()) { + clip.open(loadedAudioFormat, loadedAudio, 0, + loadedAudioByteLength); + } else { + clip.flush(); + if (loop != clipLooping) { + // need to stop in case the looped status changed + clip.stop(); + } + } + clip.setFramePosition(0); + if (loop) { + clip.loop(Clip.LOOP_CONTINUOUSLY); + } else { + clip.start(); + } + clipLooping = loop; + } finally { + clip.setAutoClosing(true); + } + } else if (datapusher != null ) { + datapusher.start(loop); + + } else if (sequencer != null) { + sequencerloop = loop; + if (sequencer.isRunning()) { + sequencer.setMicrosecondPosition(0); + } + if (!sequencer.isOpen()) { + try { + sequencer.open(); + sequencer.setSequence(sequence); + + } catch (InvalidMidiDataException | MidiUnavailableException e) { + if (Printer.err) e.printStackTrace(); + } + } + sequencer.addMetaEventListener(this); + try { + sequencer.start(); + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + } + } + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + } + } + + public synchronized void stop() { + if (!success) { + return; + } + lastPlayCall = 0; + + if (clip != null) { + try { + clip.flush(); + } catch (Exception e1) { + if (Printer.err) e1.printStackTrace(); + } + try { + clip.stop(); + } catch (Exception e2) { + if (Printer.err) e2.printStackTrace(); + } + } else if (datapusher != null) { + datapusher.stop(); + } else if (sequencer != null) { + try { + sequencerloop = false; + sequencer.removeMetaEventListener(this); + sequencer.stop(); + } catch (Exception e3) { + if (Printer.err) e3.printStackTrace(); + } + try { + sequencer.close(); + } catch (Exception e4) { + if (Printer.err) e4.printStackTrace(); + } + } + } + + // Event handlers (for debugging) + + @Override + public synchronized void update(LineEvent event) { + if (clip != null) { + if (clip == event.getSource()) { + if (event.getType() == LineEvent.Type.START) { + clipPlaying = true; + } else if ((event.getType() == LineEvent.Type.STOP) || + (event.getType() == LineEvent.Type.CLOSE)) { + clipPlaying = false; + } + } + } + } + + // handle MIDI track end meta events for looping + + @Override + public synchronized void meta(MetaMessage message) { + if( message.getType() == 47 ) { + if (sequencerloop){ + //notifyAll(); + sequencer.setMicrosecondPosition(0); + loop(); + } else { + stop(); + } + } + } + + @Override + public String toString() { + return getClass().toString(); + } + + // FILE LOADING METHODS + + private boolean loadAudioData(AudioInputStream as) throws IOException, UnsupportedAudioFileException { + // first possibly convert this stream to PCM + as = Toolkit.getPCMConvertedAudioInputStream(as); + if (as == null) { + return false; + } + + loadedAudioFormat = as.getFormat(); + long frameLen = as.getFrameLength(); + int frameSize = loadedAudioFormat.getFrameSize(); + long byteLen = AudioSystem.NOT_SPECIFIED; + if (frameLen != AudioSystem.NOT_SPECIFIED + && frameLen > 0 + && frameSize != AudioSystem.NOT_SPECIFIED + && frameSize > 0) { + byteLen = frameLen * frameSize; + } + if (byteLen != AudioSystem.NOT_SPECIFIED) { + // if the stream length is known, it can be efficiently loaded into memory + readStream(as, byteLen); + } else { + // otherwise we use a ByteArrayOutputStream to load it into memory + readStream(as); + } + + // if everything went fine, we have now the audio data in + // loadedAudio, and the byte length in loadedAudioByteLength + return true; + } + + private void readStream(AudioInputStream as, long byteLen) throws IOException { + // arrays "only" max. 2GB + int intLen; + if (byteLen > 2147483647) { + intLen = 2147483647; + } else { + intLen = (int) byteLen; + } + loadedAudio = new byte[intLen]; + loadedAudioByteLength = 0; + + // this loop may throw an IOException + while (true) { + int bytesRead = as.read(loadedAudio, loadedAudioByteLength, intLen - loadedAudioByteLength); + if (bytesRead <= 0) { + as.close(); + break; + } + loadedAudioByteLength += bytesRead; + } + } + + private void readStream(AudioInputStream as) throws IOException { + + DirectBAOS baos = new DirectBAOS(); + int totalBytesRead; + try (as) { + totalBytesRead = (int) as.transferTo(baos); + } + loadedAudio = baos.getInternalBuffer(); + loadedAudioByteLength = totalBytesRead; + } + + // METHODS FOR CREATING THE DEVICE + + private boolean createClip() { + try { + DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat); + if (!(AudioSystem.isLineSupported(info)) ) { + if (Printer.err) Printer.err("Clip not supported: "+loadedAudioFormat); + // fail silently + return false; + } + Object line = AudioSystem.getLine(info); + if (!(line instanceof AutoClosingClip)) { + if (Printer.err) Printer.err("Clip is not auto closing!"+clip); + // fail -> will try with SourceDataLine + return false; + } + clip = (AutoClosingClip) line; + disposerRecord.setClip(clip); + clip.setAutoClosing(true); + clip.addLineListener(this); + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + // fail silently + return false; + } + + if (clip==null) { + // fail silently + return false; + } + return true; + } + + private boolean createSourceDataLine() { + try { + DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat); + if (!(AudioSystem.isLineSupported(info)) ) { + if (Printer.err) Printer.err("Line not supported: "+loadedAudioFormat); + // fail silently + return false; + } + SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info); + datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength, true); + disposerRecord.setDataPusher(datapusher); + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + // fail silently + return false; + } + + if (datapusher==null) { + // fail silently + return false; + } + return true; + } + + private boolean createSequencer(BufferedInputStream in) throws IOException { + // get the sequencer + try { + sequencer = MidiSystem.getSequencer( ); + disposerRecord.setSequencer(sequencer); + } catch(MidiUnavailableException me) { + if (Printer.err) me.printStackTrace(); + return false; + } + if (sequencer==null) { + return false; + } + + try { + sequence = MidiSystem.getSequence(in); + if (sequence == null) { + return false; + } + } catch (InvalidMidiDataException e) { + if (Printer.err) e.printStackTrace(); + return false; + } + return true; + } + + /* + * private inner class representing a ByteArrayOutputStream + * which allows retrieval of the internal array + */ + private static class DirectBAOS extends ByteArrayOutputStream { + DirectBAOS() { + super(); + } + + public byte[] getInternalBuffer() { + return buf; + } + + } // class DirectBAOS +} From c6c451ac392cdb545ab43dd46918eca6c47cc5f0 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Fri, 5 Sep 2025 18:42:58 +0000 Subject: [PATCH 154/295] 8353468: [ubsan] arguments.cpp:2422:23: runtime error: 2.14748e+11 is outside the range of representable values of type 'int' Reviewed-by: stefank, dholmes --- src/hotspot/share/runtime/arguments.cpp | 48 ++++++++++---- .../jtreg/gc/arguments/TestHeapFreeRatio.java | 64 ++++++++++++++----- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0d4adc7f587..2ebc15d0e1a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2414,30 +2414,54 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin // Xmaxf } else if (match_option(option, "-Xmaxf", &tail)) { char* err; - int maxf = (int)(strtod(tail, &err) * 100); + double dmaxf = strtod(tail, &err); if (*err != '\0' || *tail == '\0') { jio_fprintf(defaultStream::error_stream(), - "Bad max heap free percentage size: %s\n", + "Bad max heap free ratio: %s\n", option->optionString); return JNI_EINVAL; - } else { - if (FLAG_SET_CMDLINE(MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } + } + if (dmaxf < 0.0 || dmaxf > 1.0) { + jio_fprintf(defaultStream::error_stream(), + "-Xmaxf value (%s) is outside the allowed range [ 0.0 ... 1.0 ]\n", + option->optionString); + return JNI_EINVAL; + } + const uintx umaxf = (uintx)(dmaxf * 100); + if (MinHeapFreeRatio > umaxf) { + jio_fprintf(defaultStream::error_stream(), + "-Xmaxf value (%s) must be greater than or equal to the implicit -Xminf value (%.2f)\n", + tail, MinHeapFreeRatio / 100.0f); + return JNI_EINVAL; + } + if (FLAG_SET_CMDLINE(MaxHeapFreeRatio, umaxf) != JVMFlag::SUCCESS) { + return JNI_EINVAL; } // Xminf } else if (match_option(option, "-Xminf", &tail)) { char* err; - int minf = (int)(strtod(tail, &err) * 100); + double dminf = strtod(tail, &err); if (*err != '\0' || *tail == '\0') { jio_fprintf(defaultStream::error_stream(), - "Bad min heap free percentage size: %s\n", + "Bad min heap free ratio: %s\n", option->optionString); return JNI_EINVAL; - } else { - if (FLAG_SET_CMDLINE(MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } + } + if (dminf < 0.0 || dminf > 1.0) { + jio_fprintf(defaultStream::error_stream(), + "-Xminf value (%s) is outside the allowed range [ 0.0 ... 1.0 ]\n", + tail); + return JNI_EINVAL; + } + const uintx uminf = (uintx)(dminf * 100); + if (MaxHeapFreeRatio < uminf) { + jio_fprintf(defaultStream::error_stream(), + "-Xminf value (%s) must be less than or equal to the implicit -Xmaxf value (%.2f)\n", + tail, MaxHeapFreeRatio / 100.0f); + return JNI_EINVAL; + } + if (FLAG_SET_CMDLINE(MinHeapFreeRatio, uminf) != JVMFlag::SUCCESS) { + return JNI_EINVAL; } // -Xss } else if (match_option(option, "-Xss", &tail)) { diff --git a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java index 066d3c03603..46c8f74db45 100644 --- a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java +++ b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * 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,24 +47,19 @@ public class TestHeapFreeRatio { COMBINATION_INVALID } - private static void testMinMaxFreeRatio(String min, String max, Validation type) throws Exception { - OutputAnalyzer output = GCArguments.executeTestJava( - "-Xminf" + min, - "-Xmaxf" + max, - "-version"); - + private static void checkValidity(OutputAnalyzer output, String min, String max, Validation type) { switch (type) { case VALID: output.shouldNotContain("Error"); output.shouldHaveExitValue(0); break; case MIN_INVALID: - output.shouldContain("Bad min heap free percentage size: -Xminf" + min); + output.shouldContain("Bad min heap free ratio: -Xminf" + min); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; case MAX_INVALID: - output.shouldContain("Bad max heap free percentage size: -Xmaxf" + max); + output.shouldContain("Bad max heap free ratio: -Xmaxf" + max); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; @@ -74,7 +69,7 @@ public class TestHeapFreeRatio { output.shouldHaveExitValue(1); break; case COMBINATION_INVALID: - output.shouldContain("must be less than or equal to MaxHeapFreeRatio"); + output.shouldMatch("must be (less|greater) than or equal to the implicit -Xm..f value"); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; @@ -85,10 +80,29 @@ public class TestHeapFreeRatio { System.out.println(output.getOutput()); } + private static void testMinMaxFreeRatio_Reordered(String min, String max, Validation type) throws Exception { + OutputAnalyzer output = GCArguments.executeTestJava( + "-Xmaxf" + max, + "-Xminf" + min, + "-version"); + + checkValidity(output, min, max, type); + } + + private static void testMinMaxFreeRatio(String min, String max, Validation type) throws Exception { + OutputAnalyzer output = GCArguments.executeTestJava( + "-Xminf" + min, + "-Xmaxf" + max, + "-version"); + + checkValidity(output, min, max, type); + } + public static void main(String args[]) throws Exception { - testMinMaxFreeRatio( "0.1", "0.5", Validation.VALID); - testMinMaxFreeRatio( ".1", ".5", Validation.VALID); - testMinMaxFreeRatio( "0.5", "0.5", Validation.VALID); + testMinMaxFreeRatio( "0.1", "0.5", Validation.VALID); + testMinMaxFreeRatio( ".1", ".5", Validation.VALID); + testMinMaxFreeRatio( "0.5", "0.5", Validation.VALID); + testMinMaxFreeRatio( "0.0","0.001", Validation.VALID); testMinMaxFreeRatio("=0.1", "0.5", Validation.MIN_INVALID); testMinMaxFreeRatio("0.1f", "0.5", Validation.MIN_INVALID); @@ -103,14 +117,30 @@ public class TestHeapFreeRatio { testMinMaxFreeRatio("-0.1", "0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "1.1", "0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( - "2147483647", "0.5", Validation.OUT_OF_RANGE); + "2147483647", "0.5", Validation.OUT_OF_RANGE); + testMinMaxFreeRatio( + "-2147483647", "0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "0.1", "-0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "0.1", "1.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "0.1", "2147483647", Validation.OUT_OF_RANGE); + testMinMaxFreeRatio( + "0.1", "-2147483647", Validation.OUT_OF_RANGE); - testMinMaxFreeRatio( "0.5", "0.1", Validation.COMBINATION_INVALID); - testMinMaxFreeRatio( ".5", ".10", Validation.COMBINATION_INVALID); - testMinMaxFreeRatio("0.12","0.100", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio( "0.5", "0.1", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio( ".5", ".10", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio("0.12", "0.100", Validation.COMBINATION_INVALID); + + // Default range is [0.40, 0.70] + // setting minf to 0.80 violates minf < maxf + testMinMaxFreeRatio("0.80", "0.90", Validation.COMBINATION_INVALID); + + // Options are re-ordered: -Xmaxf is given before -Xminf + + // valid range, but acceptable only if maxf be set first + testMinMaxFreeRatio_Reordered("0.80", "0.90", Validation.VALID); + + // although a valid range, but setting maxf first violates minf < maxf + testMinMaxFreeRatio_Reordered("0.10", "0.30", Validation.COMBINATION_INVALID); } } From e2a503e26ee2a3c428c5db0cd4cbe71cdc7d837f Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Fri, 5 Sep 2025 19:50:52 +0000 Subject: [PATCH 155/295] 8347277: java/awt/Focus/ComponentLostFocusTest.java fails intermittently Reviewed-by: serb --- .../awt/Focus/ComponentLostFocusTest.java | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/test/jdk/java/awt/Focus/ComponentLostFocusTest.java b/test/jdk/java/awt/Focus/ComponentLostFocusTest.java index 6af8322b2cd..8045ace43d5 100644 --- a/test/jdk/java/awt/Focus/ComponentLostFocusTest.java +++ b/test/jdk/java/awt/Focus/ComponentLostFocusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,20 @@ import java.awt.FlowLayout; import java.awt.Frame; import java.awt.KeyboardFocusManager; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Robot; import java.awt.TextField; +import java.awt.Toolkit; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.imageio.ImageIO; public class ComponentLostFocusTest { @@ -49,10 +56,10 @@ public class ComponentLostFocusTest { static TextField tf; static Robot r; static Dialog dialog = null; - static volatile boolean passed; static volatile Point loc; static volatile int width; static volatile int top; + static final CountDownLatch focusGainedLatch = new CountDownLatch(1); private static void createTestUI() { @@ -75,11 +82,7 @@ public class ComponentLostFocusTest { public static void doTest() { System.out.println("dialog.setVisible.... "); - new Thread(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }).start(); + new Thread(() -> dialog.setVisible(true)).start(); // The bug is that this construction leads to the redundant xRequestFocus // By the way, the requestFocusInWindow() works fine before the fix @@ -98,7 +101,7 @@ public class ComponentLostFocusTest { tf.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { System.out.println("TextField gained focus: " + e); - passed = true; + focusGainedLatch.countDown(); } }); @@ -116,6 +119,17 @@ public class ComponentLostFocusTest { tf.requestFocus(); } + private static void captureScreen() { + try { + final Rectangle screenBounds = new Rectangle( + Toolkit.getDefaultToolkit().getScreenSize()); + ImageIO.write(r.createScreenCapture(screenBounds), + "png", new File("ComponentLostFocusTest.png")); + } catch (Exception e) { + e.printStackTrace(); + } + } + public static final void main(String args[]) throws Exception { r = new Robot(); r.setAutoDelay(100); @@ -138,9 +152,10 @@ public class ComponentLostFocusTest { System.out.println("Focus owner: " + KeyboardFocusManager.getCurrentKeyboardFocusManager(). getFocusOwner()); - - if (!passed) { - throw new RuntimeException("TextField got no focus! Test failed."); + if (!focusGainedLatch.await(5, TimeUnit.SECONDS)) { + captureScreen(); + throw new RuntimeException("Waited too long, " + + "TextField got no focus! Test failed."); } } finally { EventQueue.invokeAndWait(() -> { @@ -151,4 +166,3 @@ public class ComponentLostFocusTest { } } } - From 4ab2b5bdb4e6d40a747d4088a25f7c6351131759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Fri, 5 Sep 2025 19:59:03 +0000 Subject: [PATCH 156/295] 8366569: Disable CompileTaskTimeout for known long-running test cases Reviewed-by: dlong --- .../compiler/c2/TestScalarReplacementMaxLiveNodes.java | 1 + .../codegen/TestAntiDependenciesHighMemUsage.java | 5 ++++- .../codegen/TestAntiDependenciesHighMemUsage2.java | 8 ++++++-- .../compiler/loopopts/TestMaxLoopOptsCountReached.java | 5 ++++- .../vectorapi/VectorReplicateLongSpecialImmTest.java | 7 ++++++- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java index f133e91a1ee..b5e349307c3 100644 --- a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java +++ b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java @@ -38,6 +38,7 @@ * -XX:CompileCommand=dontinline,*String*::substring * -XX:NodeCountInliningCutoff=220000 * -XX:DesiredMethodLimit=100000 + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 * compiler.c2.TestScalarReplacementMaxLiveNodes */ package compiler.c2; diff --git a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java index 5ca215d95ef..36bcbd866f4 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java +++ b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,7 +26,9 @@ * @test * @bug 8333258 * @summary C2: high memory usage in PhaseCFG::raise_above_anti_dependences() - * @run main/othervm -XX:CompileOnly=TestAntiDependenciesHighMemUsage::test1 -Xcomp TestAntiDependenciesHighMemUsage + * @run main/othervm -XX:CompileOnly=TestAntiDependenciesHighMemUsage::test1 -Xcomp + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 + * TestAntiDependenciesHighMemUsage */ public class TestAntiDependenciesHighMemUsage { diff --git a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java index cfe884c269f..5c5f95b6f7f 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java +++ b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,8 +26,11 @@ * @test * @bug 8333258 * @summary C2: high memory usage in PhaseCFG::raise_above_anti_dependences() - * @run main/othervm/timeout=480 -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 -XX:-ClipInlining - * -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement TestAntiDependenciesHighMemUsage2 + * @run main/othervm/timeout=480 -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 + * -XX:-ClipInlining -XX:-BackgroundCompilation + * -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 + * TestAntiDependenciesHighMemUsage2 */ public class TestAntiDependenciesHighMemUsage2 { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java index a529c69dae8..e8e603b84d3 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java @@ -26,7 +26,10 @@ * @bug 8284944 * @requires vm.compiler2.enabled * @summary triggers the loop optimization phase `LoopOptsCount` many times - * @run main/othervm/timeout=480 -Xcomp -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test TestMaxLoopOptsCountReached + * @run main/othervm/timeout=480 -Xcomp -XX:-PartialPeelLoop + * -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 + * TestMaxLoopOptsCountReached */ import java.lang.System.Logger.Level; diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java index b885abb632a..f9cb7d163d0 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java @@ -36,7 +36,12 @@ import org.testng.annotations.Test; * @library /test/lib * @requires os.arch == "aarch64" * @modules jdk.incubator.vector - * @run testng/othervm -XX:UseSVE=0 -XX:-TieredCompilation -XX:CompileThreshold=100 -XX:+IgnoreUnrecognizedVMOptions -XX:CompileCommand=MemLimit,*.*,0 compiler.vectorapi.VectorReplicateLongSpecialImmTest + * @run testng/othervm -XX:UseSVE=0 -XX:-TieredCompilation + * -XX:CompileThreshold=100 + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=MemLimit,*.*,0 + * -XX:CompileTaskTimeout=0 + * compiler.vectorapi.VectorReplicateLongSpecialImmTest */ public class VectorReplicateLongSpecialImmTest { From 3824c7cd06645b1dab5322015e8e6cf604afa754 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 5 Sep 2025 20:20:11 +0000 Subject: [PATCH 157/295] 8366517: Refine null locale processing of ctor/factory methods in `Date/DecimalFormatSymbols` Reviewed-by: jlu, rriggs --- .../share/classes/java/text/DateFormatSymbols.java | 5 ++++- .../share/classes/java/text/DecimalFormatSymbols.java | 4 +++- .../Format/DateFormat/IntlTestDateFormatSymbols.java | 10 +++++++++- .../NumberFormat/IntlTestDecimalFormatSymbols.java | 11 +++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index 9fff6a7c4d4..c8542ff17ee 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -145,10 +145,12 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @throws java.util.MissingResourceException * if the resources for the specified locale cannot be * found or cannot be loaded. + * @throws NullPointerException if {@code locale} is null */ public DateFormatSymbols(Locale locale) { - initializeData(locale); + initializeData(Objects.requireNonNull(locale, + "locale should not be null")); } /** @@ -344,6 +346,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @since 1.6 */ public static final DateFormatSymbols getInstance(Locale locale) { + Objects.requireNonNull(locale, "locale should not be null"); DateFormatSymbols dfs = getProviderInstance(locale); if (dfs != null) { return dfs; diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index c255b93bd98..fe512e9cc26 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -115,7 +115,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @throws NullPointerException if {@code locale} is null */ public DecimalFormatSymbols(Locale locale) { - initialize(locale); + initialize(Objects.requireNonNull(locale, + "locale should not be null")); } /** @@ -180,6 +181,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @since 1.6 */ public static final DecimalFormatSymbols getInstance(Locale locale) { + Objects.requireNonNull(locale, "locale should not be null"); LocaleProviderAdapter adapter; adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); DecimalFormatSymbolsProvider provider = adapter.getDecimalFormatSymbolsProvider(); diff --git a/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java b/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java index e3cb841b5c6..84b828f36c5 100644 --- a/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java +++ b/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @summary test International Date Format Symbols + * @bug 8366517 * @run junit IntlTestDateFormatSymbols */ /* @@ -43,6 +44,7 @@ import java.util.*; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; public class IntlTestDateFormatSymbols @@ -205,4 +207,10 @@ public class IntlTestDateFormatSymbols fail("ERROR: Clone failed"); } } + + @Test + void nullLocaleTest() { + assertThrows(NullPointerException.class, () -> new DateFormatSymbols(null)); + assertThrows(NullPointerException.class, () -> DateFormatSymbols.getInstance(null)); + } } diff --git a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java index 75c9199c95b..c370440c932 100644 --- a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java +++ b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8282625 + * @bug 8282625 8366517 * @summary test International Decimal Format Symbols * @run junit IntlTestDecimalFormatSymbols */ @@ -44,6 +44,7 @@ import java.util.*; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; public class IntlTestDecimalFormatSymbols @@ -146,4 +147,10 @@ public class IntlTestDecimalFormatSymbols fail("ERROR: Clone failed"); } } + + @Test + void nullLocaleTest() { + assertThrows(NullPointerException.class, () -> new DecimalFormatSymbols(null)); + assertThrows(NullPointerException.class, () -> DecimalFormatSymbols.getInstance(null)); + } } From b674a425531974bb78c4622e0f1d9b46a117f575 Mon Sep 17 00:00:00 2001 From: Sarvesh Kumar Jain Date: Fri, 5 Sep 2025 20:35:30 +0000 Subject: [PATCH 158/295] 8366750: Remove test 'java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java' from problemlist Reviewed-by: psadhukhan, serb --- test/jdk/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 58fb2c51397..aac9d9a8a21 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -260,7 +260,7 @@ java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java 8169469,8273617 java/awt/FullScreen/UninitializedDisplayModeChangeTest/UninitializedDisplayModeChangeTest.java 8273617 macosx-all java/awt/print/PrinterJob/PSQuestionMark.java 7003378 generic-all java/awt/print/PrinterJob/GlyphPositions.java 7003378 generic-all -java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 6849371 macosx-all,linux-all +java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 8366852 generic-all java/awt/Component/GetScreenLocTest/GetScreenLocTest.java 4753654 generic-all java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java 8165863 macosx-all java/awt/Clipboard/PasteNullToTextComponentsTest.java 8234140 macosx-all,windows-all From 1ebe949507b48a6b62dd36e08f0ae80da2ee1dcc Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 5 Sep 2025 20:47:48 +0000 Subject: [PATCH 159/295] 8314488: Compiling the JDK with C++17 Reviewed-by: dholmes, stefank, ayang, kvn, iwalulya, jsjolen, ihse --- doc/hotspot-style.html | 617 ++++++++++++++++-- doc/hotspot-style.md | 606 ++++++++++++++++- make/autoconf/flags-cflags.m4 | 6 +- .../vscode/hotspot/indexers/ccls-settings.txt | 2 +- .../hotspot/indexers/clangd-settings.txt | 2 +- .../hotspot/indexers/cpptools-settings.txt | 2 +- .../hotspot/indexers/rtags-settings.txt | 2 +- 7 files changed, 1150 insertions(+), 87 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 88ec07475fd..98d813242a5 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -50,6 +50,9 @@ id="toc-factoring-and-class-design">Factoring and Class Design

        4. Commenting
        5. Macros
        6. Whitespace
        7. +
        8. Avoid implicit conversions +to bool
        9. Miscellaneous
      @@ -72,28 +75,74 @@ Standard Library Deduction
    • Expression SFINAE
    • +
    • Non-type template parameter +values
    • enum
    • alignas
    • thread_local
    • nullptr
    • <atomic>
    • +
    • Inline +Variables
    • Initializing variables with static storage duration
    • Uniform Initialization
    • +
    • Mandatory Copy Elision
    • Local Function Objects
    • Inheriting constructors
    • Attributes
    • noexcept
    • +
    • Enhanced selection +statements
    • +
    • Expression Evaluation +Order
    • +
    • Compatibility with C11
    • Additional Permitted Features
    • +
    • Excluded +Features +
    • Undecided +Features +
    • @@ -418,22 +467,25 @@ adjust new lines horizontally to be consistent with that organization. (E.g., trailing backslashes on long macro definitions often align.)

      -

      Miscellaneous

      -
        -
      • Use the Resource Acquisition Is -Initialization (RAII) design pattern to manage bracketed critical -sections. See class ResourceMark for an example.

      • -
      • Avoid implicit conversions to bool.

        +

        Avoid implicit conversions +to bool

        • Use bool for boolean values.
        • Do not use ints or pointers as (implicit) booleans with &&, ||, if, while. Instead, compare explicitly, i.e. if (x != 0) or if (ptr != nullptr), etc.
        • -
        • Do not use declarations in condition forms, i.e. don't use -if (T v = value) { ... }.
        • -
      • +
      • Do not use non-boolean declarations in condition forms, +i.e. don't use if (T v = value) { ... }. But see Enhanced selection +statements.
      • +
      +

      Miscellaneous

      +
        +
      • Use the Resource Acquisition Is +Initialization (RAII) design pattern to manage bracketed critical +sections. See class ResourceMark for an example.

      • Use functions from globalDefinitions.hpp and related files when performing bitwise operations on integers. Do not code directly as C operators, unless they are extremely simple. (Examples: @@ -445,16 +497,16 @@ default case. It is ok to have an empty default with comment.

      Use of C++ Features

      HotSpot was originally written in a subset of the C++98/03 language. -More recently, support for C++14 is provided, though again, HotSpot only +More recently, support for C++17 is provided, though again, HotSpot only uses a subset. (Backports to JDK versions lacking support for more recent Standards must of course stick with the original C++98/03 subset.)

      This section describes that subset. Features from the C++98/03 language may be used unless explicitly excluded here. Features from -C++11 and C++14 may be explicitly permitted or explicitly excluded, and -discussed accordingly here. There is a third category, undecided -features, about which HotSpot developers have not yet reached a -consensus, or perhaps have not discussed at all. Use of these features +C++11, C++14, and C++17 may be explicitly permitted or explicitly +excluded, and discussed accordingly here. There is a third category, +undecided features, about which HotSpot developers have not yet reached +a consensus, or perhaps have not discussed at all. Use of these features is also excluded.

      (The use of some features may not be immediately obvious and may slip in anyway, since the compiler will accept them. The code review process @@ -463,9 +515,9 @@ is the main defense against this.)

      provide more extensive discussion or rationale for limitations. Features that don't have their own subsection are listed in omnibus feature sections for permitted, excluded, and undecided features.

      -

      Lists of new features for C++11 and C++14, along with links to their -descriptions, can be found in the online documentation for some of the -compilers and libraries. The C++14 Standard is the definitive +

      Lists of new features for C++11, C++14, and C++17, along with links +to their descriptions, can be found in the online documentation for some +of the compilers and libraries. The C++17 Standard is the definitive description.

      • C++ Standards @@ -662,12 +714,39 @@ href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">n1984
      • +
      • auto for non-type template parameters (p0127r2)
        auto may +be used as a placeholder for the type of a non-type template parameter. +The type is deduced from the value provided in a template +instantiation.

      • Function return type deduction (n3638)
        Only use if the function body has a very small number of return statements, and generally relatively little other code.

      • +
      • Class template argument deduction (n3602, p0091r3)
        The template arguments +of a class template may be deduced from the arguments to a constructor. +This is similar to ordinary function argument deduction, though partial +deduction with only some template arguments explicitly provided +is not permitted for class template argument deduction. Deduction guides +may be used to provide additional control over the deduction. As with +auto variable declarations, excessive use can make code +harder to understand, because explicit type information is lacking. But +it can also remove the need to be explicit about types that are either +obvious, or that are very hard to write. For example, these allow the +addition of a scope-guard mechanism with nice syntax; something like +this

      • +
      +
        ScopeGuard guard{[&]{ ... cleanup code ... }};
      +
      • Also see lambda expressions.

      • +
      • decltype(auto) should be avoided, whether for +variables, for non-type template parameters, or for function return +types. There are subtle and complex differences between this placeholder +type and auto. Any use would need very careful +explanation.

      Expression SFINAE

      https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468
      https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html

      +

      Non-type template parameter +values

      +

      C++17 extended the arguments permitted for non-type template +parameters (n4268). The kinds of +values (the parameter types) aren't changed. However, the values can now +be the result of arbitrary constant expressions (with a few restrictions +on the result), rather than a much more limited and restrictive set of +expressions. In particular, the argument for a pointer or reference type +parameter can now be the result of a constexpr function.

      enum

      Where appropriate, scoped-enums should be used. (n2347)

      @@ -805,6 +893,34 @@ differ from what the Java compilers implement.

      "conservative" memory ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering.

      +

      Inline Variables

      +

      Variables with static storage duration may be declared +inline (p0386r2). +This has similar effects as for declaring a function inline: it can be +defined, identically, in multiple translation units, must be defined in +every translation unit in which it is ODR used, and the behavior of the +program is as if there is exactly one variable.

      +

      Declaring a variable inline allows the complete definition to be in a +header file, rather than having a declaration in a header and the +definition in a .cpp file. The guidance on initialization +of such variables still applies. Inline variables with dynamic +initializations can make initialization order problems worse. The few +ordering constraints that exist for non-inline variables don't apply, as +there isn't a single program-designated translation unit containing the +definition.

      +

      A constexpr static data member is implicitly +inline. As a consequence, an ODR use of such a variable doesn't +require a definition in some .cpp file. (This is a change from +pre-C++17. Beginning with C++17, such a definition is considered a +duplicate definition, and is deprecated.)

      +

      Declaring a thread_local variable inline is +forbidden for HotSpot code. The use of +thread_local is already heavily restricted.

      Initializing variables with static storage duration

      @@ -856,6 +972,45 @@ initialization

      Although related, the use of std::initializer_list remains forbidden, as part of the avoidance of the C++ Standard Library in HotSpot code.

      +

      Mandatory Copy Elision

      +

      Copy elision +(or here) +is a compiler optimization used to avoid potentially expensive copies in +certain situations. It is critical to making practical the performance +of return by value or pass by value. It is also unusual in not following +the as-if rule for optimizations - copy elision can be applied even if +doing so bypasses side-effects of copying/moving the object. The C++ +standard explicitly permits this.

      +

      However, because it's an optional optimization, the relevant +copy/move constructor must be available and accessible, in case the +compiler chooses to not apply the optimization even in a situation where +permitted.

      +

      C++17 changed some cases of copy elision so that there is never a +copy/move in these cases (p0135r1). The interesting cases +involve a function that returns an unnamed temporary object, and +constructors. In such cases the object being initialized from the +temporary is always direct initialized, with no copy/move ever involved; +see RVO and more specifically URVO.

      +

      Since this is now standard behavior it can't be avoided in the +covered situations. This could change the behavior of code that relied +on side effects by constructors, but that's both uncommon and was +already problematic because of the previous optional copy elision. But +HotSpot code can, and should, explicitly take advantage of this newly +required behavior where it makes sense to do so.

      +

      For example, it may be beneficial to delay construction of the result +of a function until the return statement, rather than having a local +variable that is modified into the desired state and then returned. +(Though NRVO may apply in that +case.)

      +

      It is also now possible to define a factory function for a class that +is neither movable nor copyable, if it can be written in a way that +makes use of this feature.

      Local Function Objects

      • Local function objects, including lambda expressions, may be @@ -928,6 +1083,13 @@ href="https://en.wikipedia.org/wiki/Partial_application" title="Partial Application">partial application. Again here, lambdas are typically much simpler and less verbose than function object classes.

        +

        A lambda is a constexpr function if either the parameter declaration +clause is followed by constexpr, or it satisfies the +requirements for a constexpr function (p0170r1). +Thus, using a lambda to package up some computation doesn't incur +unnecessary overhead or prevent use in a context required to be +compile-time evaluated (such as an array size).

        Because of these benefits, lambda expressions are permitted in HotSpot code, with some restrictions and usage guidance. An anonymous lambda is one which is passed directly as an argument. A named lambda is @@ -975,6 +1137,18 @@ making the captured value unaffected by modifications to the outer variable. But this only applies to captured auto variables, not member variables, and is inconsistent with referential transparency.

      +
    • By-value capture of this (using a capture list like +[*this] (p0018r3)) +is also not permitted. One of the motivating use-cases is when the +lifetime of the lambda exceeds the lifetime of the object for the +containing member function. That is, we have an upward lambda that is +capturing this of the enclosing method. But again, that +use-case doesn't apply if only downward lambdas are used. Another +use-case is when we simply want the lambda to be operating on a copy of +this for some reason. This is sufficiently uncommon that it +can be handled by manual copying, so readers don't need to understand +this rare syntax.

    • Non-capturing lambdas (with an empty capture list - []) have limited utility. There are cases where no captures are required (pure functions, for example), but if the function is small @@ -984,14 +1158,15 @@ href="https://isocpp.org/files/papers/N3649.html">N3649) are not permitted. Capture initializers inherently increase the complexity of the capture list, and provide little benefit over an additional in-scope local variable.

    • - -

      The use of mutable lambda expressions is forbidden +

    • The use of mutable lambda expressions is forbidden because there don't seem to be many, if any, good use-cases for them in HotSpot. A lambda expression needs to be mutable in order to modify a by-value captured value. But with only downward lambdas, such usage seems likely to be rare and complicated. It is better to use a function object class in any such cases that arise, rather than requiring all -HotSpot developers to understand this relatively obscure feature.

      +HotSpot developers to understand this relatively obscure +feature.

    • +

      While it is possible to directly invoke an anonymous lambda expression, that feature should not be used, as such a form can be confusing to readers. Instead, name the lambda and call it by name.

      @@ -1109,23 +1284,12 @@ href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">n2540C++11 provides simple syntax allowing a class to inherit the constructors of a base class. Unfortunately there are a number of problems with the original specification, and C++17 contains significant -revisions (p0136r1 opens with a list of 8 Core Issues). Since -HotSpot doesn't support use of C++17, use of inherited constructors -could run into those problems. Such uses might also change behavior in a -future HotSpot update to use C++17 or later, potentially in subtle ways -that could lead to hard to diagnose problems. Because of this, HotSpot -code must not use inherited constructors.

      -

      Note that gcc7 provides the -fnew-inheriting-ctors -option to use the p0136r1 semantics. This is enabled by default when -using C++17 or later. It is also enabled by default for -fabi-version=11 (introduced by gcc7) or higher when using -C++11/14, as the change is considered a Defect Report that applies to -those versions. Earlier versions of gcc don't have that option, and -other supported compilers may not have anything similar.

      +revisions (p0136r1 +opens with a list of 8 Core Issues). Although those issues have been +addressed, the benefits from this feature are small compared to the +complexity. Because of this, HotSpot code must not use inherited +constructors.

      +

      p0195r0

      Attributes

      The use of some attributes (n2761) @@ -1141,9 +1305,17 @@ those cases HotSpot has a preferred location.

      beginning of the function's declaration, rather than between the function name and the parameter list. +

      p0068r0 is the initial +proposal for the attributes added by C++17.)

      Only the following attributes are permitted:

      The following attributes are expressly forbidden:

        @@ -1151,6 +1323,23 @@ function name and the parameter list. memory_order_consume.
      • [[deprecated]] - Not relevant in HotSpot code.
      +

      Direct use of non-standard (and presumably scoped) attributes in +shared code is also forbidden. Using such would depend on the C++17 +feature that an attribute not recognized by the implementation is +ignored (p0283r2). If such an +attribute is needed in shared code, the well-established technique of +providing an ATTRIBUTE_XXX macro with per-compiler +definitions (sometimes empty) should be used. Compilers may warn about +unrecognized attributes (whether by name or by location), in order to +report typos or misuse. Disabling such warnings globally would not be +desirable.

      +

      The use of using directives in attribute lists is also +forbidden. (p0028r0) (p0028r4) We don't generally use +scoped attributes in attribute lists with other attributes. Rather, uses +of scoped attributes (which are implementation defined) are generally +hidden behind a portability macro that includes the surrounding +brackets.

      noexcept

      Use of noexcept exception specifications (n3050) are permitted with restrictions @@ -1200,9 +1389,72 @@ Standard Library facilities.

      functions not declared noexcept. So HotSpot code doesn't ever need to check, either with conditional exception specifications or with noexcept expressions.

      +

      The exception specification is part of the type of a function (p0012r1. This likely has little +impact on HotSpot code, since the use of noexcept is +expected to be rare.

      Dynamic exception specifications were deprecated in C++11. C++17 removed all but throw(), with that remaining a deprecated equivalent to noexcept.

      +

      Enhanced selection +statements

      +

      C++17 modified the condition part of if and +switch statements, permitting an init-statement to +be included (p0305r1).

      +

      Use of this feature is permitted. (However, complex uses may +interfere with readability.) Limiting the scope of a variable involved +in the condition, while also making the value available to the +statement's body, can improve readability. The alternative method of +scope-limiting by introducing a nested scope isn't very popular and is +rarely used.

      +

      This new syntax is in addition to the condition being a +declaration with a brace-or-equal-initializer. For an +if statement this new sytax gains that benefit without +violating the long-standing guidance against using implicit conversions to +bool, which still stands.

      +

      For example, uses of Unified Logging sometimes explicitly check +whether a LogTarget is enabled. Instead of

      +
        LogTarget(...) lt;
      +  if (lt.is_enabled()) {
      +    LogStream log(lt);
      +    ... use log ...
      +  }
      +  ... lt is accessible but probably not needed here ...
      +

      using this feature one could write

      +
        if (LogTarget(...) lt; lt.is_enabled()) {
      +    LogStream log(lt);
      +    ... use log ...
      +  }
      +

      C++17 also added compile-time if statements (p0292r2). Use of +if constexpr is permitted. This feature can replace and +(sometimes vastly) simplify many uses of SFINAE. The same +declaration and initialization guidance for the condition part +apply here as for ordinary if statements.

      +

      Expression Evaluation Order

      +

      C++17 tightened up the evaluation order for some kinds of +subexpressions (p0138r2). Note, +however, that the Alternate Evaluation Order for Function Calls +alternative in that paper was adopted, rather than the strict left to +right order of evaluation for function call arguments that was proposed +in the main body of the paper.

      +

      The primary purpose of this change seems to be to make certain kinds +of call chaining well defined. That's not a style widely used in +HotSpot. In general it is better to continue to avoid questions in this +area by isolating operations with side effects from other statements. In +particular, continue to avoid modifying a value in an expression where +it is also used.

      +

      Compatibility with C11

      +

      C++17 refers to C11 rather than C99. This means that C11 libraries +and functions may be used in HotSpot. There may be limitations because +of differing levels of compatibility among various compilers and +versions of those compilers.

      +

      Note that the C parts of the JDK have been built with C11 selected +for some time (JDK-8292008).

      Additional Permitted Features

        @@ -1218,8 +1470,10 @@ href="https://isocpp.org/files/papers/n3778.html">n3778)

        href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">n2242) (n2555)

        -
      • Static assertions (n1720)

      • +
      • Static assertions (n1720) +(n3928)
        Both the original +(C++11) two-argument form and the new (C++17) single-argument form are +permitted.

      • decltype (n2343) (n2930< href="https://en.cppreference.com/w/cpp/language/range-for">range-for)

      • Unrestricted Unions (n2544)

      • +
      • Preprocessor Condition __has_include (p0061r0) (p0061r1)

      • +
      • Hexadecimal Floating-Point Literals (p0245r1)

      • +
      • Construction Rules for enum class Values (p0138r2)

      • +
      • Allow typename in template template parameter (n4051) — template template parameters +are barely used (if at all) in HotSpot, but there's no reason to +artificially disallow this syntactic regularization in any such +uses.

      -

      Excluded Features

      +

      Excluded Features

      +

      Structured Bindings

      +

      The use of structured bindings p0217r3 is forbidden. Preferred +approaches for handling functions with multiple return values +include

      +
        +
      • Return a named class/struct intended for that purpose, with named +and typed members/accessors.

      • +
      • Return a value along with out parameters (usually pointers, +sometimes references).

      • +
      • Designate a sentinel "failure" value in the normal return value +type, with some out of band location for additional information. For +example, this is the model typically used with errno, where +a function returns a normal result, or -1 to indicate an error, with +additional error information in errno.

      • +
      +

      There is a strong preference for names and explicit types, as opposed +to offsets and implicit types. For example, there are folks who strongly +dislike that some of the Standard Library functions return +std::pair because first and +second members don't carry any useful information.

      +

      File System Library

      +

      The use of the File System library is forbidden. HotSpot doesn't do +very much with files, and already has adequate mechanisms for its needs. +Rewriting in terms of this new library doesn't provide any obviously +significant benefits. Having a mix of the existing usage and uses of +this new library would be confusing.

      +

      n4100 p0218r0 p0219r1 p0317r1 p0392r0 p0430r2 p0492r2 p1164r1

      +

      Aggregate Extensions

      +

      Aggregates with base classes are forbidden. C++17 allows aggregate +initialization for classes with base classes (p0017r1). HotSpot makes very little +use of aggregate classes, preferring explicit constructors even for very +simple classes.

      +

      Additional Excluded Features

      • New string and character literals

          @@ -1295,22 +1603,239 @@ useful.

          operator overloading is used, ensure the semantics conform to the normal expected behavior of the operation.

        • Avoid most implicit conversion constructors and (implicit or -explicit) conversion operators. (Note that conversion to -bool isn't needed in HotSpot code because of the "no -implicit boolean" guideline.)

        • +explicit) conversion operators. Conversion to bool +operators aren't needed because of the no implicit boolean +guideline.)

        • Avoid goto statements.

        • +
        • Attributes for namespaces and enumerators (n4266 — The only applicable attribute +is [[deprecated]], which is +forbidden.

        • +
        • Variadic using declarations (p0195r2)

        • +
        • std::variant<> (p0088r3) — Even if more of the C++ +Standard Library is permitted, this class will remain forbidded. Invalid +accesses are indicated by throwing exceptions.

        • +
        • std::any (p0220r1) — Even if more of the C++ +Standard Library is permitted, this class will remain forbidden. It may +require allocation, and always uses the standard allocator. It requires +RTTI.

        • +
        • std::as_const() (p0007r1) — If sufficiently useful, +HotSpot could add such a function. It would likely be added to +globalDefinitions.hpp, where there are already some similar small +utilities.

        • +
        • std::clamp() (p002501) — This function is already +provided in globalDefinitions.hpp.

        • +
        • Parallel STL Algorithms (p0024r2) — Even if more of the C++ +Standard Library is permitted, these will remain forbidden. They are +built on the standard C++ threading mechanisms. HotSpot doesn't use +those mechanisms, instead providing and using its own.

        • +
        • Cache Line Sizes p0154r1 — +HotSpot has its own mechanisms for this, using values like +DEFAULT_CACHE_LINE_SIZE. The platform-specific +implementation of the HotSpot mechanisms might use these library +functions, but there is no reason to move away from the current +approach. Quoting from JOSUTTIS: "... if you know better, +use specific values, but using these values is better than any assumed +fixed size for code supporting multiple platforms."

        • +
        • register storage class removal p0001r1 — The register +storage class has been removed. register is still a +keyword, so still can't be used for normal purposes. Also, this doesn't +affect the use of register for gcc-style extended asm code; +that's a different syntactic element with a different meaning.

        • +
        • Value of __cplusplus — Testing whether +__cplusplus is defined or not is permitted, and indeed +required. But the value should not need to be examined. The value is +changed with each revision of the Standard. But we build HotSpot and +(most of) the rest of the JDK with a specifically selected version of +the Standard. The value of __cplusplus should be known and +unchanging until we change the project's build configuration again. So +examining the value shouldn't ever be necessary.

        • +
        • Removal of ++ for bool (p0003r1)

        • +
        • Removal of trigraphs (n4086)

        -

        Undecided Features

        +

        Undecided Features

        This list is incomplete; it serves to explicitly call out some features that have not yet been discussed.

        +

        Some features are undecided (so implicitly forbidden) because we +don't expect to use them at all. This might be reconsidered if someone +finds a good use case.

        +

        Some Standard Library features are undecided (so implicitly +forbidden) because, while this Style Guide forbids the use of such, they +may be sufficiently useful that we want to permit them anyway. Doing so +may require some idiomatic mechanism for addressing things like +assert incompatibility, incompatibility with HotSpot's +FORBID_C_FUNCTION mechanism, and the like.

        +

        std::optional<>

        +

        It is undecided whether to permit the use of +std::optional<> (p0220r1). It may be sufficiently +useful that it should be permitted despite the usual prohibition against +using Standard Library facilities. Use of the value() +member function must be forbidden, as it reports an invalid access by +throwing an exception.

        +

        std::byte

        +

        It is undecided whether to permit the use of the +std::byte type (p0298r3). It may be sufficiently +useful that it should be permitted despite the usual prohibition against +using Standard Library facilities.

        +

        It has been suggested that changing the HotSpot address +type to use std::byte has some benefits. That is, +replace

        +
        typedef u_char*       address;
        +typedef const u_char* const_address;
        +
        using address       = std::byte*;
        +using const_address = const std::byte*;
        +

        in globalDefinitions.hpp.

        +

        A specific benefit that was mentioned is that it might improve the +horrible way that gdb handles our current definition of the +address type.

        +
        #include <cstddef>
        +
        +typedef unsigned char* address;
        +typedef std::byte* address_b;
        +
        +int main() {
        +
        +  char* mem;
        +
        +  address addr = (address)mem;
        +  address_b addr_b = (address_b)mem;
        +
        +  return 0;
        +}
        +
        (gdb) p addr
        +$1 = (address) 0x7ffff7fe4fa0 <dl_main> "\363\017\036\372Uf\017\357\300H\211\345AWI\211\377AVAUATSH\201\354\210\002"
        +(gdb) p addr_b
        +$2 = (address_b) 0x7ffff7fe4fa0 <dl_main>
        +

        This needs to be explored. Some folks have said they will do so.

        +

        String Views

        +

        It is undecided whether to permit the use of +std::string_view (p0220r1).

        +

        HotSpot doesn't use std::string, but uses +char* strings a lot. Wrapping such in a +std::string_view to enable the use of various algorithms +could be useful. But since HotSpot also doesn't permit use of +<algorithm> and the like, that only gets the limited +set of algorithms provided by the view class directly.

        +

        There is also the issue of NUL termination; string views +are not necessarily NUL terminated. Moreover, if one goes +to the work of making one that is NUL terminated, that +terminator is included in the size.

        +

        There are other caveats. Permitting use of string views would require +discussion of those.

        +

        Substring and Subsequence +Searching

        +

        In addition to simple substring searching, the Standard Library now +includes Boyer-Moore and Boyer-Moore-Horspool searchers, in case someone +wants to search really large texts. That seems an unlikely use-case for +HotSpot. See p0220r1.

        +

        new and +delete with Over-Aligned Data

        +

        It is undecided whether to permit the use of dynamic allocation of +overaligned types (n3396).

        +

        HotSpot currently only has a couple of over-aligned types that are +dynamically allocated. These are handled manually, not going through +new expressions, as that couldn't work before C++17.

        +

        One of the ways an over-aligned type might arise is by aligning a +data member. This might be done to avoid destructive interference for +concurrent accesses. But HotSpot uses a different approach, using +explicit padding. Again, this is in part because new and +delete of overaligned types didn't work. But we might +prefer to continue this approach.

        +

        We would need to add operator new overloads to +CHeapObj<> and possibly in other places in order to +support this. However, it has been suggested that implementing it +(efficiently) on top of NMT might be difficult. Note that +posix_memalign / _aligned_malloc don't help +here, because of NMT's use of malloc headers.

        +

        If we don't support it we may want to add operator new +overloads that are deleted, to prevent attempted uses.

        +

        Alignment usage in non-HotSpot parts of the OpenJDK:

        +
          +
        • alignas used once in harfbuzz, to align a +variable.

        • +
        • libpipewire has #define SPA_ALIGNED macro using gcc +aligned attribute, but doesn't use it.

        • +
        • libsleef has #define ALIGNED macro using gcc +aligned attribute. It is not used for class or member +declarations.

        • +
        +

        std::to_chars() and +std::from_chars

        +

        It is undecided whether to permit the use of +std::to_chars() and std::from_chars() (p0067r5).

        +

        These functions provide low-level conversions between character +sequences and numeric values. This seems like a good candidate for use +in HotSpot, potentially replacing various clumsy or less performant +alternatives. There is no memory allocation. Parsing failures are +indicated via error codes rather than exceptions. Various other nice for +HotSpot properties.

        +

        Note that the published C++17 Standard puts these in +<utility>, but a defect report moved them to +<charconv>. This also needs +<system_error>.

        +

        This would require upgrading the minimum gcc version to 11.1 for +floating point conversion support. The minimum Visual Studio version is +already sufficient. The minimum clang version requirement hasn't been +determined yet.

        +

        std::launder()

        +

        It is undecided whether to permit the use of +std::launder() (p0137r1).

        +

        Change to permitted if we discover a place where we need it. Or maybe +we should just permit it, but hope we don't need it.

        +

        Also, C++20 revised the relevant part of Object Lifetime in a way +that seems more permissive and with less need of laundering. We don't +know if implementations of prior versions take advantage of the +difference.

        +

        See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8

        +

        Additional Undecided +Features

        • Trailing return type syntax for functions (n2541)

        • Variable templates (n3651)

        • +href="https://isocpp.org/files/papers/N3651.pdf">n3651, p0127r2)

        • Member initializers and aggregates (n3653)

        • Rvalue references and move semantics

        • +
        • Shorthand for nested namespaces (n4230) — HotSpot makes very little use +of namespaces, so this seemingly innocuous feature probably isn't useful +to us.

        • +
        • Direct list initialization with auto (n3681) — This change fixed some issues +with direct list initialization and auto. But we don't use +that feature much, if at all. And perhaps shouldn't be using +it.

        • +
        • UTF-8 Character Literals (n4267) — Do we have a use-case for +this?

        • +
        • Fold Expressions (n4295) — +Provides a simple way to apply operators to a parameter pack. HotSpot +doesn't use variadic templates very much. That makes it questionable +that developers should need to know about this feature. But if someone +does come up with a good use-case, it's likely that the alternatives are +significantly worse, because pack manipulation without this can be +complicated.

        • +
        • std::invoke<>() (n4169)

        diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 322bdc8458e..e3ba4b470ce 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -377,20 +377,22 @@ adjust new lines horizontally to be consistent with that organization. (E.g., trailing backslashes on long macro definitions often align.) +### Avoid implicit conversions to bool + +* Use `bool` for boolean values. +* Do not use ints or pointers as (implicit) booleans with `&&`, `||`, +`if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or +`if (ptr != nullptr)`, etc. +* Do not use non-boolean declarations in _condition_ forms, i.e. don't use +`if (T v = value) { ... }`. But see +[Enhanced selection statements](#enhanced-selection-statements). + ### Miscellaneous * Use the [Resource Acquisition Is Initialization][RAII] (RAII) design pattern to manage bracketed critical sections. See class `ResourceMark` for an example. -* Avoid implicit conversions to `bool`. - * Use `bool` for boolean values. - * Do not use ints or pointers as (implicit) booleans with `&&`, `||`, - `if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or - `if (ptr != nullptr)`, etc. - * Do not use declarations in _condition_ forms, i.e. don't use - `if (T v = value) { ... }`. - * Use functions from globalDefinitions.hpp and related files when performing bitwise operations on integers. Do not code directly as C operators, unless @@ -402,18 +404,17 @@ they are extremely simple. (Examples: `align_up`, `is_power_of_2`, * Always enumerate all cases in a switch statement or provide a default case. It is ok to have an empty default with comment. - ## Use of C++ Features HotSpot was originally written in a subset of the C++98/03 language. -More recently, support for C++14 is provided, though again, +More recently, support for C++17 is provided, though again, HotSpot only uses a subset. (Backports to JDK versions lacking support for more recent Standards must of course stick with the original C++98/03 subset.) This section describes that subset. Features from the C++98/03 language may be used unless explicitly excluded here. Features from -C++11 and C++14 may be explicitly permitted or explicitly excluded, +C++11, C++14, and C++17 may be explicitly permitted or explicitly excluded, and discussed accordingly here. There is a third category, undecided features, about which HotSpot developers have not yet reached a consensus, or perhaps have not discussed at all. Use of these @@ -428,9 +429,9 @@ more extensive discussion or rationale for limitations. Features that don't have their own subsection are listed in omnibus feature sections for permitted, excluded, and undecided features. -Lists of new features for C++11 and C++14, along with links to their +Lists of new features for C++11, C++14, and C++17, along with links to their descriptions, can be found in the online documentation for some of the -compilers and libraries. The C++14 Standard is the definitive +compilers and libraries. The C++17 Standard is the definitive description. * [C++ Standards Support in GCC](https://gcc.gnu.org/projects/cxx-status.html) @@ -635,13 +636,40 @@ For local variables, this can be used to make the code clearer by eliminating type information that is obvious or irrelevant. Excessive use can make code much harder to understand. +* `auto` for non-type template parameters +([p0127r2](http://wg21.link/p0127r2))
        +`auto` may be used as a placeholder for the type of a non-type template +parameter. The type is deduced from the value provided in a template +instantiation. + * Function return type deduction ([n3638](https://isocpp.org/files/papers/N3638.html))
        Only use if the function body has a very small number of `return` statements, and generally relatively little other code. +* Class template argument deduction +([n3602](http://wg21.link/n3602), [p0091r3](http://wg21.link/p0091r3))
        +The template arguments of a class template may be deduced from the arguments +to a constructor. This is similar to ordinary function argument deduction, +though partial deduction with only _some_ template arguments explicitly +provided is not permitted for class template argument deduction. Deduction +guides may be used to provide additional control over the deduction. As with +`auto` variable declarations, excessive use can make code harder to +understand, because explicit type information is lacking. But it can also +remove the need to be explicit about types that are either obvious, or that +are very hard to write. For example, these allow the addition of a scope-guard +mechanism with nice syntax; something like this +``` + ScopeGuard guard{[&]{ ... cleanup code ... }}; +``` + * Also see [lambda expressions](#lambdaexpressions). +* `decltype(auto)` should be avoided, whether for variables, for non-type +template parameters, or for function return types. There are subtle and +complex differences between this placeholder type and `auto`. Any use would +need very careful explanation. + ### Expression SFINAE [Substitution Failure Is Not An Error][SFINAE] (SFINAE) @@ -663,6 +691,16 @@ Here are a few closely related example bugs:

        +### Non-type template parameter values + +C++17 extended the arguments permitted for non-type template parameters +([n4268](http://wg21.link/n4268)). The kinds of values (the parameter types) +aren't changed. However, the values can now be the result of arbitrary +constant expressions (with a few restrictions on the result), rather than a +much more limited and restrictive set of expressions. In particular, the +argument for a pointer or reference type parameter can now be the result of a +constexpr function. + ### enum Where appropriate, _scoped-enums_ should be used. @@ -781,6 +819,32 @@ ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering. +### Inline Variables + +Variables with static storage duration may be declared `inline` +([p0386r2](https://wg21.link/p0386r2)). This has similar effects as for +declaring a function inline: it can be defined, identically, in multiple +translation units, must be defined in every translation unit in which it is +[ODR used][ODR], and the behavior of the program is as if there is exactly one +variable. + +Declaring a variable inline allows the complete definition to be in a header +file, rather than having a declaration in a header and the definition in a +.cpp file. The guidance on +[initialization](#initializing-variables-with-static-storage-duration) of such +variables still applies. Inline variables with dynamic initializations can +make initialization order problems worse. The few ordering constraints +that exist for non-inline variables don't apply, as there isn't a single +program-designated translation unit containing the definition. + +A `constexpr` static data member is implicitly `inline`. As a consequence, an +[ODR use][ODR] of such a variable doesn't require a definition in some .cpp +file. (This is a change from pre-C++17. Beginning with C++17, such a +definition is considered a duplicate definition, and is deprecated.) + +Declaring a `thread_local` variable `inline` is forbidden for HotSpot code. +[The use of `thread_local`](#thread_local) is already heavily restricted. + ### Initializing variables with static storage duration Variables with static storage duration and _dynamic initialization_ @@ -824,6 +888,53 @@ Some relevant sections from cppreference.com: Although related, the use of `std::initializer_list` remains forbidden, as part of the avoidance of the C++ Standard Library in HotSpot code. +### Mandatory Copy Elision + +[Copy elision](https://en.wikipedia.org/wiki/Copy_elision) +(or [here](https://cn.cppreference.com/w/cpp/language/copy_elision.html)) +is a compiler optimization used to avoid potentially expensive copies in +certain situations. It is critical to making practical the performance of +return by value or pass by value. It is also unusual in not following the +as-if rule for optimizations - copy elision can be applied even if doing so +bypasses side-effects of copying/moving the object. The C++ standard +explicitly permits this. + +However, because it's an optional optimization, the relevant copy/move +constructor must be available and accessible, in case the compiler chooses to +not apply the optimization even in a situation where permitted. + +C++17 changed some cases of copy elision so that there is never a copy/move in +these cases ([p0135r1](http://wg21.link/p0135r1)). The interesting cases +involve a function that returns an unnamed temporary object, and constructors. +In such cases the object being initialized from the temporary is always direct +initialized, with no copy/move ever involved; see [RVO] and more specifically +[URVO]. + +Since this is now standard behavior it can't be avoided in the covered +situations. This could change the behavior of code that relied on side effects +by constructors, but that's both uncommon and was already problematic because +of the previous optional copy elision. But HotSpot code can, and should, +explicitly take advantage of this newly required behavior where it makes sense +to do so. + +For example, it may be beneficial to delay construction of the result of a +function until the return statement, rather than having a local variable that +is modified into the desired state and then returned. (Though [NRVO] may apply +in that case.) + +It is also now possible to define a factory function for a class that is +neither movable nor copyable, if it can be written in a way that makes use of +this feature. + +[RVO]: https://en.wikipedia.org/wiki/Copy_elision#RVO + "Return Value Optimization" + +[NRVO]: https://en.wikipedia.org/wiki/Copy_elision#NRVO + "Named Return Value Optimization" + +[URVO]: https://cn.cppreference.com/w/cpp/language/copy_elision.html + "Unnamed Return Value Optimization" + ### Local Function Objects * Local function objects, including lambda expressions, may be used. @@ -892,6 +1003,12 @@ Another use for local functions is [partial application][PARTIALAPP]. Again here, lambdas are typically much simpler and less verbose than function object classes. +A lambda is a constexpr function if either the parameter declaration clause is +followed by `constexpr`, or it satisfies the requirements for a constexpr +function ([p0170r1]). Thus, using a lambda to package up some computation +doesn't incur unnecessary overhead or prevent use in a context required to be +compile-time evaluated (such as an array size). + Because of these benefits, lambda expressions are permitted in HotSpot code, with some restrictions and usage guidance. An anonymous lambda is one which is passed directly as an argument. A named lambda is the value of a @@ -943,6 +1060,17 @@ the most part they don't apply to HotSpot code, given other usage restrictions. applies to captured auto variables, not member variables, and is inconsistent with referential transparency. +* By-value capture of `this` (using a capture list like `[*this]` ([p0018r3])) +is also not permitted. One of the motivating use-cases is when the lifetime of +the lambda exceeds the lifetime of the object for the containing member +function. That is, we have an upward lambda that is capturing `this` of the +enclosing method. But again, that use-case doesn't apply if only downward +lambdas are used. + Another use-case is when we simply want the lambda to be operating on a copy +of `this` for some reason. This is sufficiently uncommon that it can be +handled by manual copying, so readers don't need to understand this rare +syntax. + * Non-capturing lambdas (with an empty capture list - `[]`) have limited utility. There are cases where no captures are required (pure functions, for example), but if the function is small and simple then that's obvious @@ -952,7 +1080,7 @@ anyway. Capture initializers inherently increase the complexity of the capture list, and provide little benefit over an additional in-scope local variable. -The use of `mutable` lambda expressions is forbidden because there don't +* The use of `mutable` lambda expressions is forbidden because there don't seem to be many, if any, good use-cases for them in HotSpot. A lambda expression needs to be mutable in order to modify a by-value captured value. But with only downward lambdas, such usage seems likely to be rare and @@ -1099,21 +1227,12 @@ Do not use _inheriting constructors_ C++11 provides simple syntax allowing a class to inherit the constructors of a base class. Unfortunately there are a number of problems with the original specification, and C++17 contains significant revisions ([p0136r1] opens with -a list of 8 Core Issues). Since HotSpot doesn't support use of C++17, use of -inherited constructors could run into those problems. Such uses might also -change behavior in a future HotSpot update to use C++17 or later, potentially -in subtle ways that could lead to hard to diagnose problems. Because of this, -HotSpot code must not use inherited constructors. +a list of 8 Core Issues). Although those issues have been addressed, the +benefits from this feature are small compared to the complexity. Because of +this, HotSpot code must not use inherited constructors. -Note that gcc7 provides the `-fnew-inheriting-ctors` option to use the -[p0136r1] semantics. This is enabled by default when using C++17 or later. -It is also enabled by default for `fabi-version=11` (introduced by gcc7) or -higher when using C++11/14, as the change is considered a Defect Report that -applies to those versions. Earlier versions of gcc don't have that option, -and other supported compilers may not have anything similar. - -[p0136r1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html - "p0136r1" +[p0136r1]: http:/wg21.link/p0136r1 "p0136r1" +[p0195r0](http://wg21.link/p0195r0) ### Attributes @@ -1132,15 +1251,39 @@ preferred location. function's declaration, rather than between the function name and the parameter list. +[p0068r0](http://wg21.link/p0068r0) is the initial proposal for the attributes +added by C++17.) + Only the following attributes are permitted: * `[[noreturn]]` +* `[[nodiscard]]` ([p0189r1](http://wg21.link/p0189r1)) +* `[[maybe_unused]]` ([p0212r1](http://wg21.link/p0212r1)) +* `[[fallthrough]]` ([p0188r1](http://wg21.link/p0188)) The following attributes are expressly forbidden: * `[[carries_dependency]]` - Related to `memory_order_consume`. * `[[deprecated]]` - Not relevant in HotSpot code. +Direct use of non-standard (and presumably scoped) attributes in shared code +is also forbidden. Using such would depend on the C++17 feature that an +attribute not recognized by the implementation is ignored +([p0283r2](http://wg21.link/p0283r2)). If such an attribute is needed in +shared code, the well-established technique of providing an `ATTRIBUTE_XXX` +macro with per-compiler definitions (sometimes empty) should be +used. Compilers may warn about unrecognized attributes (whether by name or by +location), in order to report typos or misuse. Disabling such warnings +globally would not be desirable. + +The use of `using` directives in attribute lists is also forbidden. +([p0028r0](http://wg21.link/p0028r0)) +([p0028r4](http://wg21.link/p0028r4)) +We don't generally use scoped attributes in attribute lists with other +attributes. Rather, uses of scoped attributes (which are implementation +defined) are generally hidden behind a portability macro that includes the +surrounding brackets. + ### noexcept Use of `noexcept` exception specifications @@ -1189,9 +1332,79 @@ HotSpot code can assume no exceptions will ever be thrown, even from functions not declared `noexcept`. So HotSpot code doesn't ever need to check, either with conditional exception specifications or with `noexcept` expressions. +The exception specification is part of the type of a function +([p0012r1](http://wg21.link/p0012r1). This likely has little impact on HotSpot +code, since the use of `noexcept` is expected to be rare. + Dynamic exception specifications were deprecated in C++11. C++17 removed all but `throw()`, with that remaining a deprecated equivalent to `noexcept`. +### Enhanced selection statements + +C++17 modified the _condition_ part of `if` and `switch` statements, permitting +an _init-statement_ to be included +([p0305r1](http://wg21.link/p0305r1)). + +Use of this feature is permitted. (However, complex uses may interfere with +readability.) Limiting the scope of a variable involved in the condition, +while also making the value available to the statement's body, can improve +readability. The alternative method of scope-limiting by introducing a nested +scope isn't very popular and is rarely used. + +This new syntax is in addition to the _condition_ being a declaration with a +_brace-or-equal-initializer_. For an `if` statement this new sytax gains that +benefit without violating the long-standing guidance against using +[implicit conversions to `bool`](#avoid-implicit-conversions-to-bool), +which still stands. + +For example, uses of Unified Logging sometimes explicitly check whether a +`LogTarget` is enabled. Instead of +``` + LogTarget(...) lt; + if (lt.is_enabled()) { + LogStream log(lt); + ... use log ... + } + ... lt is accessible but probably not needed here ... +``` +using this feature one could write +``` + if (LogTarget(...) lt; lt.is_enabled()) { + LogStream log(lt); + ... use log ... + } +``` + +C++17 also added compile-time `if` statements +([p0292r2](http://wg21.link/p0292r2)). Use of `if constexpr` is +permitted. This feature can replace and (sometimes vastly) simplify many uses +of [SFINAE]. The same declaration and initialization guidance for the +_condition_ part apply here as for ordinary `if` statements. + +### Expression Evaluation Order + +C++17 tightened up the evaluation order for some kinds of subexpressions +([p0138r2](http://wg21.link/p0138r2)). Note, however, that the Alternate +Evaluation Order for Function Calls alternative in that paper was adopted, +rather than the strict left to right order of evaluation for function call +arguments that was proposed in the main body of the paper. + +The primary purpose of this change seems to be to make certain kinds of call +chaining well defined. That's not a style widely used in HotSpot. In general +it is better to continue to avoid questions in this area by isolating +operations with side effects from other statements. In particular, continue to +avoid modifying a value in an expression where it is also used. + +### Compatibility with C11 + +C++17 refers to C11 rather than C99. This means that C11 libraries and +functions may be used in HotSpot. There may be limitations because of +differing levels of compatibility among various compilers and versions of +those compilers. + +Note that the C parts of the JDK have been built with C11 selected for some +time ([JDK-8292008](https://bugs.openjdk.org/browse/JDK-8292008)). + ### Additional Permitted Features * `alignof` @@ -1209,7 +1422,10 @@ but `throw()`, with that remaining a deprecated equivalent to `noexcept`. ([n2555](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf)) * Static assertions -([n1720](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html)) +([n1720](http://wg21.link/n1720)) +([n3928](http://wg21.link/n3928))
        +Both the original (C++11) two-argument form and the new (C++17) +single-argument form are permitted. * `decltype` ([n2343](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf)) @@ -1256,7 +1472,72 @@ but `throw()`, with that remaining a deprecated equivalent to `noexcept`. * Unrestricted Unions ([n2544](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf)) -### Excluded Features +* Preprocessor Condition `__has_include` +([p0061r0](http://wg21.link/p0061r0)) +([p0061r1](http://wg21.link/p0061r1)) + +* Hexadecimal Floating-Point Literals +([p0245r1](http://wg21.link/p0245r1)) + +* Construction Rules for `enum class` Values +([p0138r2](http://wg21.link/p0138r2)) + +* Allow `typename` in template template parameter +([n4051](http://wg21.link/n4051)) — template template parameters are +barely used (if at all) in HotSpot, but there's no reason to artificially +disallow this syntactic regularization in any such uses. + +## Excluded Features + +### Structured Bindings + +The use of structured bindings [p0217r3](http://wg21.link/p0217r3) is +forbidden. Preferred approaches for handling functions with multiple return +values include + +* Return a named class/struct intended for that purpose, with named and typed +members/accessors. + +* Return a value along with out parameters (usually pointers, sometimes +references). + +* Designate a sentinel "failure" value in the normal return value type, with +some out of band location for additional information. For example, this is +the model typically used with `errno`, where a function returns a normal +result, or -1 to indicate an error, with additional error information in +`errno`. + +There is a strong preference for names and explicit types, as opposed to +offsets and implicit types. For example, there are folks who strongly dislike +that some of the Standard Library functions return `std::pair` because `first` +and `second` members don't carry any useful information. + +### File System Library + +The use of the File System library is forbidden. HotSpot doesn't do very much +with files, and already has adequate mechanisms for its needs. Rewriting in +terms of this new library doesn't provide any obviously significant +benefits. Having a mix of the existing usage and uses of this new library +would be confusing. + +[n4100](http://wg21.link/n4100) +[p0218r0](http://wg21.link/p0218r0) +[p0219r1](http://wg21.link/p0219r1) +[p0317r1](http://wg21.link/p0317r1) +[p0392r0](http://wg21.link/p0392r0) +[p0430r2](http://wg21.link/p0430r2) +[p0492r2](http://wg21.link/p0492r2) +[p1164r1](http://wg21.link/p1164r1) + +### Aggregate Extensions + +Aggregates with base classes are forbidden. C++17 allows aggregate +initialization for classes with base classes +([p0017r1](https://wg21.link/p0017r1)). HotSpot makes very little use of +aggregate classes, preferring explicit constructors even for very simple +classes. + +### Additional Excluded Features * New string and character literals * New character types @@ -1292,27 +1573,281 @@ operator overloading is used, ensure the semantics conform to the normal expected behavior of the operation. * Avoid most implicit conversion constructors and (implicit or explicit) -conversion operators. (Note that conversion to `bool` isn't needed -in HotSpot code because of the "no implicit boolean" guideline.) +conversion operators. Conversion to `bool` operators aren't needed +because of the +[no implicit boolean](#avoid-implicit-conversions-to-bool) +guideline.) * Avoid `goto` statements. -### Undecided Features +* Attributes for namespaces and enumerators +([n4266](http://wg21.link/n4266) — +The only applicable attribute is [`[[deprecated]]`](#attributes), which is +forbidden. + +* Variadic `using` declarations +([p0195r2](http://wg21.link/p0195r2)) + +* `std::variant<>` +([p0088r3](http://wg21.link/p0088r3)) — +Even if more of the C++ Standard Library is permitted, this class will remain +forbidded. Invalid accesses are indicated by throwing exceptions. + +* `std::any` +([p0220r1](http://wg21.link/p0220r1)) — +Even if more of the C++ Standard Library is permitted, this class will remain +forbidden. It may require allocation, and always uses the standard +allocator. It requires [RTTI]. + +* `std::as_const()` +([p0007r1](http://wg21.link/p0007r1)) — +If sufficiently useful, HotSpot could add such a function. It would likely be +added to globalDefinitions.hpp, where there are already some similar small +utilities. + +* `std::clamp()` +([p002501](http://wg21.link/p002501)) — +This function is already provided in globalDefinitions.hpp. + +* Parallel STL Algorithms +([p0024r2](http://wg21.link/p0024r2)) — +Even if more of the C++ Standard Library is permitted, these will remain +forbidden. They are built on the standard C++ threading mechanisms. HotSpot +doesn't use those mechanisms, instead providing and using its own. + +* Cache Line Sizes +[p0154r1](http://wg21.link/p0154r1) — +HotSpot has its own mechanisms for this, using values like +`DEFAULT_CACHE_LINE_SIZE`. The platform-specific implementation of the HotSpot +mechanisms might use these library functions, but there is no reason to move +away from the current approach. Quoting from [JOSUTTIS]: "... if you know better, +use specific values, but using these values is better than any assumed fixed +size for code supporting multiple platforms." + +* `register` storage class removal +[p0001r1](http://wg21.link/p0001r1) — +The `register` storage class has been removed. `register` is still a keyword, +so still can't be used for normal purposes. Also, this doesn't affect the use +of `register` for gcc-style extended asm code; that's a different syntactic +element with a different meaning. + +* Value of `__cplusplus` — +Testing whether `__cplusplus` is defined or not is permitted, and indeed +required. But the value should not need to be examined. The value is changed +with each revision of the Standard. But we build HotSpot and (most of) the +rest of the JDK with a specifically selected version of the Standard. The +value of `__cplusplus` should be known and unchanging until we change the +project's build configuration again. So examining the value shouldn't ever be +necessary. + +* Removal of `++` for `bool` +([p0003r1](http://wg21.link/p0003r1)) + +* Removal of trigraphs +([n4086](http://wg21.link/n4086)) + +## Undecided Features This list is incomplete; it serves to explicitly call out some features that have not yet been discussed. +Some features are undecided (so implicitly forbidden) because we don't expect +to use them at all. This might be reconsidered if someone finds a good use +case. + +Some Standard Library features are undecided (so implicitly forbidden) +because, while this Style Guide forbids the use of such, they may be +sufficiently useful that we want to permit them anyway. Doing so may require +some idiomatic mechanism for addressing things like `assert` incompatibility, +incompatibility with HotSpot's `FORBID_C_FUNCTION` mechanism, and the like. + +### std::optional<> + +It is undecided whether to permit the use of `std::optional<>` +([p0220r1](http://wg21.link/p0220r1)). It may be sufficiently useful that it +should be permitted despite the usual prohibition against using Standard +Library facilities. Use of the `value()` member function must be forbidden, as +it reports an invalid access by throwing an exception. + +### std::byte + +It is undecided whether to permit the use of the `std::byte` type +([p0298r3](http://wg21.link/p0298r3)). It may be sufficiently useful that it +should be permitted despite the usual prohibition against using Standard +Library facilities. + +It has been suggested that changing the HotSpot `address` type to use +`std::byte` has some benefits. That is, replace +``` +typedef u_char* address; +typedef const u_char* const_address; +``` +``` +using address = std::byte*; +using const_address = const std::byte*; +``` +in globalDefinitions.hpp. + +A specific benefit that was mentioned is that it might improve the horrible +way that gdb handles our current definition of the `address` type. +``` +#include + +typedef unsigned char* address; +typedef std::byte* address_b; + +int main() { + + char* mem; + + address addr = (address)mem; + address_b addr_b = (address_b)mem; + + return 0; +} +``` + +``` +(gdb) p addr +$1 = (address) 0x7ffff7fe4fa0 "\363\017\036\372Uf\017\357\300H\211\345AWI\211\377AVAUATSH\201\354\210\002" +(gdb) p addr_b +$2 = (address_b) 0x7ffff7fe4fa0 +``` + +This needs to be explored. Some folks have said they will do so. + +### String Views + +It is undecided whether to permit the use of `std::string_view` +([p0220r1](http://wg21.link/p0220r1)). + +HotSpot doesn't use `std::string`, but uses `char*` strings a lot. Wrapping +such in a `std::string_view` to enable the use of various algorithms could be +useful. But since HotSpot also doesn't permit use of `` and the +like, that only gets the limited set of algorithms provided by the view class +directly. + +There is also the issue of `NUL` termination; string views are not necessarily +`NUL` terminated. Moreover, if one goes to the work of making one that is +`NUL` terminated, that terminator is included in the size. + +There are other caveats. Permitting use of string views would require +discussion of those. + +### Substring and Subsequence Searching + +In addition to simple substring searching, the Standard Library now includes +Boyer-Moore and Boyer-Moore-Horspool searchers, in case someone wants to +search really large texts. That seems an unlikely use-case for HotSpot. See +[p0220r1](http://wg21.link/p0220r1). + +### `new` and `delete` with Over-Aligned Data + +It is undecided whether to permit the use of dynamic allocation of overaligned +types ([n3396](http://wg21.link/n3396)). + +HotSpot currently only has a couple of over-aligned types that are dynamically +allocated. These are handled manually, not going through `new` expressions, as +that couldn't work before C++17. + +One of the ways an over-aligned type might arise is by aligning a data member. +This might be done to avoid destructive interference for concurrent accesses. +But HotSpot uses a different approach, using explicit padding. Again, this is +in part because `new` and `delete` of overaligned types didn't work. But we +might prefer to continue this approach. + +We would need to add `operator new` overloads to `CHeapObj<>` and possibly in +other places in order to support this. However, it has been suggested that +implementing it (efficiently) on top of NMT might be difficult. Note that +`posix_memalign` / `_aligned_malloc` don't help here, because of NMT's use of +malloc headers. + +If we don't support it we may want to add `operator new` overloads that are +deleted, to prevent attempted uses. + +Alignment usage in non-HotSpot parts of the OpenJDK: + +* `alignas` used once in harfbuzz, to align a variable. + +* libpipewire has `#define SPA_ALIGNED` macro using gcc `aligned` attribute, +but doesn't use it. + +* libsleef has `#define ALIGNED` macro using gcc `aligned` attribute. It is +not used for class or member declarations. + +### `std::to_chars()` and `std::from_chars` + +It is undecided whether to permit the use of `std::to_chars()` and +`std::from_chars()` ([p0067r5](http://wg21.link/p0067r5)). + +These functions provide low-level conversions between character sequences and +numeric values. This seems like a good candidate for use in HotSpot, +potentially replacing various clumsy or less performant alternatives. There is +no memory allocation. Parsing failures are indicated via error codes rather +than exceptions. Various other nice for HotSpot properties. + +Note that the published C++17 Standard puts these in ``, but a defect +report moved them to ``. This also needs ``. + +This would require upgrading the minimum gcc version to 11.1 for floating +point conversion support. The minimum Visual Studio version is already +sufficient. The minimum clang version requirement hasn't been determined yet. + +### `std::launder()` + +It is undecided whether to permit the use of `std::launder()` +([p0137r1](http://wg21.link/p0137r1)). + +Change to permitted if we discover a place where we need it. Or maybe we +should just permit it, but hope we don't need it. + +Also, C++20 revised the relevant part of Object Lifetime in a way that seems +more permissive and with less need of laundering. We don't know if +implementations of prior versions take advantage of the difference. + +See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8 + +### Additional Undecided Features + * Trailing return type syntax for functions ([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)) * Variable templates -([n3651](https://isocpp.org/files/papers/N3651.pdf)) +([n3651](https://isocpp.org/files/papers/N3651.pdf), +[p0127r2](http://wg21.link/p0127r2)) * Member initializers and aggregates ([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html)) * Rvalue references and move semantics +* Shorthand for nested namespaces +([n4230](http://wg21.link/n4230)) — +HotSpot makes very little use of namespaces, so this seemingly innocuous +feature probably isn't useful to us. + +* Direct list initialization with `auto` +([n3681](http://wg21.link/n3681)) — +This change fixed some issues with direct list initialization and `auto`. But +we don't use that feature much, if at all. And perhaps shouldn't be using it. + +* UTF-8 Character Literals +([n4267](http://wg21.link/n4267)) — +Do we have a use-case for this? + +* Fold Expressions +([n4295](http://wg21.link/n4295)) — +Provides a simple way to apply operators to a parameter pack. HotSpot doesn't +use variadic templates very much. That makes it questionable that developers +should need to know about this feature. But if someone does come up with a +good use-case, it's likely that the alternatives are significantly worse, +because pack manipulation without this can be complicated. + +* `std::invoke<>()` +([n4169](http://wg21.link/n4169)) + + + [ADL]: https://en.cppreference.com/w/cpp/language/adl "Argument Dependent Lookup" @@ -1330,3 +1865,6 @@ features that have not yet been discussed. [PARTIALAPP]: https://en.wikipedia.org/wiki/Partial_application "Partial Application" + +[JOSUTTIS]: https://www.cppstd17.com + "C++17: The Complete Guide" diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 3a61840e8c9..6072cbc74dd 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -597,11 +597,11 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], # CXXFLAGS C++ language level for all of JDK, including Hotspot. if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then - LANGSTD_CXXFLAGS="-std=c++14" + LANGSTD_CXXFLAGS="-std=c++17" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - LANGSTD_CXXFLAGS="-std:c++14" + LANGSTD_CXXFLAGS="-std:c++17" else - AC_MSG_ERROR([Cannot enable C++14 for this toolchain]) + AC_MSG_ERROR([Cannot enable C++17 for this toolchain]) fi TOOLCHAIN_CFLAGS_JDK_CXXONLY="$TOOLCHAIN_CFLAGS_JDK_CXXONLY $LANGSTD_CXXFLAGS" TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM $LANGSTD_CXXFLAGS" diff --git a/make/ide/vscode/hotspot/indexers/ccls-settings.txt b/make/ide/vscode/hotspot/indexers/ccls-settings.txt index bacc49c6112..fed586e5488 100644 --- a/make/ide/vscode/hotspot/indexers/ccls-settings.txt +++ b/make/ide/vscode/hotspot/indexers/ccls-settings.txt @@ -1,7 +1,7 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", // Configure ccls diff --git a/make/ide/vscode/hotspot/indexers/clangd-settings.txt b/make/ide/vscode/hotspot/indexers/clangd-settings.txt index 2a5b5e4a8cb..795229bb870 100644 --- a/make/ide/vscode/hotspot/indexers/clangd-settings.txt +++ b/make/ide/vscode/hotspot/indexers/clangd-settings.txt @@ -1,7 +1,7 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", // Configure clangd diff --git a/make/ide/vscode/hotspot/indexers/cpptools-settings.txt b/make/ide/vscode/hotspot/indexers/cpptools-settings.txt index ec266fa79c3..53bfe7889e2 100644 --- a/make/ide/vscode/hotspot/indexers/cpptools-settings.txt +++ b/make/ide/vscode/hotspot/indexers/cpptools-settings.txt @@ -1,5 +1,5 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", diff --git a/make/ide/vscode/hotspot/indexers/rtags-settings.txt b/make/ide/vscode/hotspot/indexers/rtags-settings.txt index 75727ae17f1..be417bfeeab 100644 --- a/make/ide/vscode/hotspot/indexers/rtags-settings.txt +++ b/make/ide/vscode/hotspot/indexers/rtags-settings.txt @@ -1,7 +1,7 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", // Configure RTags From cdc8b5eb83ed6335a65b93cfa0cf38932486c7e3 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 5 Sep 2025 21:08:29 +0000 Subject: [PATCH 160/295] 8366455: Move VarHandles.GuardMethodGenerator to execute on build Reviewed-by: psandoz, redestad, erikj --- make/ToolsJdk.gmk | 3 + .../VarHandleGuardMethodGenerator.java | 325 ++++ .../java.base/gensrc/GensrcVarHandles.gmk | 12 + .../java/lang/invoke/VarHandleGuards.java | 1619 ----------------- .../classes/java/lang/invoke/VarHandles.java | 238 --- 5 files changed, 340 insertions(+), 1857 deletions(-) create mode 100644 make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java delete mode 100644 src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index a7a2289f78a..629cadbf83a 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -130,6 +130,9 @@ TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_clas TOOL_FIXUPPANDOC = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.fixuppandoc.Main +TOOL_VARHANDLEGUARDMETHODGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + build.tools.methodhandle.VarHandleGuardMethodGenerator + ################################################################################ # Executable javascript filter for man page generation using pandoc. diff --git a/make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java b/make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java new file mode 100644 index 00000000000..4cb833dffe2 --- /dev/null +++ b/make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 build.tools.methodhandle; + +import java.io.PrintWriter; +import java.lang.classfile.TypeKind; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * A helper program to generate the VarHandleGuards class with a set of + * static guard methods each of which corresponds to a particular shape and + * performs a type check of the symbolic type descriptor with the VarHandle + * type descriptor before linking/invoking to the underlying operation as + * characterized by the operation member name on the VarForm of the + * VarHandle. + *

        + * The generated class essentially encapsulates pre-compiled LambdaForms, + * one for each method, for the most common set of method signatures. + * This reduces static initialization costs, footprint costs, and circular + * dependencies that may arise if a class is generated per LambdaForm. + *

        + * A maximum of L*T*S methods will be generated where L is the number of + * access modes kinds (or unique operation signatures) and T is the number + * of variable types and S is the number of shapes (such as instance field, + * static field, or array access). + * If there are 4 unique operation signatures, 5 basic types (Object, int, + * long, float, double), and 3 shapes then a maximum of 60 methods will be + * generated. However, the number is likely to be less since there may + * be duplicate signatures. + *

        + * Each method is annotated with @LambdaForm.Compiled to inform the runtime + * that such methods should be treated as if a method of a class that is the + * result of compiling a LambdaForm. Annotation of such methods is + * important for correct evaluation of certain assertions and method return + * type profiling in HotSpot. + * + * @see java.lang.invoke.GenerateJLIClassesHelper + */ +public final class VarHandleGuardMethodGenerator { + + static final String CLASS_HEADER = """ + /* + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package java.lang.invoke; + + import jdk.internal.vm.annotation.AOTSafeClassInitializer; + import jdk.internal.vm.annotation.ForceInline; + import jdk.internal.vm.annotation.Hidden; + + // This file is generated by build.tools.methodhandle.VarHandleGuardMethodGenerator. + // Do not edit! + @AOTSafeClassInitializer + final class VarHandleGuards { + """; + + static final String GUARD_METHOD_SIG_TEMPLATE = " _()"; + + static final String GUARD_METHOD_TEMPLATE = + """ + @ForceInline + @LambdaForm.Compiled + @Hidden + static final throws Throwable { + boolean direct = handle.checkAccessModeThenIsDirect(ad); + if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + MethodHandle.linkToStatic(); + } else { + MethodHandle mh = handle.getMethodHandle(ad.mode); + mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); + } + }"""; + + static final String GUARD_METHOD_TEMPLATE_V = + """ + @ForceInline + @LambdaForm.Compiled + @Hidden + static final throws Throwable { + boolean direct = handle.checkAccessModeThenIsDirect(ad); + if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + MethodHandle.linkToStatic(); + } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + MethodHandle.linkToStatic(); + } else { + MethodHandle mh = handle.getMethodHandle(ad.mode); + mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); + } + }"""; + + // A template for deriving the operations + // could be supported by annotating VarHandle directly with the + // operation kind and shape + interface VarHandleTemplate { + Object get(); + + void set(Object value); + + boolean compareAndSet(Object actualValue, Object expectedValue); + + Object compareAndExchange(Object actualValue, Object expectedValue); + + Object getAndUpdate(Object value); + } + + record HandleType(Class receiver, Class... intermediates) { + } + + public static void main(String... args) throws Throwable { + if (args.length != 1) { + System.err.println("Usage: java VarHandleGuardMethodGenerator VarHandleGuards.java"); + System.exit(1); + } + + Path outputFile = Path.of(args[0]); + + try (PrintWriter pw = new PrintWriter(Files.newBufferedWriter( + outputFile, + StandardCharsets.UTF_8, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING))) { + print(pw); + } + } + + public static void print(PrintWriter pw) { + pw.println(CLASS_HEADER); + + // Declare the stream of shapes + List hts = List.of( + // Object->T + new HandleType(Object.class), + + // ->T + new HandleType(null), + + // Array[index]->T + new HandleType(Object.class, int.class), + + // MS[base]->T + new HandleType(Object.class, long.class), + + // MS[base][offset]->T + new HandleType(Object.class, long.class, long.class) + ); + + // The 5 JVM calling convention types + List> basicTypes = List.of(Object.class, int.class, long.class, float.class, double.class); + + Stream.of(VarHandleTemplate.class.getMethods()). + mapMulti((m, sink) -> { + for (var ht : hts) { + for (var bt : basicTypes) { + sink.accept(generateMethodType(m, ht.receiver, bt, ht.intermediates)); + } + } + }). + distinct(). + map(VarHandleGuardMethodGenerator::generateMethod). + forEach(pw::println); + + pw.println("}"); + } + + static MethodType generateMethodType(Method m, Class receiver, Class value, Class... intermediates) { + Class returnType = m.getReturnType() == Object.class + ? value : m.getReturnType(); + + List> params = new ArrayList<>(); + if (receiver != null) + params.add(receiver); + Collections.addAll(params, intermediates); + for (var p : m.getParameters()) { + params.add(value); + } + return MethodType.methodType(returnType, params); + } + + static String generateMethod(MethodType mt) { + Class returnType = mt.returnType(); + + var params = new LinkedHashMap(); + params.put("handle", className(VarHandle.class)); + for (int i = 0; i < mt.parameterCount(); i++) { + params.put("arg" + i, className(mt.parameterType(i))); + } + params.put("ad", "VarHandle.AccessDescriptor"); + + // Generate method signature line + String RETURN = className(returnType); + String NAME = "guard"; + String SIGNATURE = getSignature(mt); + String PARAMS = params.entrySet().stream(). + map(e -> e.getValue() + " " + e.getKey()). + collect(Collectors.joining(", ")); + String METHOD = GUARD_METHOD_SIG_TEMPLATE. + replace("", RETURN). + replace("", NAME). + replace("", SIGNATURE). + replace("", PARAMS); + + // Generate method + params.remove("ad"); + + List LINK_TO_STATIC_ARGS = new ArrayList<>(params.keySet()); + LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)"); + + List LINK_TO_INVOKER_ARGS = new ArrayList<>(params.keySet()); + LINK_TO_INVOKER_ARGS.set(0, LINK_TO_INVOKER_ARGS.get(0) + ".asDirect()"); + + RETURN = returnType == void.class + ? "" + : returnType == Object.class + ? "return " + : "return (" + returnType.getName() + ") "; + + String RESULT_ERASED = returnType == void.class + ? "" + : returnType != Object.class + ? "return (" + returnType.getName() + ") " + : "Object r = "; + + String RETURN_ERASED = returnType != Object.class + ? "" + : "\n return ad.returnType.cast(r);"; + + String template = returnType == void.class + ? GUARD_METHOD_TEMPLATE_V + : GUARD_METHOD_TEMPLATE; + return template. + replace("", METHOD). + replace("", NAME). + replaceAll("", RETURN). + replace("", RESULT_ERASED). + replace("", RETURN_ERASED). + replaceAll("", String.join(", ", LINK_TO_STATIC_ARGS)). + replace("", String.join(", ", LINK_TO_INVOKER_ARGS)) + .indent(4); + } + + static String className(Class c) { + String n = c.getCanonicalName(); + if (n == null) + throw new IllegalArgumentException("Not representable in source code: " + c); + if (!c.isPrimitive() && c.getPackageName().equals("java.lang")) { + n = n.substring("java.lang.".length()); + } else if (c.getPackageName().equals("java.lang.invoke")) { + n = n.substring("java.lang.invoke.".length()); + } + return n; + } + + static String getSignature(MethodType m) { + StringBuilder sb = new StringBuilder(m.parameterCount() + 1); + + for (int i = 0; i < m.parameterCount(); i++) { + Class pt = m.parameterType(i); + sb.append(getCharType(pt)); + } + + sb.append('_').append(getCharType(m.returnType())); + + return sb.toString(); + } + + static char getCharType(Class pt) { + return TypeKind.from(pt).upperBound().descriptorString().charAt(0); + } +} diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index 899f827462c..ec1aec5c764 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -302,5 +302,17 @@ TARGETS += $(GENSRC_VARHANDLES) ################################################################################ +GENSRC_VARHANDLEGUARDS := $(VARHANDLES_GENSRC_DIR)/VarHandleGuards.java + +$(GENSRC_VARHANDLEGUARDS): $(BUILD_TOOLS_JDK) + $(call LogInfo, Generating $@) + $(call MakeTargetDir) + $(TOOL_VARHANDLEGUARDMETHODGENERATOR) \ + $(GENSRC_VARHANDLEGUARDS) + +TARGETS += $(GENSRC_VARHANDLEGUARDS) + +################################################################################ + endif # include guard include MakeIncludeEnd.gmk diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java b/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java deleted file mode 100644 index 49408a22cef..00000000000 --- a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java +++ /dev/null @@ -1,1619 +0,0 @@ -/* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.lang.invoke; - -import jdk.internal.vm.annotation.AOTSafeClassInitializer; -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Hidden; - -// This class is auto-generated by java.lang.invoke.VarHandles$GuardMethodGenerator. Do not edit. -@AOTSafeClassInitializer -final class VarHandleGuards { - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_L_L(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_L_I(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_L_J(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_L_F(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_L_D(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard__L(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard__I(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard__J(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard__F(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard__D(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LI_L(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LI_I(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LI_J(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LI_F(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LI_D(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJ_L(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJ_I(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJ_J(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJ_F(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJ_D(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJJ_L(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJJ_I(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJJ_F(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJJ_D(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LL_V(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LI_V(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJ_V(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LF_V(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LD_V(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_L_V(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_I_V(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_J_V(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_F_V(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_D_V(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LIL_V(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LII_V(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LIJ_V(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LIF_V(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LID_V(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJL_V(VarHandle handle, Object arg0, long arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJI_V(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJ_V(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJF_V(VarHandle handle, Object arg0, long arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJD_V(VarHandle handle, Object arg0, long arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJL_V(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJI_V(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJJ_V(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJF_V(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJD_V(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LLL_Z(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LII_Z(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LFF_Z(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LDD_Z(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LL_Z(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_II_Z(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_JJ_Z(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_FF_Z(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_DD_Z(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LILL_Z(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIII_Z(VarHandle handle, Object arg0, int arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIJJ_Z(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIFF_Z(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIDD_Z(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJLL_Z(VarHandle handle, Object arg0, long arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJII_Z(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJFF_Z(VarHandle handle, Object arg0, long arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJDD_Z(VarHandle handle, Object arg0, long arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJLL_Z(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, Object arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJII_Z(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, int arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, long arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJFF_Z(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, float arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJDD_Z(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, double arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LLL_L(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LII_I(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LFF_F(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LDD_D(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LL_L(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_II_I(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_JJ_J(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_FF_F(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_DD_D(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LILL_L(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LIII_I(VarHandle handle, Object arg0, int arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LIJJ_J(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LIFF_F(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LIDD_D(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJLL_L(VarHandle handle, Object arg0, long arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJII_I(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJFF_F(VarHandle handle, Object arg0, long arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJDD_D(VarHandle handle, Object arg0, long arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJJLL_L(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, Object arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJJII_I(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, int arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJJJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, long arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJJFF_F(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, float arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJJDD_D(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, double arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LF_F(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LD_D(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_I_I(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_J_J(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_F_F(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_D_D(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LIL_L(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LIJ_J(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LIF_F(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LID_D(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJL_L(VarHandle handle, Object arg0, long arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJI_I(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJF_F(VarHandle handle, Object arg0, long arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJD_D(VarHandle handle, Object arg0, long arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJJL_L(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJJI_I(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJJF_F(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJJD_D(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - -} diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index 571587ab42f..c97d44ba5d3 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -657,242 +657,4 @@ final class VarHandles { !RuntimeException.class.isAssignableFrom(clazz) && !Error.class.isAssignableFrom(clazz); } - -// /** -// * A helper program to generate the VarHandleGuards class with a set of -// * static guard methods each of which corresponds to a particular shape and -// * performs a type check of the symbolic type descriptor with the VarHandle -// * type descriptor before linking/invoking to the underlying operation as -// * characterized by the operation member name on the VarForm of the -// * VarHandle. -// *

        -// * The generated class essentially encapsulates pre-compiled LambdaForms, -// * one for each method, for the most set of common method signatures. -// * This reduces static initialization costs, footprint costs, and circular -// * dependencies that may arise if a class is generated per LambdaForm. -// *

        -// * A maximum of L*T*S methods will be generated where L is the number of -// * access modes kinds (or unique operation signatures) and T is the number -// * of variable types and S is the number of shapes (such as instance field, -// * static field, or array access). -// * If there are 4 unique operation signatures, 5 basic types (Object, int, -// * long, float, double), and 3 shapes then a maximum of 60 methods will be -// * generated. However, the number is likely to be less since there -// * be duplicate signatures. -// *

        -// * Each method is annotated with @LambdaForm.Compiled to inform the runtime -// * that such methods should be treated as if a method of a class that is the -// * result of compiling a LambdaForm. Annotation of such methods is -// * important for correct evaluation of certain assertions and method return -// * type profiling in HotSpot. -// */ -// public static class GuardMethodGenerator { -// -// static final String GUARD_METHOD_SIG_TEMPLATE = " _()"; -// -// static final String GUARD_METHOD_TEMPLATE = -// """ -// @ForceInline -// @LambdaForm.Compiled -// @Hidden -// static final throws Throwable { -// boolean direct = handle.checkAccessModeThenIsDirect(ad); -// if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { -// MethodHandle.linkToStatic(); -// } else { -// MethodHandle mh = handle.getMethodHandle(ad.mode); -// mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); -// } -// }"""; -// -// static final String GUARD_METHOD_TEMPLATE_V = -// """ -// @ForceInline -// @LambdaForm.Compiled -// @Hidden -// static final throws Throwable { -// boolean direct = handle.checkAccessModeThenIsDirect(ad); -// if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { -// MethodHandle.linkToStatic(); -// } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { -// MethodHandle.linkToStatic(); -// } else { -// MethodHandle mh = handle.getMethodHandle(ad.mode); -// mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); -// } -// }"""; -// -// // A template for deriving the operations -// // could be supported by annotating VarHandle directly with the -// // operation kind and shape -// interface VarHandleTemplate { -// Object get(); -// -// void set(Object value); -// -// boolean compareAndSet(Object actualValue, Object expectedValue); -// -// Object compareAndExchange(Object actualValue, Object expectedValue); -// -// Object getAndUpdate(Object value); -// } -// -// record HandleType(Class receiver, Class... intermediates) { -// } -// -// /** -// * @param args parameters -// */ -// public static void main(String[] args) { -// System.out.println("package java.lang.invoke;"); -// System.out.println(); -// System.out.println("import jdk.internal.vm.annotation.AOTSafeClassInitializer;"); -// System.out.println("import jdk.internal.vm.annotation.ForceInline;"); -// System.out.println("import jdk.internal.vm.annotation.Hidden;"); -// System.out.println(); -// System.out.println("// This class is auto-generated by " + -// GuardMethodGenerator.class.getName() + -// ". Do not edit."); -// System.out.println("@AOTSafeClassInitializer"); -// System.out.println("final class VarHandleGuards {"); -// -// System.out.println(); -// -// // Declare the stream of shapes -// List hts = List.of( -// // Object->T -// new HandleType(Object.class), -// -// // ->T -// new HandleType(null), -// -// // Array[index]->T -// new HandleType(Object.class, int.class), -// -// // MS[base]->T -// new HandleType(Object.class, long.class), -// -// // MS[base][offset]->T -// new HandleType(Object.class, long.class, long.class) -// ); -// -// Stream.of(VarHandleTemplate.class.getMethods()). -// mapMulti((m, sink) -> { -// for (var ht : hts) { -// for (var bt : LambdaForm.BasicType.ARG_TYPES) { -// sink.accept(generateMethodType(m, ht.receiver, bt.btClass, ht.intermediates)); -// } -// } -// }). -// distinct(). -// map(GuardMethodGenerator::generateMethod). -// forEach(System.out::println); -// -// System.out.println("}"); -// } -// -// static MethodType generateMethodType(Method m, Class receiver, Class value, Class... intermediates) { -// Class returnType = m.getReturnType() == Object.class -// ? value : m.getReturnType(); -// -// List> params = new ArrayList<>(); -// if (receiver != null) -// params.add(receiver); -// java.util.Collections.addAll(params, intermediates); -// for (var p : m.getParameters()) { -// params.add(value); -// } -// return MethodType.methodType(returnType, params); -// } -// -// static String generateMethod(MethodType mt) { -// Class returnType = mt.returnType(); -// -// var params = new java.util.LinkedHashMap>(); -// params.put("handle", VarHandle.class); -// for (int i = 0; i < mt.parameterCount(); i++) { -// params.put("arg" + i, mt.parameterType(i)); -// } -// params.put("ad", VarHandle.AccessDescriptor.class); -// -// // Generate method signature line -// String RETURN = className(returnType); -// String NAME = "guard"; -// String SIGNATURE = getSignature(mt); -// String PARAMS = params.entrySet().stream(). -// map(e -> className(e.getValue()) + " " + e.getKey()). -// collect(java.util.stream.Collectors.joining(", ")); -// String METHOD = GUARD_METHOD_SIG_TEMPLATE. -// replace("", RETURN). -// replace("", NAME). -// replace("", SIGNATURE). -// replace("", PARAMS); -// -// // Generate method -// params.remove("ad"); -// -// List LINK_TO_STATIC_ARGS = new ArrayList<>(params.keySet()); -// LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)"); -// -// List LINK_TO_INVOKER_ARGS = new ArrayList<>(params.keySet()); -// LINK_TO_INVOKER_ARGS.set(0, LINK_TO_INVOKER_ARGS.get(0) + ".asDirect()"); -// -// RETURN = returnType == void.class -// ? "" -// : returnType == Object.class -// ? "return " -// : "return (" + returnType.getName() + ") "; -// -// String RESULT_ERASED = returnType == void.class -// ? "" -// : returnType != Object.class -// ? "return (" + returnType.getName() + ") " -// : "Object r = "; -// -// String RETURN_ERASED = returnType != Object.class -// ? "" -// : "\n return ad.returnType.cast(r);"; -// -// String template = returnType == void.class -// ? GUARD_METHOD_TEMPLATE_V -// : GUARD_METHOD_TEMPLATE; -// return template. -// replace("", METHOD). -// replace("", NAME). -// replaceAll("", RETURN). -// replace("", RESULT_ERASED). -// replace("", RETURN_ERASED). -// replaceAll("", String.join(", ", LINK_TO_STATIC_ARGS)). -// replace("", String.join(", ", LINK_TO_INVOKER_ARGS)) -// .indent(4); -// } -// -// static String className(Class c) { -// String n = c.getName(); -// if (n.startsWith("java.lang.")) { -// n = n.replace("java.lang.", ""); -// if (n.startsWith("invoke.")) { -// n = n.replace("invoke.", ""); -// } -// } -// return n.replace('$', '.'); -// } -// -// static String getSignature(MethodType m) { -// StringBuilder sb = new StringBuilder(m.parameterCount() + 1); -// -// for (int i = 0; i < m.parameterCount(); i++) { -// Class pt = m.parameterType(i); -// sb.append(getCharType(pt)); -// } -// -// sb.append('_').append(getCharType(m.returnType())); -// -// return sb.toString(); -// } -// -// static char getCharType(Class pt) { -// return Wrapper.forBasicType(pt).basicTypeChar(); -// } -// } } From dbf4ffffe3fbbb513122081bbcc04c543473082e Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 5 Sep 2025 23:55:13 +0000 Subject: [PATCH 161/295] 8366477: Refactor AOT-related flag bits in klass.hpp Reviewed-by: liach, asmehra, kvn --- src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 +- .../classfile/systemDictionaryShared.cpp | 2 +- src/hotspot/share/oops/instanceKlass.hpp | 8 --- src/hotspot/share/oops/instanceKlassFlags.hpp | 2 - src/hotspot/share/oops/klass.cpp | 2 +- src/hotspot/share/oops/klass.hpp | 70 ++++++++++++------- 7 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 7a6c91e503e..42d575a012f 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -942,7 +942,7 @@ void ArchiveBuilder::make_klasses_shareable() { old = " old"; } - if (ik->is_generated_shared_class()) { + if (ik->is_aot_generated_class()) { generated = " generated"; } if (aotlinked) { diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 966b3eab298..e8900f43d43 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -184,7 +184,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { klass->set_shared_classpath_index(0); // Set the "generated" bit, so it won't interfere with JVMTI. // See SystemDictionaryShared::find_builtin_class(). - klass->set_is_generated_shared_class(); + klass->set_is_aot_generated_class(); } } else { int len = h_bytes->length(); @@ -222,7 +222,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, AOTMetaspace::try_link_class(THREAD, result); assert(!HAS_PENDING_EXCEPTION, "Invariant"); - result->set_is_generated_shared_class(); + result->set_is_aot_generated_class(); if (!klass->in_aot_cache()) { log_info(aot, lambda)("regenerate_class excluding klass %s %s", class_name, klass->name()->as_C_string()); SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index df22db82165..45a5dc2328c 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1146,7 +1146,7 @@ InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) { DEBUG_ONLY(check_klass_after_loading(record->klass());) // We did not save the classfile data of the generated LambdaForm invoker classes, // so we cannot support CLFH for such classes. - if (record->klass()->is_generated_shared_class() && JvmtiExport::should_post_class_file_load_hook()) { + if (record->klass()->is_aot_generated_class() && JvmtiExport::should_post_class_file_load_hook()) { return nullptr; } return record->klass(); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 3338b5cd446..dfd134857b8 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -764,14 +764,6 @@ public: bool has_final_method() const { return _misc_flags.has_final_method(); } void set_has_final_method() { _misc_flags.set_has_final_method(true); } - // Indicates presence of @AOTSafeClassInitializer. Also see AOTClassInitializer for more details. - bool has_aot_safe_initializer() const { return _misc_flags.has_aot_safe_initializer(); } - void set_has_aot_safe_initializer() { _misc_flags.set_has_aot_safe_initializer(true); } - - // Indicates @AOTRuntimeSetup private static void runtimeSetup() presence. - bool is_runtime_setup_required() const { return _misc_flags.is_runtime_setup_required(); } - void set_is_runtime_setup_required() { _misc_flags.set_is_runtime_setup_required(true); } - // for adding methods, ConstMethod::UNSET_IDNUM means no more ids available inline u2 next_method_idnum(); void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; } diff --git a/src/hotspot/share/oops/instanceKlassFlags.hpp b/src/hotspot/share/oops/instanceKlassFlags.hpp index 1872c3bc998..18a9c76103d 100644 --- a/src/hotspot/share/oops/instanceKlassFlags.hpp +++ b/src/hotspot/share/oops/instanceKlassFlags.hpp @@ -54,8 +54,6 @@ class InstanceKlassFlags { flag(has_localvariable_table , 1 << 11) /* has localvariable information */ \ flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \ flag(has_final_method , 1 << 13) /* True if klass has final method */ \ - flag(has_aot_safe_initializer , 1 << 14) /* has @AOTSafeClassInitializer annotation */ \ - flag(is_runtime_setup_required , 1 << 15) /* has a runtimeSetup method to be called */ \ /* end of list */ #define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value, diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index f4ae128aef7..92bcaebec4a 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -302,7 +302,7 @@ Klass::Klass() : _kind(UnknownKlassKind) { Klass::Klass(KlassKind kind) : _kind(kind), _prototype_header(make_prototype(this)), _shared_class_path_index(-1) { - CDS_ONLY(_shared_class_flags = 0;) + CDS_ONLY(_aot_class_flags = 0;) CDS_JAVA_HEAP_ONLY(_archived_mirror_index = -1;) _primary_supers[0] = this; set_super_check_offset(in_bytes(primary_supers_offset())); diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index d62f3f21ee2..ad03c1e2ed6 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -174,18 +174,20 @@ private: #if INCLUDE_CDS // Various attributes for shared classes. Should be zero for a non-shared class. - u2 _shared_class_flags; - enum CDSSharedClassFlags { + u2 _aot_class_flags; + enum { _in_aot_cache = 1 << 0, _archived_lambda_proxy_is_available = 1 << 1, _has_value_based_class_annotation = 1 << 2, _verified_at_dump_time = 1 << 3, _has_archived_enum_objs = 1 << 4, - // This class was not loaded from a classfile in the module image - // or classpath. - _is_generated_shared_class = 1 << 5, - // archived mirror already initialized by AOT-cache assembly: no further need to call - _has_aot_initialized_mirror = 1 << 6, + _is_aot_generated_class = 1 << 5, // this class was not loaded from a classfile in the module image + // or classpath, but was generated during AOT cache assembly. + _has_aot_initialized_mirror = 1 << 6, // archived mirror already initialized by AOT cache assembly. + // no further need to call + _has_aot_safe_initializer = 1 << 7, // has @AOTSafeClassInitializer annotation + _is_runtime_setup_required = 1 << 8, // has a runtimeSetup method to be called when + // this class is loaded from AOT cache }; #endif @@ -325,66 +327,84 @@ protected: void clear_archived_mirror_index() NOT_CDS_JAVA_HEAP_RETURN; void set_lambda_proxy_is_available() { - CDS_ONLY(_shared_class_flags |= _archived_lambda_proxy_is_available;) + CDS_ONLY(_aot_class_flags |= _archived_lambda_proxy_is_available;) } void clear_lambda_proxy_is_available() { - CDS_ONLY(_shared_class_flags &= (u2)(~_archived_lambda_proxy_is_available);) + CDS_ONLY(_aot_class_flags &= (u2)(~_archived_lambda_proxy_is_available);) } bool lambda_proxy_is_available() const { - CDS_ONLY(return (_shared_class_flags & _archived_lambda_proxy_is_available) != 0;) + CDS_ONLY(return (_aot_class_flags & _archived_lambda_proxy_is_available) != 0;) NOT_CDS(return false;) } void set_has_value_based_class_annotation() { - CDS_ONLY(_shared_class_flags |= _has_value_based_class_annotation;) + CDS_ONLY(_aot_class_flags |= _has_value_based_class_annotation;) } void clear_has_value_based_class_annotation() { - CDS_ONLY(_shared_class_flags &= (u2)(~_has_value_based_class_annotation);) + CDS_ONLY(_aot_class_flags &= (u2)(~_has_value_based_class_annotation);) } bool has_value_based_class_annotation() const { - CDS_ONLY(return (_shared_class_flags & _has_value_based_class_annotation) != 0;) + CDS_ONLY(return (_aot_class_flags & _has_value_based_class_annotation) != 0;) NOT_CDS(return false;) } void set_verified_at_dump_time() { - CDS_ONLY(_shared_class_flags |= _verified_at_dump_time;) + CDS_ONLY(_aot_class_flags |= _verified_at_dump_time;) } bool verified_at_dump_time() const { - CDS_ONLY(return (_shared_class_flags & _verified_at_dump_time) != 0;) + CDS_ONLY(return (_aot_class_flags & _verified_at_dump_time) != 0;) NOT_CDS(return false;) } void set_has_archived_enum_objs() { - CDS_ONLY(_shared_class_flags |= _has_archived_enum_objs;) + CDS_ONLY(_aot_class_flags |= _has_archived_enum_objs;) } bool has_archived_enum_objs() const { - CDS_ONLY(return (_shared_class_flags & _has_archived_enum_objs) != 0;) + CDS_ONLY(return (_aot_class_flags & _has_archived_enum_objs) != 0;) NOT_CDS(return false;) } - void set_is_generated_shared_class() { - CDS_ONLY(_shared_class_flags |= _is_generated_shared_class;) + void set_is_aot_generated_class() { + CDS_ONLY(_aot_class_flags |= _is_aot_generated_class;) } - bool is_generated_shared_class() const { - CDS_ONLY(return (_shared_class_flags & _is_generated_shared_class) != 0;) + bool is_aot_generated_class() const { + CDS_ONLY(return (_aot_class_flags & _is_aot_generated_class) != 0;) NOT_CDS(return false;) } void set_has_aot_initialized_mirror() { - CDS_ONLY(_shared_class_flags |= _has_aot_initialized_mirror;) + CDS_ONLY(_aot_class_flags |= _has_aot_initialized_mirror;) } bool has_aot_initialized_mirror() const { - CDS_ONLY(return (_shared_class_flags & _has_aot_initialized_mirror) != 0;) + CDS_ONLY(return (_aot_class_flags & _has_aot_initialized_mirror) != 0;) + NOT_CDS(return false;) + } + + // Indicates presence of @AOTSafeClassInitializer. Also see AOTClassInitializer for more details. + void set_has_aot_safe_initializer() { + CDS_ONLY(_aot_class_flags |= _has_aot_safe_initializer;) + } + bool has_aot_safe_initializer() const { + CDS_ONLY(return (_aot_class_flags & _has_aot_safe_initializer) != 0;) + NOT_CDS(return false;) + } + + // Indicates @AOTRuntimeSetup private static void runtimeSetup() presence. + void set_is_runtime_setup_required() { + CDS_ONLY(_aot_class_flags |= _is_runtime_setup_required;) + } + bool is_runtime_setup_required() const { + CDS_ONLY(return (_aot_class_flags & _is_runtime_setup_required) != 0;) NOT_CDS(return false;) } bool in_aot_cache() const { // shadows MetaspaceObj::in_aot_cache)() - CDS_ONLY(return (_shared_class_flags & _in_aot_cache) != 0;) + CDS_ONLY(return (_aot_class_flags & _in_aot_cache) != 0;) NOT_CDS(return false;) } void set_in_aot_cache() { - CDS_ONLY(_shared_class_flags |= _in_aot_cache;) + CDS_ONLY(_aot_class_flags |= _in_aot_cache;) } // Obtain the module or package for this class From e8c7d2aaf3cdbbe07b8cdcc68dd7ec9645956bf2 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Sat, 6 Sep 2025 09:00:51 +0000 Subject: [PATCH 162/295] 8332872: SetupExecute should cd to temp directory Reviewed-by: erikj --- make/CreateJmods.gmk | 1 + make/UpdateSleefSource.gmk | 16 ++++----- make/common/Execute.gmk | 20 +++++++---- test/make/TestExecute.gmk | 74 ++++++++++++++++++++++++++++++++++++++ test/make/TestMake.gmk | 5 ++- 5 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 test/make/TestExecute.gmk diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index a26042fb0d5..3280b24924a 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -257,6 +257,7 @@ $(eval $(call SetupExecute, create_$(JMOD_FILE), \ WARN := Creating $(INTERIM_MSG)$(JMOD_FILE), \ DEPS := $(DEPS), \ OUTPUT_FILE := $(JMODS_DIR)/$(JMOD_FILE), \ + WORKING_DIR := $(WORKSPACE_ROOT), \ SUPPORT_DIR := $(JMODS_SUPPORT_DIR), \ PRE_COMMAND := $(RM) $(JMODS_DIR)/$(JMOD_FILE) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \ COMMAND := $(JMOD) $(JMOD_SMALL_FLAGS) create --module-version $(VERSION_SHORT) \ diff --git a/make/UpdateSleefSource.gmk b/make/UpdateSleefSource.gmk index c7fdfdb41d9..d7b8f8e141b 100644 --- a/make/UpdateSleefSource.gmk +++ b/make/UpdateSleefSource.gmk @@ -81,8 +81,8 @@ SLEEF_CMAKE_FILE := toolchains/$(OPENJDK_TARGET_CPU)-$(SLEEF_TOOLCHAIN_TYPE).cma $(eval $(call SetupExecute, sleef_native_config, \ INFO := Configuring native sleef build, \ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \ - $(SLEEF_NATIVE_BUILD_DIR), \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) -S . -B $(SLEEF_NATIVE_BUILD_DIR), \ )) TARGETS := $(sleef_native_config) @@ -91,8 +91,8 @@ $(eval $(call SetupExecute, sleef_native_build, \ INFO := Building native sleef, \ DEPS := $(sleef_native_config), \ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \ - $(SLEEF_NATIVE_BUILD_DIR) -j, \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) --build $(SLEEF_NATIVE_BUILD_DIR) -j, \ )) TARGETS := $(sleef_native_build) @@ -101,8 +101,8 @@ $(eval $(call SetupExecute, sleef_cross_config, \ INFO := Configuring cross-compiling sleef build, \ DEPS := $(sleef_native_build), \ OUTPUT_DIR := $(SLEEF_CROSS_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \ - $(SLEEF_CROSS_BUILD_DIR) \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) -S . -B $(SLEEF_CROSS_BUILD_DIR) \ -DCMAKE_C_COMPILER=$(CC) \ -DCMAKE_TOOLCHAIN_FILE=$(SLEEF_CMAKE_FILE) \ -DNATIVE_BUILD_DIR=$(SLEEF_NATIVE_BUILD_DIR) \ @@ -116,8 +116,8 @@ $(eval $(call SetupExecute, sleef_cross_build, \ INFO := Building cross-compiling sleef, \ DEPS := $(sleef_cross_config), \ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \ - $(SLEEF_CROSS_BUILD_DIR) -j, \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) --build $(SLEEF_CROSS_BUILD_DIR) -j, \ )) TARGETS := $(sleef_cross_build) diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk index bf108c30c05..1ee3c28261b 100644 --- a/make/common/Execute.gmk +++ b/make/common/Execute.gmk @@ -45,6 +45,9 @@ ifeq ($(INCLUDE), true) # e.g. a simple sed replacement on the input file. If the operations are # unrelated to the main COMMAND, this is not a suitable solution. # +# Before execution, the current working directory is changed to SUPPORT_DIR. +# This can be overridden with WORKING_DIR. +# # If your command outputs a variety of files, or if it's really a single file # but you don't really care about the output from the perspective, you can just # supply an OUTPUT_DIR. You are supposed to make sure the command creates files @@ -75,6 +78,7 @@ ifeq ($(INCLUDE), true) # OUTPUT_DIR : The directory that will contain the result from the command # OUTPUT_FILE : Use this if the command results in a single output file # SUPPORT_DIR : Where to store generated support files +# WORKING_DIR : Directory to cd to before executing the command # INFO : Message to display at LOG=info level when running command (optional) # WARN : Message to display at LOG=warn level when running command (optional) # DEPS : Dependencies for the execution to take place @@ -133,6 +137,10 @@ define SetupExecuteBody endif + ifeq ($$($1_WORKING_DIR), ) + $1_WORKING_DIR := $$($1_SUPPORT_DIR) + endif + ifeq ($$($1_INFO)$$($1_WARN), ) # If neither info nor warn is provided, add basic info text. $1_INFO := Running commands for $1 @@ -147,14 +155,14 @@ define SetupExecuteBody ifneq ($$($1_INFO), ) $$(call LogInfo, $$($1_INFO)) endif - $$(call MakeDir, $$($1_SUPPORT_DIR) $$($1_OUTPUT_DIR)) + $$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) $$(call ExecuteWithLog, $$($1_BASE)_pre, \ - $$($1_PRE_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_PRE_COMMAND)) $$(TOUCH) $$@ $$($1_EXEC_RESULT): $$($1_PRE_MARKER) $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - $$($1_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif @@ -168,9 +176,9 @@ define SetupExecuteBody ifneq ($$($1_INFO), ) $$(call LogInfo, $$($1_INFO)) endif - $$(call MakeDir, $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) + $$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - $$($1_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif @@ -182,7 +190,7 @@ define SetupExecuteBody $$($1_FINAL_RESULT): $$($1_EXEC_RESULT) $$(call ExecuteWithLog, $$($1_BASE)_post, \ - $$($1_POST_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_POST_COMMAND)) $$(TOUCH) $$@ $1 += $$($1_FINAL_RESULT) diff --git a/test/make/TestExecute.gmk b/test/make/TestExecute.gmk new file mode 100644 index 00000000000..f71a402502e --- /dev/null +++ b/test/make/TestExecute.gmk @@ -0,0 +1,74 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# 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 MakeFileStart.gmk + +################################################################################ + +include Execute.gmk +include UtilsForTests.gmk + +THIS_FILE := $(TOPDIR)/test/make/TestExecute.gmk +DEPS := $(THIS_FILE) \ + $(TOPDIR)/make/common/MakeBase.gmk \ + # + +OUTPUT_DIR := $(TESTMAKE_OUTPUTDIR)/execute +$(call MakeDir, $(OUTPUT_DIR)) + +################################################################################ +# Test SetupExecute + +$(eval $(call SetupExecute, EXEC_1, \ + INFO := Testing that SetupExecute runs from SUPPORT_DIR, \ + OUTPUT_DIR := $(OUTPUT_DIR)/exec_1, \ + SUPPORT_DIR := $(OUTPUT_DIR)/exec_1/support, \ + COMMAND := $(ECHO) "Generating junk file" > ./junkfile, \ +)) + +run-test1: $(EXEC_1) + test -f $(OUTPUT_DIR)/exec_1/support/junkfile + +$(eval $(call SetupExecute, EXEC_2, \ + INFO := Testing that SetupExecute runs from SUPPORT_DIR, \ + OUTPUT_DIR := $(OUTPUT_DIR)/exec_2, \ + SUPPORT_DIR := $(OUTPUT_DIR)/exec_2/support, \ + WORKING_DIR := $(OUTPUT_DIR)/exec_2/special, \ + COMMAND := $(ECHO) "Generating special file" > ./specialfile, \ +)) + +run-test2: $(EXEC_2) + test -f $(OUTPUT_DIR)/exec_2/special/specialfile + + +TEST_TARGETS += run-test1 run-test2 + +.PHONY: run-test1 run-test2 + +################################################################################ + +all: $(TEST_TARGETS) + +################################################################################ + +include MakeFileEnd.gmk diff --git a/test/make/TestMake.gmk b/test/make/TestMake.gmk index a017b573d0c..8c4141c1c89 100644 --- a/test/make/TestMake.gmk +++ b/test/make/TestMake.gmk @@ -34,6 +34,9 @@ java-compilation: copy-files: +$(MAKE) -f TestCopyFiles.gmk $(TEST_SUBTARGET) +execute: + +$(MAKE) -f TestExecute.gmk $(TEST_SUBTARGET) + fix-deps-file: +$(MAKE) -f TestFixDepsFile.gmk $(TEST_SUBTARGET) @@ -47,7 +50,7 @@ configure: $(BASH) $(TOPDIR)/test/make/autoconf/test-configure.sh \ "$(AUTOCONF)" "$(TOPDIR)" "$(TEST_SUPPORT_DIR)" -TARGETS += make-base java-compilation copy-files fix-deps-file idea \ +TARGETS += make-base java-compilation copy-files execute fix-deps-file idea \ compile-commands configure # Prints targets to TARGETS_FILE which must be set when calling this target. From 6bb15a542b0eb6a4b17cfd9da50a94781d0180eb Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 7 Sep 2025 20:21:23 +0000 Subject: [PATCH 163/295] 8367035: [BACKOUT] Protect ExecuteWithLog from running with redirection without a subshell Reviewed-by: kbarrett --- make/RunTests.gmk | 28 ++++++++++++++-------------- make/StaticLibs.gmk | 2 +- make/common/MakeBase.gmk | 26 +++++++++----------------- make/common/ProcessMarkdown.gmk | 2 +- make/hotspot/gensrc/GensrcDtrace.gmk | 5 ++--- 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index b44243dae76..10f0a2f87ed 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -509,7 +509,7 @@ define SetupRunGtestTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \ $$(CD) $$($1_TEST_SUPPORT_DIR) && \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ -jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \ @@ -520,7 +520,7 @@ define SetupRunGtestTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - ) + )) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt @@ -644,7 +644,7 @@ define SetupRunMicroTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ @@ -655,7 +655,7 @@ define SetupRunMicroTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - ) + )) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt @@ -758,34 +758,34 @@ define SetupAOTBody ifeq ($$($1_TRAINING), onestep) $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - ) + )) else $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - ) + )) $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - ) + )) endif @@ -1085,9 +1085,9 @@ define SetupRunJtregTestBody $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \ $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ - ) + )) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1204,12 +1204,12 @@ define SetupRunSpecialTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \ $$($1_TEST_COMMAND_LINE) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - ) + )) # We can not parse the various "special" tests. parse-test-$1: run-test-$1 diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk index 80d6b4538c8..3cf2a4dd136 100644 --- a/make/StaticLibs.gmk +++ b/make/StaticLibs.gmk @@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true) INFO := Generating export list for $(notdir $(lib)), \ DEPS := $(lib), \ OUTPUT_FILE := $(lib).exp, \ - COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \ + COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \ )) \ $(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \ ) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 97ef88932cb..d1bb0396943 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -284,12 +284,6 @@ else LogCmdlines = endif -# Check if the command line contains redirection, that is <, > or >>, -# and if so, return a value that is interpreted as true in a make $(if) -# construct. -is_redirect = \ - $(if $(filter < > >>, $1), true) - ################################################################################ # ExecuteWithLog will run a command and log the output appropriately. This is # meant to be used by commands that do "real" work, like a compilation. @@ -297,23 +291,21 @@ is_redirect = \ # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # +# NOTE: If the command redirects stdout, the caller needs to wrap it in a +# subshell (by adding parentheses around it), otherwise the redirect to the +# subshell tee process will create a race condition where the target file may +# not be fully written when the make recipe is done. +# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ - $(call LogCmdlines, Executing: \ - [$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ - is_redirect, $2), $(RIGHT_PAREN))]) \ + $(call LogCmdlines, Executing: [$(strip $2)]) \ $(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(RM) $(strip $1).log && \ - $(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ - is_redirect, $2), $(RIGHT_PAREN)) \ - > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ + ( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ - $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ - /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ - $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ - /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ + $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ + $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ exit $(DOLLAR)exitcode ) ) ################################################################################ diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index c60b49ae85f..1b4a5b76ea1 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -109,7 +109,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) + ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index 7a80bf47285..e71c3cb961d 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -47,9 +47,8 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - $(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) - $(call ExecuteWithLog, $@, \ - $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + ($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) + $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: # hotspot_jni.d hotspot.d hs_private.d From 14a40fd579b087f061da086f5eb18230c379dce0 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sun, 7 Sep 2025 23:18:07 +0000 Subject: [PATCH 164/295] 8361533: Apply java.io.Serial annotations in java.logging Reviewed-by: rriggs --- .../share/classes/java/util/logging/LoggingPermission.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java.logging/share/classes/java/util/logging/LoggingPermission.java b/src/java.logging/share/classes/java/util/logging/LoggingPermission.java index d9cf9b58bbd..725a2dd19da 100644 --- a/src/java.logging/share/classes/java/util/logging/LoggingPermission.java +++ b/src/java.logging/share/classes/java/util/logging/LoggingPermission.java @@ -26,6 +26,7 @@ package java.util.logging; +import java.io.Serial; /** * This class is for logging permissions. Currently there is only one @@ -48,6 +49,7 @@ package java.util.logging; @Deprecated(since="25", forRemoval=true) public final class LoggingPermission extends java.security.BasicPermission { + @Serial private static final long serialVersionUID = 63564341580231582L; /** From 8a6b8751e1a8ad93646bf3900186802c863d7119 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 7 Sep 2025 23:20:22 +0000 Subject: [PATCH 165/295] 8354871: Replace stack map frame type magics with constants Reviewed-by: liach --- .../attribute/StackMapFrameInfo.java | 19 +++---- .../jdk/internal/classfile/impl/CodeImpl.java | 15 +++--- .../classfile/impl/StackMapDecoder.java | 33 ++++++------ .../classfile/impl/StackMapGenerator.java | 32 +++++++++--- .../impl/verifier/ParserVerifier.java | 18 ++++--- .../impl/verifier/VerificationTable.java | 35 ++++++------- .../impl/verifier/VerificationType.java | 50 +++++++------------ 7 files changed, 99 insertions(+), 103 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 06e9e6d585e..d807cc23f2a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -34,6 +34,7 @@ import java.lang.constant.ClassDesc; import java.util.List; import jdk.internal.classfile.impl.StackMapDecoder; +import jdk.internal.classfile.impl.StackMapGenerator; import jdk.internal.classfile.impl.TemporaryConstantPool; /** @@ -103,31 +104,31 @@ public sealed interface StackMapFrameInfo sealed interface VerificationTypeInfo { /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#TOP TOP}. */ - int ITEM_TOP = 0; + int ITEM_TOP = StackMapGenerator.ITEM_TOP; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#INTEGER INTEGER}. */ - int ITEM_INTEGER = 1; + int ITEM_INTEGER = StackMapGenerator.ITEM_INTEGER; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#FLOAT FLOAT}. */ - int ITEM_FLOAT = 2; + int ITEM_FLOAT = StackMapGenerator.ITEM_FLOAT; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#DOUBLE DOUBLE}. */ - int ITEM_DOUBLE = 3; + int ITEM_DOUBLE = StackMapGenerator.ITEM_DOUBLE; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#LONG LONG}. */ - int ITEM_LONG = 4; + int ITEM_LONG = StackMapGenerator.ITEM_LONG; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#NULL NULL}. */ - int ITEM_NULL = 5; + int ITEM_NULL = StackMapGenerator.ITEM_NULL; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#UNINITIALIZED_THIS UNINITIALIZED_THIS}. */ - int ITEM_UNINITIALIZED_THIS = 6; + int ITEM_UNINITIALIZED_THIS = StackMapGenerator.ITEM_UNINITIALIZED_THIS; /** The {@link #tag() tag} for verification type info {@link ObjectVerificationTypeInfo OBJECT}. */ - int ITEM_OBJECT = 7; + int ITEM_OBJECT = StackMapGenerator.ITEM_OBJECT; /** The {@link #tag() tag} for verification type info {@link UninitializedVerificationTypeInfo UNINITIALIZED}. */ - int ITEM_UNINITIALIZED = 8; + int ITEM_UNINITIALIZED = StackMapGenerator.ITEM_UNINITIALIZED; /** * {@return the tag of the type info} diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index c8c6d254650..e4480d740bd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -39,6 +39,7 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; +import static jdk.internal.classfile.impl.StackMapGenerator.*; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class CodeImpl @@ -292,33 +293,33 @@ public final class CodeImpl for (int i = 0; i < nEntries; ++i) { int frameType = classReader.readU1(p); int offsetDelta; - if (frameType < 64) { + if (frameType <= SAME_FRAME_END) { offsetDelta = frameType; ++p; } - else if (frameType < 128) { + else if (frameType <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) { offsetDelta = frameType & 0x3f; p = adjustForObjectOrUninitialized(p + 1); } else switch (frameType) { - case 247 -> { + case SAME_LOCALS_1_STACK_ITEM_EXTENDED -> { offsetDelta = classReader.readU2(p + 1); p = adjustForObjectOrUninitialized(p + 3); } - case 248, 249, 250, 251 -> { + case CHOP_FRAME_START, CHOP_FRAME_START + 1, CHOP_FRAME_END, SAME_FRAME_EXTENDED -> { offsetDelta = classReader.readU2(p + 1); p += 3; } - case 252, 253, 254 -> { + case APPEND_FRAME_START, APPEND_FRAME_START + 1, APPEND_FRAME_END -> { offsetDelta = classReader.readU2(p + 1); - int k = frameType - 251; + int k = frameType - APPEND_FRAME_START + 1; p += 3; for (int c = 0; c < k; ++c) { p = adjustForObjectOrUninitialized(p); } } - case 255 -> { + case FULL_FRAME -> { offsetDelta = classReader.readU2(p + 1); p += 3; int k = classReader.readU2(p); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index c5ce2204c09..d8e24cd2b70 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -44,14 +44,11 @@ import java.util.List; import java.util.Objects; import static java.lang.classfile.ClassFile.ACC_STATIC; -import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*; import static java.util.Objects.requireNonNull; +import static jdk.internal.classfile.impl.StackMapGenerator.*; public class StackMapDecoder { - private static final int - SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, - SAME_EXTENDED = 251; private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {}; private final ClassReader classReader; @@ -136,25 +133,25 @@ public class StackMapDecoder { int commonLocalsSize = Math.min(prevLocals.size(), fr.locals().size()); int diffLocalsSize = fr.locals().size() - prevLocals.size(); if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(fr.locals(), prevLocals, commonLocalsSize)) { - if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame + if (diffLocalsSize == 0 && offsetDelta <= SAME_FRAME_END) { //same frame out.writeU1(offsetDelta); } else { //chop, same extended or append frame - out.writeU1U2(251 + diffLocalsSize, offsetDelta); + out.writeU1U2(SAME_FRAME_EXTENDED + diffLocalsSize, offsetDelta); for (int i=commonLocalsSize; i prevFrame.localsSize ? prevFrame.localsSize : localsSize; int diffLocalsSize = localsSize - prevFrame.localsSize; if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(locals, prevFrame.locals, commonLocalsSize)) { - if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame + if (diffLocalsSize == 0 && offsetDelta <= SAME_FRAME_END) { //same frame out.writeU1(offsetDelta); } else { //chop, same extended or append frame - out.writeU1U2(251 + diffLocalsSize, offsetDelta); + out.writeU1U2(SAME_FRAME_EXTENDED + diffLocalsSize, offsetDelta); for (int i=commonLocalsSize; i 246) { - if (ft == 247) return 3 + verificationTypeSize(frame.stack().getFirst()); - if (ft < 252) return 3; - if (ft < 255) { + if (ft <= SAME_FRAME_END) return 1; + if (ft <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) return 1 + verificationTypeSize(frame.stack().getFirst()); + if (ft > RESERVED_END) { + if (ft == SAME_LOCALS_1_STACK_ITEM_EXTENDED) return 3 + verificationTypeSize(frame.stack().getFirst()); + if (ft <= SAME_FRAME_EXTENDED) return 3; + if (ft <= APPEND_FRAME_END) { var loc = frame.locals(); int l = 3; - for (int i = loc.size() + 251 - ft; i < loc.size(); i++) { + var k = ft - APPEND_FRAME_START + 1; + for (int i = loc.size() - k; i < loc.size(); i++) { l += verificationTypeSize(loc.get(i)); } return l; } - if (ft == 255) { + if (ft == FULL_FRAME) { int l = 7; for (var vt : frame.stack()) { l += verificationTypeSize(vt); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java index 85342e7106f..04276b8eeb8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java @@ -27,9 +27,7 @@ package jdk.internal.classfile.impl.verifier; import java.util.ArrayList; import java.util.List; -import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object; -import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized; -import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis; +import static jdk.internal.classfile.impl.StackMapGenerator.*; /// From `stackMapTable.cpp`. class VerificationTable { @@ -158,11 +156,6 @@ class VerificationTable { } } - private static final int - SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, - SAME_EXTENDED = 251, - FULL = 255; - public int get_frame_count() { return _frame_count; } @@ -252,10 +245,10 @@ class VerificationTable { VerificationType parse_verification_type(int[] flags) { int tag = _stream.get_u1(); - if (tag < ITEM_UninitializedThis) { + if (tag < ITEM_UNINITIALIZED_THIS) { return VerificationType.from_tag(tag, _verifier); } - if (tag == ITEM_Object) { + if (tag == ITEM_OBJECT) { int class_index = _stream.get_u2(); int nconstants = _cp.entryCount(); if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { @@ -263,13 +256,13 @@ class VerificationTable { } return VerificationType.reference_type(_cp.classNameAt(class_index)); } - if (tag == ITEM_UninitializedThis) { + if (tag == ITEM_UNINITIALIZED_THIS) { if (flags != null) { flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; } return VerificationType.uninitialized_this_type; } - if (tag == ITEM_Uninitialized) { + if (tag == ITEM_UNINITIALIZED) { int offset = _stream.get_u2(); if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); @@ -285,7 +278,7 @@ class VerificationTable { int offset; VerificationType[] locals = null; int frame_type = _stream.get_u1(); - if (frame_type < 64) { + if (frame_type <= SAME_FRAME_END) { if (_first) { offset = frame_type; if (_prev_frame.locals_size() > 0) { @@ -302,14 +295,14 @@ class VerificationTable { _first = false; return frame; } - if (frame_type < 128) { + if (frame_type <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) { if (_first) { - offset = frame_type - 64; + offset = frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_START; if (_prev_frame.locals_size() > 0) { locals = new VerificationType[_prev_frame.locals_size()]; } } else { - offset = _prev_frame.offset() + frame_type - 63; + offset = _prev_frame.offset() + frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_START + 1; locals = _prev_frame.locals(); } VerificationType[] stack = new VerificationType[2]; @@ -356,10 +349,10 @@ class VerificationTable { _first = false; return frame; } - if (frame_type <= SAME_EXTENDED) { + if (frame_type <= SAME_FRAME_EXTENDED) { locals = _prev_frame.locals(); int length = _prev_frame.locals_size(); - int chops = SAME_EXTENDED - frame_type; + int chops = SAME_FRAME_EXTENDED - frame_type; int new_length = length; int flags = _prev_frame.flags(); if (chops != 0) { @@ -389,8 +382,8 @@ class VerificationTable { } _first = false; return frame; - } else if (frame_type < SAME_EXTENDED + 4) { - int appends = frame_type - SAME_EXTENDED; + } else if (frame_type <= APPEND_FRAME_END) { + int appends = frame_type - APPEND_FRAME_START + 1; int real_length = _prev_frame.locals_size(); int new_length = real_length + appends*2; locals = new VerificationType[new_length]; @@ -418,7 +411,7 @@ class VerificationTable { _first = false; return frame; } - if (frame_type == FULL) { + if (frame_type == FULL_FRAME) { int flags[] = new int[]{0}; int locals_size = _stream.get_u2(); int real_locals_size = 0; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java index caf230cbdc0..dd9742be305 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java @@ -33,6 +33,7 @@ import java.util.Objects; import jdk.internal.classfile.impl.ClassHierarchyImpl; import jdk.internal.classfile.impl.Util; +import static jdk.internal.classfile.impl.StackMapGenerator.*; import static jdk.internal.classfile.impl.verifier.VerifierImpl.*; /// From `verificationType.cpp`. @@ -40,18 +41,6 @@ class VerificationType { private static final int BitsPerByte = 8; - static final int - ITEM_Top = 0, - ITEM_Integer = 1, - ITEM_Float = 2, - ITEM_Double = 3, - ITEM_Long = 4, - ITEM_Null = 5, - ITEM_UninitializedThis = 6, - ITEM_Object = 7, - ITEM_Uninitialized = 8, - ITEM_Bogus = -1; - VerificationType(String sym) { _data = 0x100; _sym = sym; @@ -92,9 +81,6 @@ class VerificationType { String name() { return _sym; } - private static final int - ITEM_Boolean = 9, ITEM_Byte = 10, ITEM_Short = 11, ITEM_Char = 12, - ITEM_Long_2nd = 13, ITEM_Double_2nd = 14; private static final int TypeMask = 0x00000003, @@ -116,17 +102,17 @@ class VerificationType { Category2_2nd = (Category2_2ndFlag << BitsPerByte) | Primitive, // Primitive values (type discriminator stored in most-significant bytes) // Bogus needs the " | Primitive". Else, isReference(Bogus) returns TRUE. - Bogus = (ITEM_Bogus << 2 * BitsPerByte) | Primitive, - Boolean = (ITEM_Boolean << 2 * BitsPerByte) | Category1, - Byte = (ITEM_Byte << 2 * BitsPerByte) | Category1, - Short = (ITEM_Short << 2 * BitsPerByte) | Category1, - Char = (ITEM_Char << 2 * BitsPerByte) | Category1, - Integer = (ITEM_Integer << 2 * BitsPerByte) | Category1, - Float = (ITEM_Float << 2 * BitsPerByte) | Category1, - Long = (ITEM_Long << 2 * BitsPerByte) | Category2, - Double = (ITEM_Double << 2 * BitsPerByte) | Category2, - Long_2nd = (ITEM_Long_2nd << 2 * BitsPerByte) | Category2_2nd, - Double_2nd = (ITEM_Double_2nd << 2 * BitsPerByte) | Category2_2nd, + Bogus = (ITEM_BOGUS << 2 * BitsPerByte) | Primitive, + Boolean = (ITEM_BOOLEAN << 2 * BitsPerByte) | Category1, + Byte = (ITEM_BYTE << 2 * BitsPerByte) | Category1, + Short = (ITEM_SHORT << 2 * BitsPerByte) | Category1, + Char = (ITEM_CHAR << 2 * BitsPerByte) | Category1, + Integer = (ITEM_INTEGER << 2 * BitsPerByte) | Category1, + Float = (ITEM_FLOAT << 2 * BitsPerByte) | Category1, + Long = (ITEM_LONG << 2 * BitsPerByte) | Category2, + Double = (ITEM_DOUBLE << 2 * BitsPerByte) | Category2, + Long_2nd = (ITEM_LONG_2ND << 2 * BitsPerByte) | Category2_2nd, + Double_2nd = (ITEM_DOUBLE_2ND << 2 * BitsPerByte) | Category2_2nd, // Used by Uninitialized (second and third bytes hold the bci) BciMask = 0xffff << BitsPerByte, // A bci of -1 is an Uninitialized-This @@ -364,12 +350,12 @@ class VerificationType { static VerificationType from_tag(int tag, VerifierImpl context) { switch (tag) { - case ITEM_Top: return bogus_type; - case ITEM_Integer: return integer_type; - case ITEM_Float: return float_type; - case ITEM_Double: return double_type; - case ITEM_Long: return long_type; - case ITEM_Null: return null_type; + case ITEM_TOP: return bogus_type; + case ITEM_INTEGER: return integer_type; + case ITEM_FLOAT: return float_type; + case ITEM_DOUBLE: return double_type; + case ITEM_LONG: return long_type; + case ITEM_NULL: return null_type; default: context.verifyError("Should not reach here"); return bogus_type; From b0ca9bf61e0390a3b022a0915eacabb0cfd92e93 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 04:35:05 +0000 Subject: [PATCH 166/295] 8365776: Convert JShell tests to use JUnit instead of TestNG Reviewed-by: vromero --- .../jdk/jshell/AbstractStopExecutionTest.java | 2 +- test/langtools/jdk/jshell/AnalysisTest.java | 11 +- .../jdk/jshell/AnalyzeSnippetTest.java | 81 +++++----- .../jshell/BadExecutionControlSpecTest.java | 11 +- .../jdk/jshell/ClassMembersTest.java | 26 +-- test/langtools/jdk/jshell/ClassPathTest.java | 13 +- test/langtools/jdk/jshell/ClassesTest.java | 55 +++++-- .../jdk/jshell/CommandCompletionTest.java | 20 ++- .../jdk/jshell/CompilerOptionsTest.java | 13 +- .../jdk/jshell/CompletenessStressTest.java | 10 +- .../jdk/jshell/CompletenessTest.java | 26 ++- .../jdk/jshell/CompletionSuggestionTest.java | 60 ++++++- .../langtools/jdk/jshell/ComputeFQNsTest.java | 20 +-- test/langtools/jdk/jshell/ConsoleTest.java | 18 +-- .../langtools/jdk/jshell/ConsoleToolTest.java | 4 +- .../jdk/jshell/CustomInputToolBuilder.java | 12 +- test/langtools/jdk/jshell/DropTest.java | 18 ++- test/langtools/jdk/jshell/EditorTestBase.java | 28 ++-- test/langtools/jdk/jshell/EmptyTest.java | 13 +- .../jdk/jshell/ErrorRecoveryTest.java | 11 +- .../jdk/jshell/ErrorTranslationTest.java | 26 +-- .../jdk/jshell/ExceptionMessageTest.java | 19 +-- test/langtools/jdk/jshell/ExceptionsTest.java | 46 ++++-- .../jdk/jshell/ExecutionControlSpecTest.java | 14 +- .../jdk/jshell/ExecutionControlTestBase.java | 4 +- .../jdk/jshell/ExpectedDiagnostic.java | 14 +- .../jdk/jshell/ExternalEditorTest.java | 37 ++--- .../FailOverDirectExecutionControlTest.java | 28 ++-- ...ilOverExecutionControlDyingLaunchTest.java | 10 +- ...OverExecutionControlHangingLaunchTest.java | 10 +- ...OverExecutionControlHangingListenTest.java | 10 +- .../jshell/FailOverExecutionControlTest.java | 10 +- .../langtools/jdk/jshell/FileManagerTest.java | 15 +- .../jshell/ForwardReferenceImportTest.java | 24 ++- .../jdk/jshell/ForwardReferenceTest.java | 33 ++-- .../langtools/jdk/jshell/GetResourceTest.java | 13 +- .../langtools/jdk/jshell/HighlightUITest.java | 6 +- test/langtools/jdk/jshell/HistoryTest.java | 34 ++-- test/langtools/jdk/jshell/HistoryUITest.java | 9 +- test/langtools/jdk/jshell/IOTest.java | 17 +- .../langtools/jdk/jshell/IdGeneratorTest.java | 20 ++- test/langtools/jdk/jshell/IgnoreTest.java | 16 +- .../jshell/IllegalArgumentExceptionTest.java | 15 +- test/langtools/jdk/jshell/ImportTest.java | 27 +++- .../jshell/InaccessibleExpressionTest.java | 24 +-- test/langtools/jdk/jshell/IndentUITest.java | 8 +- test/langtools/jdk/jshell/InferTypeTest.java | 8 +- test/langtools/jdk/jshell/InputUITest.java | 8 +- .../langtools/jdk/jshell/JLCollisionTest.java | 10 +- .../langtools/jdk/jshell/JShellQueryTest.java | 18 ++- .../jdk/jshell/JShellStateClosedTest.java | 21 ++- test/langtools/jdk/jshell/JavadocTest.java | 10 +- ...diBadOptionLaunchExecutionControlTest.java | 12 +- ...diBadOptionListenExecutionControlTest.java | 12 +- ...diBogusHostListenExecutionControlTest.java | 12 +- .../JdiFailingLaunchExecutionControlTest.java | 12 +- .../JdiFailingListenExecutionControlTest.java | 12 +- .../JdiHangingLaunchExecutionControlTest.java | 10 +- .../JdiHangingListenExecutionControlTest.java | 10 +- .../JdiLaunchingExecutionControlTest.java | 10 +- .../JdiListeningExecutionControlTest.java | 10 +- ...isteningLocalhostExecutionControlTest.java | 10 +- test/langtools/jdk/jshell/JdiStarterTest.java | 18 +-- .../jshell/KullaCompletenessStressTest.java | 22 +-- test/langtools/jdk/jshell/KullaTesting.java | 150 +++++++++--------- .../jshell/LocalExecutionClassPathTest.java | 8 +- ...LocalExecutionContextLoaderParentTest.java | 12 +- .../jdk/jshell/LocalExecutionTestSupport.java | 6 +- .../jdk/jshell/LocalStopExecutionTest.java | 12 +- test/langtools/jdk/jshell/MethodsTest.java | 49 ++++-- test/langtools/jdk/jshell/ModifiersTest.java | 23 ++- .../jdk/jshell/MultipleDocumentationTest.java | 12 +- .../jdk/jshell/MyExecutionControl.java | 4 +- test/langtools/jdk/jshell/NullTest.java | 8 +- .../jshell/PasteAndMeasurementsUITest.java | 10 +- .../jdk/jshell/PipeInputStreamTest.java | 22 +-- .../jdk/jshell/PrimitiveInstanceOfTest.java | 16 +- test/langtools/jdk/jshell/RecordsTest.java | 20 +-- .../jdk/jshell/RejectedFailedTest.java | 29 ++-- .../langtools/jdk/jshell/ReplToolTesting.java | 21 ++- test/langtools/jdk/jshell/ReplaceTest.java | 29 +++- .../jdk/jshell/SealedClassesTest.java | 12 +- test/langtools/jdk/jshell/ShutdownTest.java | 83 ++++++---- .../jdk/jshell/SimpleRegressionTest.java | 48 ++++-- .../jdk/jshell/SnippetEventToStringTest.java | 18 ++- .../jdk/jshell/SnippetHighlightTest.java | 14 +- .../jdk/jshell/SnippetStatusListenerTest.java | 45 +++--- test/langtools/jdk/jshell/SnippetTest.java | 31 +++- .../langtools/jdk/jshell/SourceLevelTest.java | 14 +- .../langtools/jdk/jshell/StartOptionTest.java | 88 +++++----- .../StartupWithFormatSpecifierTest.java | 8 +- .../jdk/jshell/StopExecutionTest.java | 22 +-- .../jshell/T8146368/JShellTest8146368.java | 8 +- .../T8146368/JShellToolTest8146368.java | 8 +- test/langtools/jdk/jshell/Test8294583.java | 13 +- test/langtools/jdk/jshell/Test8296012.java | 13 +- test/langtools/jdk/jshell/ToolBasicTest.java | 84 +++++++--- .../jdk/jshell/ToolCommandOptionTest.java | 23 ++- .../jdk/jshell/ToolCompletionTest.java | 4 +- .../jshell/ToolEnableNativeAccessTest.java | 9 +- .../jdk/jshell/ToolEnablePreviewTest.java | 9 +- test/langtools/jdk/jshell/ToolFormatTest.java | 42 +++-- .../jdk/jshell/ToolLocalSimpleTest.java | 10 +- .../jdk/jshell/ToolLocaleMessageTest.java | 16 +- .../ToolMultilineSnippetHistoryTest.java | 8 +- .../jdk/jshell/ToolProviderTest.java | 8 +- test/langtools/jdk/jshell/ToolReloadTest.java | 19 ++- test/langtools/jdk/jshell/ToolRetainTest.java | 17 +- .../jdk/jshell/ToolShiftTabTest.java | 13 +- test/langtools/jdk/jshell/ToolSimpleTest.java | 13 +- .../jdk/jshell/ToolTabCommandTest.java | 10 +- .../jdk/jshell/ToolTabSnippetTest.java | 12 +- test/langtools/jdk/jshell/ToolingTest.java | 5 +- test/langtools/jdk/jshell/TypeNameTest.java | 23 ++- test/langtools/jdk/jshell/UITesting.java | 6 +- .../jdk/jshell/UndefinedClassTest.java | 9 +- test/langtools/jdk/jshell/UnicodeTest.java | 13 +- test/langtools/jdk/jshell/UnnamedTest.java | 12 +- .../jdk/jshell/UserExecutionControlTest.java | 18 +-- test/langtools/jdk/jshell/UserInputTest.java | 12 +- .../jdk/jshell/UserJdiUserRemoteTest.java | 22 +-- test/langtools/jdk/jshell/VariablesTest.java | 71 +++++++-- test/langtools/jdk/jshell/WrapperTest.java | 72 +++++---- 123 files changed, 1553 insertions(+), 1029 deletions(-) diff --git a/test/langtools/jdk/jshell/AbstractStopExecutionTest.java b/test/langtools/jdk/jshell/AbstractStopExecutionTest.java index c38549b5128..7fca7d75d5e 100644 --- a/test/langtools/jdk/jshell/AbstractStopExecutionTest.java +++ b/test/langtools/jdk/jshell/AbstractStopExecutionTest.java @@ -26,7 +26,7 @@ import java.io.StringWriter; import jdk.jshell.JShell; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; public abstract class AbstractStopExecutionTest extends KullaTesting { diff --git a/test/langtools/jdk/jshell/AnalysisTest.java b/test/langtools/jdk/jshell/AnalysisTest.java index f6cd5bf9efb..478301f3fd5 100644 --- a/test/langtools/jdk/jshell/AnalysisTest.java +++ b/test/langtools/jdk/jshell/AnalysisTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ * @test * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream - * @run testng AnalysisTest + * @run junit AnalysisTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class AnalysisTest extends KullaTesting { + @Test public void testSource() { assertAnalyze("int x=3//test", "int x=3;//test", "", true); assertAnalyze("int x=3 ;//test", "int x=3 ;//test", "", true); @@ -41,6 +41,7 @@ public class AnalysisTest extends KullaTesting { assertAnalyze("int ff; int v // hi", "int ff;", " int v // hi", true); } + @Test public void testSourceSlashStar() { assertAnalyze("/*zoo*/int x=3 /*test*/", "/*zoo*/int x=3; /*test*/", "", true); assertAnalyze("/*zoo*/int x=3 ;/*test*/", "/*zoo*/int x=3 ;/*test*/", "", true); @@ -49,11 +50,13 @@ public class AnalysisTest extends KullaTesting { assertAnalyze("int ff; int v /*hgjghj*/", "int ff;", " int v /*hgjghj*/", true); } + @Test public void testIncomplete() { assertAnalyze("void m() { //erer", null, "void m() { //erer\n", false); assertAnalyze("int m=//", null, "int m=//\n", false); } + @Test public void testExpression() { assertAnalyze("45//test", "45//test", "", true); assertAnalyze("45;//test", "45;//test", "", true); diff --git a/test/langtools/jdk/jshell/AnalyzeSnippetTest.java b/test/langtools/jdk/jshell/AnalyzeSnippetTest.java index a9b0315e960..3b93e68f03d 100644 --- a/test/langtools/jdk/jshell/AnalyzeSnippetTest.java +++ b/test/langtools/jdk/jshell/AnalyzeSnippetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8182270 8341176 * @summary test non-eval Snippet analysis * @build KullaTesting TestingInputStream - * @run testng AnalyzeSnippetTest + * @run junit AnalyzeSnippetTest */ import java.io.ByteArrayOutputStream; @@ -36,15 +36,12 @@ import java.util.stream.Stream; import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; import jdk.jshell.Diag; -import org.testng.annotations.Test; import jdk.jshell.JShell; import jdk.jshell.MethodSnippet; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import jdk.jshell.ErroneousSnippet; import jdk.jshell.ExpressionSnippet; import jdk.jshell.ImportSnippet; @@ -55,14 +52,16 @@ import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.SubKind.*; import jdk.jshell.SourceCodeAnalysis.SnippetWrapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class AnalyzeSnippetTest { JShell state; SourceCodeAnalysis sca; - @BeforeMethod + @BeforeEach public void setUp() { state = JShell.builder() .out(new PrintStream(new ByteArrayOutputStream())) @@ -72,7 +71,7 @@ public class AnalyzeSnippetTest { sca = state.sourceCodeAnalysis(); } - @AfterMethod + @AfterEach public void tearDown() { if (state != null) { state.close(); @@ -81,55 +80,61 @@ public class AnalyzeSnippetTest { sca = null; } + @Test public void testImport() { ImportSnippet sn = (ImportSnippet) assertSnippet("import java.util.List;", SubKind.SINGLE_TYPE_IMPORT_SUBKIND); - assertEquals(sn.name(), "List"); + assertEquals("List", sn.name()); sn = (ImportSnippet) assertSnippet("import static java.nio.file.StandardOpenOption.CREATE;", SubKind.SINGLE_STATIC_IMPORT_SUBKIND); assertTrue(sn.isStatic()); } + @Test public void testClass() { TypeDeclSnippet sn = (TypeDeclSnippet) assertSnippet("class C {}", SubKind.CLASS_SUBKIND); - assertEquals(sn.name(), "C"); + assertEquals("C", sn.name()); sn = (TypeDeclSnippet) assertSnippet("enum EE {A, B , C}", SubKind.ENUM_SUBKIND); } + @Test public void testMethod() { MethodSnippet sn = (MethodSnippet) assertSnippet("int m(int x) { return x + x; }", SubKind.METHOD_SUBKIND); - assertEquals(sn.name(), "m"); - assertEquals(sn.signature(), "(int)int"); + assertEquals("m", sn.name()); + assertEquals("(int)int", sn.signature()); } + @Test public void testVar() { VarSnippet sn = (VarSnippet) assertSnippet("int i;", SubKind.VAR_DECLARATION_SUBKIND); - assertEquals(sn.name(), "i"); - assertEquals(sn.typeName(), "int"); + assertEquals("i", sn.name()); + assertEquals("int", sn.typeName()); sn = (VarSnippet) assertSnippet("int jj = 6;", SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND); sn = (VarSnippet) assertSnippet("2 + 2", SubKind.TEMP_VAR_EXPRESSION_SUBKIND); } + @Test public void testExpression() { state.eval("int aa = 10;"); ExpressionSnippet sn = (ExpressionSnippet) assertSnippet("aa", SubKind.VAR_VALUE_SUBKIND); - assertEquals(sn.name(), "aa"); - assertEquals(sn.typeName(), "int"); + assertEquals("aa", sn.name()); + assertEquals("int", sn.typeName()); sn = (ExpressionSnippet) assertSnippet("aa;", SubKind.VAR_VALUE_SUBKIND); - assertEquals(sn.name(), "aa"); - assertEquals(sn.typeName(), "int"); + assertEquals("aa", sn.name()); + assertEquals("int", sn.typeName()); sn = (ExpressionSnippet) assertSnippet("aa = 99", SubKind.ASSIGNMENT_SUBKIND); } + @Test public void testStatement() { StatementSnippet sn = (StatementSnippet) assertSnippet("System.out.println(33)", SubKind.STATEMENT_SUBKIND); @@ -137,6 +142,7 @@ public class AnalyzeSnippetTest { SubKind.STATEMENT_SUBKIND); } + @Test public void testErroneous() { ErroneousSnippet sn = (ErroneousSnippet) assertSnippet("+++", SubKind.UNKNOWN_SUBKIND); @@ -144,6 +150,7 @@ public class AnalyzeSnippetTest { SubKind.UNKNOWN_SUBKIND); } + @Test public void testDiagnosticsForSourceSnippet() { Snippet sn; sn = assertSnippet("unknown()", UNKNOWN_SUBKIND); @@ -164,6 +171,7 @@ public class AnalyzeSnippetTest { assertDiagnostics(sn, "7-22:compiler.err.doesnt.exist"); } + @Test public void testSnippetWrapper() { SourceCodeAnalysis analysis = state.sourceCodeAnalysis(); Snippet sn; @@ -171,38 +179,39 @@ public class AnalyzeSnippetTest { sn = assertSnippet(code, UNKNOWN_SUBKIND); SnippetWrapper wrapper = analysis.wrapper(sn); String wrapped = wrapper.wrapped(); - assertEquals(wrapped, """ - package REPL; + assertEquals(""" + package REPL; - class $JShell$DOESNOTMATTER { - public static java.lang.Object do_it$() throws java.lang.Throwable { - return unknown(); - } - } - """); + class $JShell$DOESNOTMATTER { + public static java.lang.Object do_it$() throws java.lang.Throwable { + return unknown(); + } + } + """, wrapped); for (int pos = 0; pos < code.length(); pos++) { int wrappedPos = wrapper.sourceToWrappedPosition(pos); - assertEquals(wrapped.charAt(wrappedPos), code.charAt(pos)); - assertEquals(wrapper.wrappedToSourcePosition(wrappedPos), pos); + assertEquals(code.charAt(pos), wrapped.charAt(wrappedPos)); + assertEquals(pos, wrapper.wrappedToSourcePosition(wrappedPos)); } } + @Test public void testNoStateChange() { assertSnippet("int a = 5;", SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND); assertSnippet("a", SubKind.UNKNOWN_SUBKIND); VarSnippet vsn = (VarSnippet) state.eval("int aa = 10;").get(0).snippet(); assertSnippet("++aa;", SubKind.TEMP_VAR_EXPRESSION_SUBKIND); - assertEquals(state.varValue(vsn), "10"); + assertEquals("10", state.varValue(vsn)); assertSnippet("class CC {}", SubKind.CLASS_SUBKIND); assertSnippet("new CC();", SubKind.UNKNOWN_SUBKIND); } private Snippet assertSnippet(String input, SubKind sk) { List sns = sca.sourceToSnippets(input); - assertEquals(sns.size(), 1, "snippet count"); + assertEquals(1, sns.size(), "snippet count"); Snippet sn = sns.get(0); - assertEquals(sn.id(), "*UNASSOCIATED*"); - assertEquals(sn.subKind(), sk); + assertEquals("*UNASSOCIATED*", sn.id()); + assertEquals(sk, sn.subKind()); return sn; } @@ -213,6 +222,6 @@ public class AnalyzeSnippetTest { private void assertDiagnostics(Snippet s, String... expectedDiags) { List actual = state.diagnostics(s).map(this::diagToString).toList(); List expected = List.of(expectedDiags); - assertEquals(actual, expected); + assertEquals(expected, actual); } } diff --git a/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java b/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java index a4f4158a5c7..f7b34a0e194 100644 --- a/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java +++ b/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool - * @run testng BadExecutionControlSpecTest + * @run junit BadExecutionControlSpecTest */ import java.io.ByteArrayInputStream; @@ -38,12 +38,11 @@ import java.io.InputStream; import java.io.PrintStream; import java.util.Collections; import java.util.List; -import org.testng.annotations.Test; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionEnv; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class BadExecutionControlSpecTest { private static void assertIllegal(String spec) throws Throwable { try { @@ -80,6 +79,7 @@ public class BadExecutionControlSpecTest { } } + @Test public void syntaxTest() throws Throwable { assertIllegal(":launch(true)"); assertIllegal("jdi:launch(true"); @@ -87,6 +87,7 @@ public class BadExecutionControlSpecTest { assertIllegal("jdi:,"); } + @Test public void notFoundTest() throws Throwable { assertIllegal("fruitbats"); assertIllegal("jdi:baz(true)"); diff --git a/test/langtools/jdk/jshell/ClassMembersTest.java b/test/langtools/jdk/jshell/ClassMembersTest.java index 25360770ab3..6e188e7b8eb 100644 --- a/test/langtools/jdk/jshell/ClassMembersTest.java +++ b/test/langtools/jdk/jshell/ClassMembersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8139829 * @summary Test access to members of user defined class. * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng/timeout=600 ClassMembersTest + * @run junit/timeout=600 ClassMembersTest */ import java.lang.annotation.RetentionPolicy; @@ -36,22 +36,26 @@ import java.util.List; import javax.tools.Diagnostic; import jdk.jshell.SourceCodeAnalysis; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import jdk.jshell.TypeDeclSnippet; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ClassMembersTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("local")); } - @Test(dataProvider = "memberTestCase") + @ParameterizedTest + @MethodSource("memberTestCaseGenerator") public void memberTest(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) { MemberTestCase testCase = new MemberTestCase(accessModifier, codeChunk, isStaticMember, isStaticReference); assertEval(testCase.generateSource()); @@ -78,7 +82,8 @@ public class ClassMembersTest extends KullaTesting { return list; } - @Test(dataProvider = "memberTestCase") + @ParameterizedTest + @MethodSource("memberTestCaseGenerator") public void extendsMemberTest(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) { MemberTestCase testCase = new ExtendsMemberTestCase(accessModifier, codeChunk, isStaticMember, isStaticReference); String input = testCase.generateSource(); @@ -151,7 +156,8 @@ public class ClassMembersTest extends KullaTesting { new ExpectedDiagnostic("compiler.err.non-static.cant.be.ref", 0, 8, 1, -1, -1, Diagnostic.Kind.ERROR)); } - @Test(dataProvider = "retentionPolicyTestCase") + @ParameterizedTest + @MethodSource("retentionPolicyTestCaseGenerator") public void annotationTest(RetentionPolicy policy) { assertEval("import java.lang.annotation.*;"); String annotationSource = @@ -174,7 +180,6 @@ public class ClassMembersTest extends KullaTesting { assertEval("C.Inner.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); } - @DataProvider(name = "retentionPolicyTestCase") public Object[][] retentionPolicyTestCaseGenerator() { List list = new ArrayList<>(); for (RetentionPolicy policy : RetentionPolicy.values()) { @@ -183,7 +188,6 @@ public class ClassMembersTest extends KullaTesting { return list.toArray(new Object[list.size()][]); } - @DataProvider(name = "memberTestCase") public Object[][] memberTestCaseGenerator() { List list = new ArrayList<>(); for (AccessModifier accessModifier : AccessModifier.values()) { diff --git a/test/langtools/jdk/jshell/ClassPathTest.java b/test/langtools/jdk/jshell/ClassPathTest.java index b9c86274389..6c2320ffac2 100644 --- a/test/langtools/jdk/jshell/ClassPathTest.java +++ b/test/langtools/jdk/jshell/ClassPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +30,20 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng ClassPathTest + * @run junit ClassPathTest */ import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ClassPathTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("class_path_test"); + @Test public void testDirectory() { compiler.compile(outDir, "package pkg; public class TestDirectory { }"); assertDeclareFail("import pkg.TestDirectory;", "compiler.err.doesnt.exist"); @@ -52,6 +52,7 @@ public class ClassPathTest extends KullaTesting { assertEval("new pkg.TestDirectory();"); } + @Test public void testJar() { compiler.compile(outDir, "package pkg; public class TestJar { }"); String jarName = "test.jar"; @@ -62,6 +63,7 @@ public class ClassPathTest extends KullaTesting { assertEval("new pkg.TestJar();"); } + @Test public void testAmbiguousDirectory() { Path p1 = outDir.resolve("dir1"); compiler.compile(p1, @@ -82,6 +84,7 @@ public class ClassPathTest extends KullaTesting { assertEval("new p.TestAmbiguous();", "first"); } + @Test public void testAmbiguousJar() { Path p1 = outDir.resolve("dir1"); compiler.compile(p1, @@ -104,11 +107,13 @@ public class ClassPathTest extends KullaTesting { assertEval("new p.TestAmbiguous();", "first"); } + @Test public void testEmptyClassPath() { addToClasspath(""); assertEval("new java.util.ArrayList();"); } + @Test public void testUnknown() { addToClasspath(compiler.getPath(outDir.resolve("UNKNOWN"))); assertDeclareFail("new Unknown();", "compiler.err.cant.resolve.location"); diff --git a/test/langtools/jdk/jshell/ClassesTest.java b/test/langtools/jdk/jshell/ClassesTest.java index 3da389e5059..85f85e69c94 100644 --- a/test/langtools/jdk/jshell/ClassesTest.java +++ b/test/langtools/jdk/jshell/ClassesTest.java @@ -26,7 +26,7 @@ * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456 8282160 8292755 8319532 * @summary Tests for EvaluationState.classes * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng/timeout=480 ClassesTest + * @run junit/timeout=480 ClassesTest */ import java.util.ArrayList; @@ -37,8 +37,6 @@ import javax.tools.Diagnostic; import jdk.jshell.Snippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import jdk.jshell.Diag; import jdk.jshell.Snippet.Status; @@ -51,16 +49,22 @@ import static jdk.jshell.Snippet.Status.REJECTED; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.SubKind.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ClassesTest extends KullaTesting { + @Test public void noClasses() { assertNumberOfActiveClasses(0); } + @Test public void testSignature1() { TypeDeclSnippet c1 = classKey(assertEval("class A extends B {}", added(RECOVERABLE_NOT_DEFINED))); assertTypeDeclSnippet(c1, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0); @@ -82,6 +86,7 @@ public class ClassesTest extends KullaTesting { assertTypeDeclSnippet(c5, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0); } + @Test public void testSignature2() { TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req"); assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2); @@ -92,27 +97,32 @@ public class ClassesTest extends KullaTesting { ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null)); } + @Test public void classDeclaration() { assertEval("class A { }"); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); } + @Test public void interfaceDeclaration() { assertEval("interface A { }"); assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A")); } + @Test public void annotationDeclaration() { assertEval("@interface A { }"); assertClasses(clazz(KullaTesting.ClassType.ANNOTATION, "A")); } + @Test public void enumDeclaration() { assertEval("enum A { }"); assertClasses(clazz(KullaTesting.ClassType.ENUM, "A")); } + @Test public void classesDeclaration() { assertEval("interface A { }"); assertEval("class B implements A { }"); @@ -128,6 +138,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesRedeclaration1() { Snippet a = classKey(assertEval("class A { }")); Snippet b = classKey(assertEval("interface B { }")); @@ -149,6 +160,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesRedeclaration2() { assertEval("class A { }"); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); @@ -180,6 +192,7 @@ public class ClassesTest extends KullaTesting { } //8154496: test3 update: sig change should false + @Test public void classesRedeclaration3() { Snippet a = classKey(assertEval("class A { }")); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); @@ -201,6 +214,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesCyclic1() { Snippet b = classKey(assertEval("class B extends A { }", added(RECOVERABLE_NOT_DEFINED))); @@ -221,11 +235,12 @@ public class ClassesTest extends KullaTesting { diags = diagsA; assertTrue(diagsB.isEmpty()); } - assertEquals(diags.size(), 1, "Expected one error"); - assertEquals(diags.get(0).getCode(), "compiler.err.cyclic.inheritance", "Expected cyclic inheritance error"); + assertEquals(1, diags.size(), "Expected one error"); + assertEquals("compiler.err.cyclic.inheritance", diags.get(0).getCode(), "Expected cyclic inheritance error"); assertActiveKeys(); } + @Test public void classesCyclic2() { Snippet d = classKey(assertEval("class D extends E { }", added(RECOVERABLE_NOT_DEFINED))); assertEval("class E { D d; }", @@ -234,6 +249,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesCyclic3() { Snippet outer = classKey(assertEval("class Outer { class Inner extends Foo { } }", added(RECOVERABLE_NOT_DEFINED))); @@ -247,6 +263,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesIgnoredModifiers() { assertEval("public interface A { }"); assertEval("static class B implements A { }"); @@ -254,6 +271,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesIgnoredModifiersAnnotation() { assertEval("public @interface X { }"); assertEval("@X public interface A { }"); @@ -262,6 +280,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesIgnoredModifiersOtherModifiers() { assertEval("strictfp public interface A { }"); assertEval("strictfp static class B implements A { }"); @@ -269,6 +288,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void ignoreModifierSpaceIssue() { assertEval("interface I { void f(); } "); // there should not be a space between 'I' and '{' to reproduce the failure @@ -277,7 +297,6 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } - @DataProvider(name = "innerClasses") public Object[][] innerClasses() { List list = new ArrayList<>(); for (ClassType outerClassType : ClassType.values()) { @@ -288,7 +307,8 @@ public class ClassesTest extends KullaTesting { return list.toArray(new Object[list.size()][]); } - @Test(dataProvider = "innerClasses") + @ParameterizedTest + @MethodSource("innerClasses") public void innerClasses(ClassType outerClassType, ClassType innerClassType) { String source = outerClassType + " A {" + (outerClassType == ClassType.ENUM ? ";" : "") + @@ -299,6 +319,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void testInnerClassesCrash() { Snippet a = classKey(assertEval("class A { class B extends A {} }")); Snippet a2 = classKey(assertEval("class A { interface I1 extends I2 {} interface I2 {} }", @@ -309,20 +330,23 @@ public class ClassesTest extends KullaTesting { ste(a2, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); } + @Test public void testInnerClassesCrash1() { assertEval("class A { class B extends A {} B getB() { return new B();} }"); - assertEquals(varKey(assertEval("A a = new A();")).name(), "a"); + assertEquals("a", varKey(assertEval("A a = new A();")).name()); VarSnippet variableKey = varKey(assertEval("a.getB();")); - assertEquals(variableKey.typeName(), "A.B"); + assertEquals("A.B", variableKey.typeName()); } + @Test public void testInnerClassesCrash2() { assertEval("class A { interface I1 extends I2 {} interface I2 {} I1 x; }"); - assertEquals(varKey(assertEval("A a = new A();")).name(), "a"); + assertEquals("a", varKey(assertEval("A a = new A();")).name()); VarSnippet variableKey = varKey(assertEval("a.x;")); - assertEquals(variableKey.typeName(), "A.I1"); + assertEquals("A.I1", variableKey.typeName()); } + @Test public void testCircular() { assertEval("import java.util.function.Supplier;"); TypeDeclSnippet aClass = @@ -342,6 +366,7 @@ public class ClassesTest extends KullaTesting { assertEval("new A()"); } + @Test public void testCircular8282160() { TypeDeclSnippet classKey = classKey(assertEval(""" class B { @@ -360,6 +385,7 @@ public class ClassesTest extends KullaTesting { ste(classKey, Status.RECOVERABLE_NOT_DEFINED, Status.VALID, true, null)); } + @Test public void testDefaultMethodInInterface() { assertEvalFail(""" interface C { @@ -374,6 +400,7 @@ public class ClassesTest extends KullaTesting { """); } + @Test public void testNonSealed() { assertAnalyze("non-sealed class C extends B {}int i;", "non-sealed class C extends B {}", diff --git a/test/langtools/jdk/jshell/CommandCompletionTest.java b/test/langtools/jdk/jshell/CommandCompletionTest.java index 3a818a74e1e..ef02e135973 100644 --- a/test/langtools/jdk/jshell/CommandCompletionTest.java +++ b/test/langtools/jdk/jshell/CommandCompletionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build ReplToolTesting TestingInputStream Compiler - * @run testng CommandCompletionTest + * @run junit CommandCompletionTest */ import java.io.IOException; @@ -46,16 +46,16 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.SkipException; -import org.testng.annotations.Test; import jdk.internal.jshell.tool.JShellTool; import jdk.internal.jshell.tool.JShellToolBuilder; import jdk.jshell.SourceCodeAnalysis.Suggestion; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; public class CommandCompletionTest extends ReplToolTesting { @@ -94,7 +94,7 @@ public class CommandCompletionTest extends ReplToolTesting { public void assertCompletion(String code, boolean isSmart, String... expected) { List completions = computeCompletions(code, isSmart); List expectedL = Arrays.asList(expected); - assertEquals(completions, expectedL, "Command: " + code + ", output: " + + assertEquals(expectedL, completions, "Command: " + code + ", output: " + completions.toString() + ", expected: " + expectedL.toString()); } @@ -356,9 +356,7 @@ public class CommandCompletionTest extends ReplToolTesting { .map(file -> file.getFileName().toString().replace(" ", "\\ ")) .orElse(null); } - if (selectedFile == null) { - throw new SkipException("No suitable file(s) found for this test in " + home); - } + Assumptions.assumeFalse(selectedFile == null, "No suitable file(s) found for this test in " + home); try (Stream content = Files.list(home)) { completions = content.filter(CLASSPATH_FILTER) .filter(file -> file.getFileName().toString().startsWith(selectedFile.replace("\\ ", " "))) diff --git a/test/langtools/jdk/jshell/CompilerOptionsTest.java b/test/langtools/jdk/jshell/CompilerOptionsTest.java index 1b4f5a8002d..e4c9332d5aa 100644 --- a/test/langtools/jdk/jshell/CompilerOptionsTest.java +++ b/test/langtools/jdk/jshell/CompilerOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,28 +26,29 @@ * @bug 8159635 * @summary Test setting compiler options * @build KullaTesting TestingInputStream - * @run testng CompilerOptionsTest + * @run junit CompilerOptionsTest */ import javax.tools.Diagnostic; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class CompilerOptionsTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(b -> b.compilerOptions("-source", "8", "-Xlint:cast,-options")); } + @Test public void testLint() { assertDeclareWarn1("String s = (String)\"hello\";", new ExpectedDiagnostic("compiler.warn.redundant.cast", 11, 26, 11, -1, -1, Diagnostic.Kind.WARNING)); } + @Test public void testSourceVersion() { assertEval("import java.util.ArrayList;", added(VALID)); // Diamond with anonymous classes allowed in 9 diff --git a/test/langtools/jdk/jshell/CompletenessStressTest.java b/test/langtools/jdk/jshell/CompletenessStressTest.java index 167ba716b10..4b20ae93d46 100644 --- a/test/langtools/jdk/jshell/CompletenessStressTest.java +++ b/test/langtools/jdk/jshell/CompletenessStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import com.sun.tools.javac.api.JavacTaskImpl; import jdk.jshell.SourceCodeAnalysis; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.Integer.max; import static java.lang.Integer.min; import static jdk.jshell.SourceCodeAnalysis.Completeness.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class CompletenessStressTest extends KullaTesting { public final static String JDK_ROOT_SRC_PROP = "jdk.root.src"; @@ -99,7 +99,6 @@ public class CompletenessStressTest extends KullaTesting { }; } - @DataProvider(name = "crawler") public Object[][] dataProvider() throws IOException { File[] srcDirs = getDirectoriesToTest(); List list = new ArrayList<>(); @@ -121,7 +120,8 @@ public class CompletenessStressTest extends KullaTesting { return list.toArray(new String[list.size()][]); } - @Test(dataProvider = "crawler") + @ParameterizedTest + @MethodSource("dataProvider") public void testFile(String fileName) throws IOException { File file = getSourceFile(fileName); final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); diff --git a/test/langtools/jdk/jshell/CompletenessTest.java b/test/langtools/jdk/jshell/CompletenessTest.java index c9fc5dc08c3..1d57aef8210 100644 --- a/test/langtools/jdk/jshell/CompletenessTest.java +++ b/test/langtools/jdk/jshell/CompletenessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 8223782 8235474 8246774 8276149 * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream - * @run testng CompletenessTest + * @run junit CompletenessTest */ import java.util.Map; @@ -35,13 +35,11 @@ import java.util.function.Consumer; import javax.lang.model.SourceVersion; import jdk.jshell.JShell; -import org.testng.annotations.Test; import jdk.jshell.SourceCodeAnalysis.Completeness; import static jdk.jshell.SourceCodeAnalysis.Completeness.*; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.Test; -@Test public class CompletenessTest extends KullaTesting { // Add complete units that end with semicolon to complete_with_semi (without @@ -278,30 +276,37 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void test_complete() { assertStatus(complete, COMPLETE); } + @Test public void test_expression() { assertStatus(expression, COMPLETE); } + @Test public void test_complete_with_semi() { assertStatus(complete_with_semi, COMPLETE_WITH_SEMI); } + @Test public void test_considered_incomplete() { assertStatus(considered_incomplete, CONSIDERED_INCOMPLETE); } + @Test public void test_definitely_incomplete() { assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); } + @Test public void test_unknown() { assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); } + @Test public void testCompleted_complete_with_semi() { for (String in : complete_with_semi) { String input = in + ";"; @@ -309,6 +314,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleted_expression_with_semi() { for (String in : expression) { String input = in + ";"; @@ -316,6 +322,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleted_considered_incomplete() { for (String in : considered_incomplete) { String input = in + ";"; @@ -332,12 +339,14 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleteSource_complete() { for (String input : complete) { assertSourceByStatus(input); } } + @Test public void testCompleteSource_complete_with_semi() { for (String in : complete_with_semi) { String input = in + ";"; @@ -345,6 +354,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleteSource_expression() { for (String in : expression) { String input = in + ";"; @@ -352,6 +362,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleteSource_considered_incomplete() { for (String in : considered_incomplete) { String input = in + ";"; @@ -359,15 +370,18 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testTrailingSlash() { assertStatus("\"abc\\", UNKNOWN, "\"abc\\"); } + @Test public void testOpenComment() { assertStatus("int xx; /* hello", DEFINITELY_INCOMPLETE, null); assertStatus("/** test", DEFINITELY_INCOMPLETE, null); } + @Test public void testTextBlocks() { assertStatus("\"\"\"", DEFINITELY_INCOMPLETE, null); assertStatus("\"\"\"broken", DEFINITELY_INCOMPLETE, null); @@ -382,6 +396,7 @@ public class CompletenessTest extends KullaTesting { assertStatus("\"\"\"\n\\", DEFINITELY_INCOMPLETE, null); } + @Test public void testMiscSource() { assertStatus("if (t) if ", DEFINITELY_INCOMPLETE, "if (t) if"); //Bug assertStatus("int m() {} dfd", COMPLETE, "int m() {}"); @@ -390,6 +405,7 @@ public class CompletenessTest extends KullaTesting { "int[] m = {1, 2}, n = new int[0];"); } + @Test public void testInstanceOf() { assertStatus("i instanceof Integer", COMPLETE, "i instanceof Integer"); assertStatus("i instanceof int", COMPLETE, "i instanceof int"); diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index cfbe874e6f2..a710f60aec4 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -32,7 +32,7 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng/timeout=480 CompletionSuggestionTest + * @run junit/timeout=480 CompletionSuggestionTest */ import java.io.IOException; @@ -51,20 +51,21 @@ import java.util.jar.JarOutputStream; import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class CompletionSuggestionTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("completion_suggestion_test"); + @Test public void testMemberExpr() { assertEval("class Test { static void test() { } }"); assertCompletion("Test.t|", "test()"); @@ -114,16 +115,19 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("\"\"\"\n\"\"\".leng|", "length()"); } + @Test public void testStartOfExpression() { assertEval("int ccTest = 0;"); assertCompletion("System.err.println(cc|", "ccTest"); assertCompletion("for (int i = cc|", "ccTest"); } + @Test public void testParameter() { assertCompletion("class C{void method(int num){num|", "num"); } + @Test public void testPrimitive() { Set primitives = new HashSet<>(Arrays.asList("boolean", "char", "byte", "short", "int", "long", "float", "double")); Set onlyVoid = new HashSet<>(Collections.singletonList("void")); @@ -157,6 +161,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("class A(Arrays.asList("Object", "Void")), @@ -169,6 +174,7 @@ public class CompletionSuggestionTest extends KullaTesting { new HashSet<>(Arrays.asList("$REPL00DOESNOTMATTER"))); } + @Test public void testSmartCompletion() { assertEval("int ccTest1 = 0;"); assertEval("int ccTest2 = 0;"); @@ -201,6 +207,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("new Klass(|", true, "ccTest1", "ccTest2"); } + @Test public void testSmartCompletionInOverriddenMethodInvocation() { assertEval("int ccTest1 = 0;"); assertEval("int ccTest2 = 0;"); @@ -211,6 +218,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("new Extend().method(|", true, "ccTest1", "ccTest2"); } + @Test public void testSmartCompletionForBoxedType() { assertEval("int ccTest1 = 0;"); assertEval("Integer ccTest2 = 0;"); @@ -226,6 +234,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("method3(|", true, "ccTest1", "ccTest2", "ccTest3", "method1(", "method2(", "method3("); } + @Test public void testNewClass() { assertCompletion("String str = new Strin|", "String(", "StringBuffer(", "StringBuilder(", "StringIndexOutOfBoundsException("); assertCompletion("String str = new java.lang.Strin|", "String(", "StringBuffer(", "StringBuilder(", "StringIndexOutOfBoundsException("); @@ -246,6 +255,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("new String(I.A|", "A"); } + @Test public void testFullyQualified() { assertCompletion("Optional opt = java.u|", "util."); assertCompletionIncludesExcludes("Optional opt = java.util.O|", new HashSet<>(Collections.singletonList("Optional")), Collections.emptySet()); @@ -274,15 +284,18 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("p1.p3.|", "Test"); } + @Test public void testCheckAccessibility() { assertCompletion("java.util.regex.Pattern.co|", "compile("); } + @Test public void testCompletePackages() { assertCompletion("java.u|", "util."); assertCompletionIncludesExcludes("jav|", new HashSet<>(Arrays.asList("java.", "javax.")), Collections.emptySet()); } + @Test public void testImports() { assertCompletion("import java.u|", "util."); assertCompletionIncludesExcludes("import jav|", new HashSet<>(Arrays.asList("java.", "javax.")), Collections.emptySet()); @@ -301,10 +314,12 @@ public class CompletionSuggestionTest extends KullaTesting { new HashSet<>(Arrays.asList("class"))); } + @Test public void testImportStart() { assertCompletionIncludesExcludes("import c|", Set.of("com."), Set.of()); } + @Test public void testBrokenClassFile() throws Exception { Compiler compiler = new Compiler(); Path testOutDir = Paths.get("CompletionTestBrokenClassFile"); @@ -314,6 +329,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("import inner.|"); } + @Test public void testDocumentation() throws Exception { dontReadParameterNamesFromClassFile(); assertSignature("System.getProperty(|", @@ -342,6 +358,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("field.FieldTest.R|", "field.FieldTest.R(java.lang.String s, E e)"); } + @Test public void testMethodsWithNoArguments() throws Exception { dontReadParameterNamesFromClassFile(); assertSignature("System.out.println(|", @@ -357,11 +374,13 @@ public class CompletionSuggestionTest extends KullaTesting { "void java.io.PrintStream.println(Object)"); } + @Test public void testErroneous() { assertCompletion("Undefined.|"); assertSignature("does.not.exist|"); } + @Test public void testClinit() { assertEval("enum E{;}"); assertEval("class C{static{}}"); @@ -369,6 +388,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletionIncludesExcludes("C.|", Collections.emptySet(), new HashSet<>(Collections.singletonList(""))); } + @Test public void testMethodHeaderContext() { assertCompletion("private void f(Runn|", "Runnable"); assertCompletion("void f(Runn|", "Runnable"); @@ -380,6 +400,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("void f(Object o1) throws HogeHoge.|", true, "HogeHogeException"); } + @Test public void testTypeVariables() { assertCompletion("class A { public void test() { TY|", "TYPE"); assertCompletion("class A { public static void test() { TY|"); @@ -387,6 +408,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("class A { public static void test() { TY|", "TYPE"); } + @Test public void testGeneric() { assertEval("import java.util.concurrent.*;"); assertCompletion("java.util.Listf(T... ts)", "void f(A a)"); } + @Test public void testClass() { assertSignature("String|", "java.lang.String"); } + @Test public void testDocumentationOfUserDefinedConstructors() { Snippet a = classKey(assertEval("class A {}")); assertSignature("new A(|", "A()"); @@ -522,6 +550,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("new A(|", "A(T a)", "A(int i)", " A(T t, U u)"); } + @Test public void testDocumentationOfOverriddenMethods() throws Exception { dontReadParameterNamesFromClassFile(); assertSignature("\"\".wait(|", @@ -537,6 +566,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("new Extend().method(|", "void Extend.method()"); } + @Test public void testDocumentationOfInvisibleMethods() { assertSignature("Object.wait(|"); assertSignature("\"\".indexOfSupplementary(|"); @@ -548,12 +578,14 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("new A().method(|"); } + @Test public void testDocumentationOfInvisibleConstructors() { assertSignature("new Compiler(|"); assertEval("class A { private A() {} }"); assertSignature("new A(|"); } + @Test public void testDocumentationWithBoxing() { assertEval("int primitive = 0;"); assertEval("Integer boxed = 0;"); @@ -570,6 +602,7 @@ public class CompletionSuggestionTest extends KullaTesting { "void method(Object n, int o)"); } + @Test public void testDocumentationWithGenerics() { class TestDocumentationWithGenerics { private final Function codeFacotry; @@ -624,6 +657,7 @@ public class CompletionSuggestionTest extends KullaTesting { }); } + @Test public void testVarArgs() { assertEval("int i = 0;"); assertEval("class Foo1 { static void m(int... i) { } } "); @@ -649,6 +683,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Foo4.m(ia, |", true, "str"); } + @Test public void testConstructorAsMemberOf() { assertEval("class Baz { Baz(X x) { } } "); assertEval("String str = null;"); @@ -660,6 +695,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Foo.m(new Baz<>(|", true, "str"); } + @Test public void testIntersection() { assertEval(" Z get() { return null; }"); assertEval("var v = get();"); @@ -669,6 +705,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Number r = |", true); } + @Test public void testAnonymous() { assertEval("var v = new Runnable() { public void run() { } public int length() { return 0; } };"); assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of()); @@ -676,10 +713,12 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("CharSequence r = |", true); } + @Test public void testCompletionInAnonymous() { assertCompletionIncludesExcludes("new Undefined() { int i = \"\".l|", Set.of("length()"), Set.of()); } + @Test public void testMemberReferences() { assertEval("class C {" + " public static String stat() { return null; }" + @@ -703,6 +742,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("FI2 fi = C::|", true, "statConvert1", "statConvert3"); } + @Test public void testBrokenLambdaCompletion() { assertEval("interface Consumer { public void consume(T t); }"); assertEval("interface Function { public R convert(T t); }"); @@ -724,7 +764,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("String s = m8(x -> {x.tri|", "trim()"); } - @BeforeMethod + @BeforeEach public void setUp() { setUp(builder -> builder.executionEngine("local")); @@ -756,7 +796,8 @@ public class CompletionSuggestionTest extends KullaTesting { keepParameterNames.set(getAnalysis(), new String[0]); } - @Test(enabled = false) //TODO 8171829 + @Test //TODO 8171829 + @Disabled public void testBrokenClassFile2() throws IOException { Path broken = outDir.resolve("broken"); compiler.compile(broken, @@ -779,6 +820,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Broke|", "BrokenA", "BrokenC"); } + @Test public void testStatements() { assertEval("String s = \"\";"); assertCompletion("if (s.conta|", (Boolean) null, "contains("); @@ -791,17 +833,20 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("for (var v : s.conta|", (Boolean) null, "contains("); } + @Test public void testRecord() { assertCompletion("record R() implements Ru|", true, "Runnable"); } //JDK-8296789 + @Test public void testParentMembers() { assertEval("var sb=new StringBuilder();"); assertCompletionIncludesExcludes("sb.|", true, Set.of("capacity()", "setLength("), Set.of("maybeLatin1")); } //JDK-8314662 + @Test public void testDuplicateImport() { MethodSnippet m1 = methodKey(assertEval("void test(String s) { foo(); }", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); MethodSnippet m2 = methodKey(assertEval("void test(Integer i) { foo(); }", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); @@ -813,6 +858,7 @@ public class CompletionSuggestionTest extends KullaTesting { //JDK-8326333: verify completion returns sensible output for arrays: //JDK-8326333: jshell completion on arrays is incomplete + @Test public void testArray() { assertEval("String[] strs = null;"); assertCompletion("strs.to|", "toString()"); @@ -826,6 +872,7 @@ public class CompletionSuggestionTest extends KullaTesting { } //JDK-8353581: completion for module imports: + @Test public void testModuleImport() { assertCompletionIncludesExcludes("import |", Set.of("module "), Set.of()); assertCompletionIncludesExcludes("import module |", Set.of("java.base"), Set.of("java.", "module")); @@ -835,6 +882,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("import module java/*c*/./*c*/ba|", "java.base"); } + @Test public void testCustomClassPathIndexing() { Path p1 = outDir.resolve("dir1"); compiler.compile(p1, diff --git a/test/langtools/jdk/jshell/ComputeFQNsTest.java b/test/langtools/jdk/jshell/ComputeFQNsTest.java index 68bb530f311..8e7f5a1d889 100644 --- a/test/langtools/jdk/jshell/ComputeFQNsTest.java +++ b/test/langtools/jdk/jshell/ComputeFQNsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng ComputeFQNsTest + * @run junit ComputeFQNsTest */ import java.io.Writer; @@ -41,15 +41,16 @@ import java.nio.file.Paths; import java.util.Arrays; import jdk.jshell.SourceCodeAnalysis.QualifiedNames; -import static org.testng.Assert.*; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class ComputeFQNsTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("ComputeFQNsTest"); + @Test public void testAddImport() throws Exception { compiler.compile(outDir, "package test1; public class FQNTestClass { }", "package test2; public class FQNTestClass { }"); String jarName = "test.jar"; @@ -77,7 +78,8 @@ public class ComputeFQNsTest extends KullaTesting { assertInferredFQNs("class X { ArrayList", "ArrayList".length(), false, "java.util.ArrayList"); } - @Test(enabled = false) //TODO 8161165 + @Test //TODO 8161165 + @Disabled public void testSuspendIndexing() throws Throwable { compiler.compile(outDir, "package test; public class FQNTest { }"); String jarName = "test.jar"; @@ -127,8 +129,8 @@ public class ComputeFQNsTest extends KullaTesting { QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length()); - assertEquals(candidates.getNames(), Arrays.asList(), "Input: " + code + ", candidates=" + candidates.getNames()); - assertEquals(candidates.isUpToDate(), false, "Input: " + code + ", up-to-date=" + candidates.isUpToDate()); + assertEquals(Arrays.asList(), candidates.getNames(), "Input: " + code + ", candidates=" + candidates.getNames()); + assertEquals(false, candidates.isUpToDate(), "Input: " + code + ", up-to-date=" + candidates.isUpToDate()); Files.delete(continueMarkFile); @@ -136,7 +138,7 @@ public class ComputeFQNsTest extends KullaTesting { candidates = getAnalysis().listQualifiedNames(code, code.length()); - assertEquals(candidates.getNames(), Arrays.asList("test.FQNTest"), "Input: " + code + ", candidates=" + candidates.getNames()); + assertEquals(Arrays.asList("test.FQNTest"), candidates.getNames(), "Input: " + code + ", candidates=" + candidates.getNames()); assertEquals(true, candidates.isUpToDate(), "Input: " + code + ", up-to-date=" + candidates.isUpToDate()); } diff --git a/test/langtools/jdk/jshell/ConsoleTest.java b/test/langtools/jdk/jshell/ConsoleTest.java index a82e0753b56..a5eead1abe0 100644 --- a/test/langtools/jdk/jshell/ConsoleTest.java +++ b/test/langtools/jdk/jshell/ConsoleTest.java @@ -26,7 +26,7 @@ * @bug 8298425 8344706 * @summary Verify behavior of System.console() * @build KullaTesting TestingInputStream - * @run testng ConsoleTest + * @run junit ConsoleTest */ import java.io.IOError; @@ -45,8 +45,8 @@ import jdk.jshell.JShell; import jdk.jshell.JShellConsole; import jdk.jshell.Snippet.Status; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ConsoleTest extends KullaTesting { @@ -62,7 +62,7 @@ public class ConsoleTest extends KullaTesting { console = new ThrowingJShellConsole() { @Override public String readLine(String prompt) throws IOError { - assertEquals(prompt, "expected"); + assertEquals("expected", prompt); return "AB"; } }; @@ -70,7 +70,7 @@ public class ConsoleTest extends KullaTesting { console = new ThrowingJShellConsole() { @Override public char[] readPassword(String prompt) throws IOError { - assertEquals(prompt, "expected"); + assertEquals("expected", prompt); return "AB".toCharArray(); } }; @@ -118,7 +118,7 @@ public class ConsoleTest extends KullaTesting { console = new ThrowingJShellConsole() { @Override public String readLine(String prompt) throws IOError { - assertEquals(prompt, "expected"); + assertEquals("expected", prompt); return "AB"; } }; @@ -146,7 +146,7 @@ public class ConsoleTest extends KullaTesting { int count = 1_000; assertEval("for (int i = 0; i < " + count + "; i++) System.console().writer().write(\"A\");"); String expected = "A".repeat(count); - assertEquals(sb.toString(), expected); + assertEquals(expected, sb.toString()); } @Test @@ -171,7 +171,7 @@ public class ConsoleTest extends KullaTesting { String testStr = "\u30A2"; // Japanese katakana (A2 >= 80) (JDK-8354910) assertEval("System.console().writer().write(\"" + testStr + "\".repeat(" + count + "))"); String expected = testStr.repeat(count); - assertEquals(sb.toString(), expected); + assertEquals(expected, sb.toString()); } @Test @@ -207,7 +207,7 @@ public class ConsoleTest extends KullaTesting { """.replace("${repeats}", "" + repeats) .replace("${output}", "" + output)); String expected = "A".repeat(repeats * output); - assertEquals(sb.toString(), expected); + assertEquals(expected, sb.toString()); } @Test diff --git a/test/langtools/jdk/jshell/ConsoleToolTest.java b/test/langtools/jdk/jshell/ConsoleToolTest.java index a1d9a612ae5..eccd58c878d 100644 --- a/test/langtools/jdk/jshell/ConsoleToolTest.java +++ b/test/langtools/jdk/jshell/ConsoleToolTest.java @@ -28,11 +28,11 @@ * @modules jdk.internal.le/jdk.internal.org.jline.reader * jdk.jshell/jdk.internal.jshell.tool:+open * @build ConsoleToolTest ReplToolTesting - * @run testng ConsoleToolTest + * @run junit ConsoleToolTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ConsoleToolTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/CustomInputToolBuilder.java b/test/langtools/jdk/jshell/CustomInputToolBuilder.java index 523981b3d91..f6fdf97ae1e 100644 --- a/test/langtools/jdk/jshell/CustomInputToolBuilder.java +++ b/test/langtools/jdk/jshell/CustomInputToolBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Verify JavaShellToolBuilder uses provided inputs * @modules jdk.jshell * @build KullaTesting TestingInputStream - * @run testng CustomInputToolBuilder + * @run junit CustomInputToolBuilder */ import java.io.ByteArrayInputStream; @@ -38,15 +38,14 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import jdk.jshell.tool.JavaShellToolBuilder; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertTrue; - -@Test public class CustomInputToolBuilder extends KullaTesting { private static final String TEST_JDK = "test.jdk"; + @Test public void checkCustomInput() throws Exception { String testJdk = System.getProperty(TEST_JDK); try { @@ -102,6 +101,7 @@ public class CustomInputToolBuilder extends KullaTesting { } } + @Test public void checkInteractiveTerminal() throws Exception { String testJdk = System.getProperty(TEST_JDK); try { diff --git a/test/langtools/jdk/jshell/DropTest.java b/test/langtools/jdk/jshell/DropTest.java index e277d1cbeea..1501d391a4d 100644 --- a/test/langtools/jdk/jshell/DropTest.java +++ b/test/langtools/jdk/jshell/DropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +26,20 @@ * @bug 8081431 8080069 8167128 8199623 * @summary Test of JShell#drop(). * @build KullaTesting TestingInputStream - * @run testng DropTest + * @run junit DropTest */ import jdk.jshell.DeclarationSnippet; import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; +import org.junit.jupiter.api.Test; -@Test public class DropTest extends KullaTesting { + @Test public void testDrop() { Snippet var = varKey(assertEval("int x;")); Snippet method = methodKey(assertEval("int mu() { return x * 4; }")); @@ -88,6 +88,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropImport() { Snippet imp = importKey(assertEval("import java.util.*;")); Snippet decl = varKey( @@ -101,11 +102,13 @@ public class DropTest extends KullaTesting { assertDeclareFail("list;", "compiler.err.cant.resolve.location"); } + @Test public void testDropStatement() { Snippet x = key(assertEval("if (true);")); assertDrop(x, ste(x, VALID, DROPPED, true, null)); } + @Test public void testDropVarToMethod() { Snippet x = varKey(assertEval("int x;")); DeclarationSnippet method = methodKey(assertEval("double mu() { return x * 4; }")); @@ -123,6 +126,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropMethodToMethod() { Snippet a = methodKey(assertEval("double a() { return 2; }")); DeclarationSnippet b = methodKey(assertEval("double b() { return a() * 10; }")); @@ -139,6 +143,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropClassToMethod() { Snippet c = classKey(assertEval("class C { int f() { return 7; } }")); DeclarationSnippet m = methodKey(assertEval("int m() { return new C().f(); }")); @@ -150,6 +155,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropVarToClass() { Snippet x = varKey(assertEval("int x;")); DeclarationSnippet a = classKey(assertEval("class A { double a = 4 * x; }")); @@ -165,6 +171,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropMethodToClass() { Snippet x = methodKey(assertEval("int x() { return 0; }")); DeclarationSnippet a = classKey(assertEval("class A { double a = 4 * x(); }")); @@ -179,6 +186,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropClassToClass() { Snippet a = classKey(assertEval("class A {}")); Snippet b = classKey(assertEval("class B extends A {}")); @@ -204,6 +212,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropNoUpdate() { String as1 = "class A {}"; String as2 = "class A extends java.util.ArrayList {}"; @@ -228,6 +237,7 @@ public class DropTest extends KullaTesting { } // 8199623 + @Test public void testTwoForkedDrop() { MethodSnippet p = methodKey(assertEval("void p() throws Exception { ((String) null).toString(); }")); MethodSnippet n = methodKey(assertEval("void n() throws Exception { try { p(); } catch (Exception ex) { throw new RuntimeException(\"bar\", ex); }}")); diff --git a/test/langtools/jdk/jshell/EditorTestBase.java b/test/langtools/jdk/jshell/EditorTestBase.java index 422d07ba1c8..a384c09fcb1 100644 --- a/test/langtools/jdk/jshell/EditorTestBase.java +++ b/test/langtools/jdk/jshell/EditorTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +25,10 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; public abstract class EditorTestBase extends ReplToolTesting { @@ -61,11 +61,11 @@ public abstract class EditorTestBase extends ReplToolTesting { } void assertEditInput(boolean after, String cmd, String input, Action action) { - assertEditInput(after, cmd, s -> assertEquals(s, input, "Input"), action); + assertEditInput(after, cmd, s -> assertEquals(input, s, "Input"), action); } void assertEditOutput(boolean after, String cmd, String output, Action action) { - assertEditOutput(after, cmd, s -> assertEquals(s.trim(), output.trim(), "command"), action); + assertEditOutput(after, cmd, s -> assertEquals(output.trim(), s.trim(), "command"), action); } @Test @@ -219,16 +219,15 @@ public abstract class EditorTestBase extends ReplToolTesting { @Test public void testNoArguments() { - testEditor( - a -> assertVariable(a, "int", "a"), + testEditor(a -> assertVariable(a, "int", "a"), a -> assertMethod(a, "void f() {}", "()void", "f"), a -> assertClass(a, "class A {}", "class", "A"), a -> assertEditInput(a, "/ed", s -> { String[] ss = s.split("\n"); - assertEquals(ss.length, 3, "Expected 3 lines: " + s); - assertEquals(ss[0], "int a;"); - assertEquals(ss[1], "void f() {}"); - assertEquals(ss[2], "class A {}"); + assertEquals(3, ss.length, "Expected 3 lines: " + s); + assertEquals("int a;", ss[0]); + assertEquals("void f() {}", ss[1]); + assertEquals("class A {}", ss[2]); }, this::exit) ); } @@ -263,7 +262,8 @@ public abstract class EditorTestBase extends ReplToolTesting { ); } - @Test(enabled = false) // TODO JDK-8191875 + @Test // TODO JDK-8191875 + @Disabled public void testStatementMush() { testEditor( a -> assertCommand(a, "System.out.println(\"Hello\")", diff --git a/test/langtools/jdk/jshell/EmptyTest.java b/test/langtools/jdk/jshell/EmptyTest.java index 6e838432220..937ab04cb2d 100644 --- a/test/langtools/jdk/jshell/EmptyTest.java +++ b/test/langtools/jdk/jshell/EmptyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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,34 +25,39 @@ * @test * @summary null test * @build KullaTesting TestingInputStream - * @run testng EmptyTest + * @run junit EmptyTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class EmptyTest extends KullaTesting { + @Test public void testEmpty() { assertEvalEmpty(""); } + @Test public void testSpace() { assertEvalEmpty(" "); } + @Test public void testSemicolon() { assertEval(";", ""); } + @Test public void testSlashStarComment() { assertEvalEmpty("/*test*/"); } + @Test public void testSlashStarCommentSemicolon() { assertEval("/*test*/;", ""); } + @Test public void testSlashComment() { assertEvalEmpty("// test"); } diff --git a/test/langtools/jdk/jshell/ErrorRecoveryTest.java b/test/langtools/jdk/jshell/ErrorRecoveryTest.java index 22d6a495f41..deaa71cb739 100644 --- a/test/langtools/jdk/jshell/ErrorRecoveryTest.java +++ b/test/langtools/jdk/jshell/ErrorRecoveryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,17 +31,17 @@ * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @build KullaTesting TestingInputStream ExpectedDiagnostic toolbox.ToolBox Compiler - * @run testng ErrorRecoveryTest + * @run junit ErrorRecoveryTest */ -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; import static jdk.jshell.Snippet.Status.REJECTED; +import org.junit.jupiter.api.Test; -@Test public class ErrorRecoveryTest extends KullaTesting { + @Test public void testExceptionErrors() { assertEval("import java.lang.annotation.Repeatable;"); assertEval(""" @@ -51,6 +51,7 @@ public class ErrorRecoveryTest extends KullaTesting { ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_NOT_DEFINED, false, null)); } + @Test public void testBrokenName() { assertEval("int strictfp = 0;", DiagCheck.DIAG_ERROR, @@ -58,6 +59,7 @@ public class ErrorRecoveryTest extends KullaTesting { ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null)); } + @Test public void testBooleanPatternExpression() { assertEval("Number n = 0;"); assertEval("if (!n instanceof Integer i) {}", @@ -67,6 +69,7 @@ public class ErrorRecoveryTest extends KullaTesting { } //JDK-8332230: + @Test public void testAnnotationsd() { assertEval("k=aa:a.@a", DiagCheck.DIAG_ERROR, diff --git a/test/langtools/jdk/jshell/ErrorTranslationTest.java b/test/langtools/jdk/jshell/ErrorTranslationTest.java index 4db2ff65469..1aa1b2c41dd 100644 --- a/test/langtools/jdk/jshell/ErrorTranslationTest.java +++ b/test/langtools/jdk/jshell/ErrorTranslationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @build KullaTesting TestingInputStream ExpectedDiagnostic toolbox.ToolBox Compiler - * @run testng ErrorTranslationTest + * @run junit ErrorTranslationTest */ import java.nio.file.Path; @@ -41,15 +41,15 @@ import java.util.function.Consumer; import javax.tools.Diagnostic; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -@Test public class ErrorTranslationTest extends ReplToolTesting { - @Test(enabled = false) // TODO 8080353 + @Test // TODO 8080353 + @Disabled public void testErrors() { test( a -> assertDiagnostic(a, "abstract void f();", newExpectedDiagnostic(0, 8, 0, -1, -1, Diagnostic.Kind.ERROR)), @@ -60,6 +60,7 @@ public class ErrorTranslationTest extends ReplToolTesting { ); } + @Test public void testlvtiErrors() { test( a -> assertDiagnostic(a, "var broken = () -> {};", newExpectedDiagnostic(0, 22, 0, -1, -1, Diagnostic.Kind.ERROR)), @@ -67,13 +68,15 @@ public class ErrorTranslationTest extends ReplToolTesting { ); } + @Test public void testExceptionErrors() { test( a -> assertDiagnostic(a, "try { } catch (IllegalStateException | java.io.IOException ex) { }", newExpectedDiagnostic(39, 58, -1, -1, -1, Diagnostic.Kind.ERROR)) ); } - @Test(enabled = false) // TODO 8132147 + @Test // TODO 8132147 + @Disabled public void stressTest() { Compiler compiler = new Compiler(); Path oome = compiler.getPath("OOME.repl"); @@ -115,11 +118,11 @@ public class ErrorTranslationTest extends ReplToolTesting { throw new AssertionError("Not enough lines: " + s); } String kind = getKind(expectedDiagnostic.getKind()); - assertEquals(lines[0], kind); + assertEquals(kind, lines[0]); boolean found = false; for (int i = 0; i < lines.length; i++) { if (lines[i].endsWith(expectedSource)) { - assertEquals(lines[i + 1], expectedMarkingLine, "Input: " + expectedSource + ", marking line: "); + assertEquals(expectedMarkingLine, lines[i + 1], "Input: " + expectedSource + ", marking line: "); found = true; } } @@ -146,6 +149,7 @@ public class ErrorTranslationTest extends ReplToolTesting { return sb.toString(); } + @Test public String getKind(Diagnostic.Kind kind) { switch (kind) { case WARNING: diff --git a/test/langtools/jdk/jshell/ExceptionMessageTest.java b/test/langtools/jdk/jshell/ExceptionMessageTest.java index 39cca56c612..c329afeb35e 100644 --- a/test/langtools/jdk/jshell/ExceptionMessageTest.java +++ b/test/langtools/jdk/jshell/ExceptionMessageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8185108 * @summary Test exception().getMessage() in events returned by eval() - * @run testng ExceptionMessageTest + * @run junit ExceptionMessageTest * @key intermittent */ @@ -42,22 +42,23 @@ import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControlProvider; import jdk.jshell.spi.ExecutionEnv; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ExceptionMessageTest { + @Test public void testDefaultEC() { doTestCases(new JdiExecutionControlProvider(), "default"); } + @Test public void testLocalEC() { doTestCases(new LocalExecutionControlProvider(), "local"); } + @Test public void testDirectEC() { doTestCases(new ExecutionControlProvider() { public ExecutionControl generate(ExecutionEnv env, Map param) throws Throwable { @@ -85,11 +86,11 @@ public class ExceptionMessageTest { private void doTest(JShell jshell, String label, String code, String expected) { List result = jshell.eval(code); - assertEquals(result.size(), 1, "Expected only one event"); + assertEquals(1, result.size(), "Expected only one event"); SnippetEvent evt = result.get(0); Exception exc = evt.exception(); String out = exc.getMessage(); - assertEquals(out, expected, "Exception message not as expected: " + + assertEquals(expected, out, "Exception message not as expected: " + label + " -- " + code); } } diff --git a/test/langtools/jdk/jshell/ExceptionsTest.java b/test/langtools/jdk/jshell/ExceptionsTest.java index 765c3696f07..f7273b2a6fc 100644 --- a/test/langtools/jdk/jshell/ExceptionsTest.java +++ b/test/langtools/jdk/jshell/ExceptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng ExceptionsTest + * @run junit ExceptionsTest */ import java.io.IOException; @@ -46,16 +46,16 @@ import jdk.jshell.UnresolvedReferenceException; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.*; - -@Test public class ExceptionsTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("test_class_path"); + @Test public void throwUncheckedException() { String message = "error_message"; SnippetEvent cr = assertEvalException("throw new RuntimeException(\"" + message + "\");"); @@ -64,6 +64,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr.snippet(), 1))); } + @Test public void throwCheckedException() { String message = "error_message"; SnippetEvent cr = assertEvalException("throw new Exception(\"" + message + "\");"); @@ -72,6 +73,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr.snippet(), 1))); } + @Test public void throwFromStaticMethodOfClass() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -84,6 +86,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwFromStaticMethodOfInterface() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -96,6 +99,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwChained() { String message1 = "error_message1"; String message2 = "error_message2"; @@ -122,6 +126,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr4.snippet(), 1))); } + @Test public void throwChainedUnresolved() { String message1 = "error_message1"; String message2 = "error_message2"; @@ -144,6 +149,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr4.snippet(), 1))); } + @Test public void throwFromConstructor() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -156,6 +162,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwFromDefaultMethodOfInterface() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -168,6 +175,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwFromLambda() { String message = "lambda"; Snippet s1 = varKey(assertEval( @@ -182,6 +190,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr2.snippet(), 1))); } + @Test public void throwFromAnonymousClass() { String message = "anonymous"; Snippet s1 = varKey(assertEval( @@ -198,6 +207,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr2.snippet(), 1))); } + @Test public void throwFromLocalClass() { String message = "local"; Snippet s1 = methodKey(assertEval( @@ -219,6 +229,7 @@ public class ExceptionsTest extends KullaTesting { } // test 8210527 + @Test public void throwFromWithoutSource() { String message = "show this"; SnippetEvent se = assertEvalException("java.lang.reflect.Proxy.newProxyInstance(" + @@ -232,6 +243,7 @@ public class ExceptionsTest extends KullaTesting { } // test 8210527 + @Test public void throwFromNoSource() { Path path = outDir.resolve("fail"); compiler.compile(path, @@ -250,6 +262,7 @@ public class ExceptionsTest extends KullaTesting { } // test 8212167 + @Test public void throwLineFormat1() { SnippetEvent se = assertEvalException( "if (true) { \n" + @@ -261,6 +274,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", se.snippet(), 3))); } + @Test public void throwLineFormat3() { Snippet sp = methodKey(assertEval( "int p() \n" + @@ -292,13 +306,15 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", se.snippet(), 1))); } - @Test(enabled = false) // TODO 8129427 + @Test // TODO 8129427 + @Disabled public void outOfMemory() { assertEval("import java.util.*;"); assertEval("List list = new ArrayList<>();"); assertExecuteException("while (true) { list.add(new byte[10000]); }", OutOfMemoryError.class); } + @Test public void stackOverflow() { assertEval("void f() { f(); }"); assertExecuteException("f();", StackOverflowError.class); @@ -361,11 +377,11 @@ public class ExceptionsTest extends KullaTesting { EvalException ex = (EvalException) exception; String actualException = ex.getExceptionClassName(); String expectedException = exceptionInfo.exception.getCanonicalName(); - assertEquals(actualException, expectedException, + assertEquals(expectedException, actualException, String.format("Given \"%s\" expected exception: %s, got: %s%nStack trace:%n%s", source, expectedException, actualException, getStackTrace(ex))); if (exceptionInfo.message != null) { - assertEquals(ex.getMessage(), exceptionInfo.message, + assertEquals(exceptionInfo.message, ex.getMessage(), String.format("Given \"%s\" expected message: %s, got: %s", source, exceptionInfo.message, ex.getMessage())); } @@ -395,7 +411,7 @@ public class ExceptionsTest extends KullaTesting { "Expected UnresolvedReferenceException: " + exception); UnresolvedExceptionInfo uei = (UnresolvedExceptionInfo) exceptionInfo; UnresolvedReferenceException ure = (UnresolvedReferenceException) exception; - assertEquals(ure.getSnippet(), uei.sn); + assertEquals(uei.sn, ure.getSnippet()); assertStackMatch(ure, "", exceptionInfo); } } @@ -405,20 +421,20 @@ public class ExceptionsTest extends KullaTesting { if (actual == null || expected == null) { fail(message); } else { - assertEquals(actual.length, expected.length, message + " : arrays do not have the same size"); + assertEquals(expected.length, actual.length, message + " : arrays do not have the same size"); for (int i = 0; i < actual.length; ++i) { StackTraceElement actualElement = actual[i]; StackTraceElement expectedElement = expected[i]; - assertEquals(actualElement.getClassName(), expectedElement.getClassName(), message + " : class names [" + i + "]"); + assertEquals(expectedElement.getClassName(), actualElement.getClassName(), message + " : class names [" + i + "]"); String expectedMethodName = expectedElement.getMethodName(); if (expectedMethodName.startsWith("lambda$")) { assertTrue(actualElement.getMethodName().startsWith("lambda$"), message + " : method names"); } else { - assertEquals(actualElement.getMethodName(), expectedElement.getMethodName(), message + " : method names [" + i + "]"); + assertEquals(expectedElement.getMethodName(), actualElement.getMethodName(), message + " : method names [" + i + "]"); } - assertEquals(actualElement.getFileName(), expectedElement.getFileName(), message + " : file names [" + i + "]"); + assertEquals(expectedElement.getFileName(), actualElement.getFileName(), message + " : file names [" + i + "]"); if (expectedElement.getLineNumber() >= 0) { - assertEquals(actualElement.getLineNumber(), expectedElement.getLineNumber(), message + " : line numbers [" + i + "]" + assertEquals(expectedElement.getLineNumber(), actualElement.getLineNumber(), message + " : line numbers [" + i + "]" + " -- actual: " + actualElement.getLineNumber() + ", expected: " + expectedElement.getLineNumber() + " -- in: " + actualElement.getClassName()); } diff --git a/test/langtools/jdk/jshell/ExecutionControlSpecTest.java b/test/langtools/jdk/jshell/ExecutionControlSpecTest.java index 920310bb1e5..14661030cf0 100644 --- a/test/langtools/jdk/jshell/ExecutionControlSpecTest.java +++ b/test/langtools/jdk/jshell/ExecutionControlSpecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +34,20 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting Compiler - * @run testng ExecutionControlSpecTest + * @run junit ExecutionControlSpecTest */ import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class ExecutionControlSpecTest extends KullaTesting { ClassLoader ccl; - @BeforeMethod + @BeforeEach @Override public void setUp() { String mod = "my.ec"; @@ -86,7 +86,7 @@ public class ExecutionControlSpecTest extends KullaTesting { setUp(builder -> builder.executionEngine("prefixing")); } - @AfterMethod + @AfterEach @Override public void tearDown() { super.tearDown(); diff --git a/test/langtools/jdk/jshell/ExecutionControlTestBase.java b/test/langtools/jdk/jshell/ExecutionControlTestBase.java index 20336c902cf..a63e1b16569 100644 --- a/test/langtools/jdk/jshell/ExecutionControlTestBase.java +++ b/test/langtools/jdk/jshell/ExecutionControlTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,11 @@ import javax.tools.Diagnostic; -import org.testng.annotations.Test; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Test; public class ExecutionControlTestBase extends KullaTesting { diff --git a/test/langtools/jdk/jshell/ExpectedDiagnostic.java b/test/langtools/jdk/jshell/ExpectedDiagnostic.java index 2416c9875b8..1fe96200e3c 100644 --- a/test/langtools/jdk/jshell/ExpectedDiagnostic.java +++ b/test/langtools/jdk/jshell/ExpectedDiagnostic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import javax.tools.Diagnostic; import jdk.jshell.Diag; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ExpectedDiagnostic { @@ -79,16 +79,16 @@ public class ExpectedDiagnostic { public void assertDiagnostic(Diag diagnostic) { String code = diagnostic.getCode(); - assertEquals(code, this.code, "Expected error: " + this.code + ", got: " + code); - assertEquals(diagnostic.isError(), kind == Diagnostic.Kind.ERROR); + assertEquals(this.code, code, "Expected error: " + this.code + ", got: " + code); + assertEquals(kind == Diagnostic.Kind.ERROR, diagnostic.isError()); if (startPosition != -1) { - assertEquals(diagnostic.getStartPosition(), startPosition, "Start position"); + assertEquals(startPosition, diagnostic.getStartPosition(), "Start position"); } if (endPosition != -1) { - assertEquals(diagnostic.getEndPosition(), endPosition, "End position"); + assertEquals(endPosition, diagnostic.getEndPosition(), "End position"); } if (position != -1) { - assertEquals(diagnostic.getPosition(), position, "Position"); + assertEquals(position, diagnostic.getPosition(), "Position"); } } } diff --git a/test/langtools/jdk/jshell/ExternalEditorTest.java b/test/langtools/jdk/jshell/ExternalEditorTest.java index 607637e207c..cf1ae4f1ae2 100644 --- a/test/langtools/jdk/jshell/ExternalEditorTest.java +++ b/test/langtools/jdk/jshell/ExternalEditorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8143955 8080843 8163816 8143006 8169828 8171130 8162989 8210808 * @modules jdk.jshell/jdk.internal.jshell.tool * @build ReplToolTesting CustomEditor EditorTestBase - * @run testng ExternalEditorTest + * @run junit ExternalEditorTest * @key intermittent */ @@ -47,15 +47,17 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Consumer; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ExternalEditorTest extends EditorTestBase { private static Path executionScript; @@ -133,21 +135,19 @@ public class ExternalEditorTest extends EditorTestBase { @Test public void testStatementSemicolonAddition() { - testEditor( - a -> assertCommand(a, "if (true) {}", ""), + testEditor(a -> assertCommand(a, "if (true) {}", ""), a -> assertCommand(a, "if (true) {} else {}", ""), a -> assertCommand(a, "Object o", "o ==> null"), a -> assertCommand(a, "if (true) o = new Object() { int x; }", ""), a -> assertCommand(a, "if (true) o = new Object() { int y; }", ""), a -> assertCommand(a, "System.err.flush()", ""), // test still ; for expression statement a -> assertEditOutput(a, "/ed", "", () -> { - assertEquals(getSource(), - "if (true) {}\n" + + assertEquals( "if (true) {}\n" + "if (true) {} else {}\n" + "Object o;\n" + "if (true) o = new Object() { int x; };\n" + "if (true) o = new Object() { int y; };\n" + - "System.err.flush();\n"); + "System.err.flush();\n", getSource()); exit(); }) ); @@ -173,7 +173,7 @@ public class ExternalEditorTest extends EditorTestBase { return System.getProperty("os.name").startsWith("Windows"); } - @BeforeClass + @BeforeAll public static void setUpExternalEditorTest() throws IOException { listener = new ServerSocket(0); listener.setSoTimeout(30000); @@ -250,7 +250,8 @@ public class ExternalEditorTest extends EditorTestBase { ); } - @Test(enabled = false) // TODO 8159229 + @Test // TODO 8159229 + @Disabled public void testRemoveTempFile() { test(new String[]{"--no-startup"}, a -> assertCommandCheckOutput(a, "/set editor " + executionScript, @@ -264,7 +265,7 @@ public class ExternalEditorTest extends EditorTestBase { ); } - @AfterClass + @AfterAll public static void shutdown() throws IOException { executorShutdown(); if (listener != null) { diff --git a/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java b/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java index 99457ea2ce6..c43ec747ffa 100644 --- a/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java +++ b/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting ExecutionControlTestBase Compiler - * @run testng FailOverDirectExecutionControlTest + * @run junit FailOverDirectExecutionControlTest * @key intermittent */ @@ -48,16 +48,15 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import jdk.jshell.execution.FailOverExecutionControlProvider; import jdk.jshell.spi.ExecutionControlProvider; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase { ClassLoader ccl; @@ -93,7 +92,7 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase } - @BeforeMethod + @BeforeEach @Override public void setUp() { logger = Logger.getLogger("jdk.jshell.execution"); @@ -134,7 +133,7 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase setUp(builder -> builder.executionEngine(provider, pm)); } - @AfterMethod + @AfterEach @Override public void tearDown() { super.tearDown(); @@ -144,11 +143,12 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase } @Override + @Test public void variables() { super.variables(); - assertEquals(logged.get(Level.FINEST).size(), 1); - assertEquals(logged.get(Level.FINE).size(), 2); - assertEquals(logged.get(Level.WARNING).size(), 2); + assertEquals(1, logged.get(Level.FINEST).size()); + assertEquals(2, logged.get(Level.FINE).size()); + assertEquals(2, logged.get(Level.WARNING).size()); assertNull(logged.get(Level.SEVERE)); String log = logged.get(Level.WARNING).get(0); assertTrue(log.contains("Failure failover -- 0 = alwaysFailing"), log); diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java index 31011960880..2e53b11b95a 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,17 +28,15 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase DyingRemoteAgent - * @run testng FailOverExecutionControlDyingLaunchTest + * @run junit FailOverExecutionControlDyingLaunchTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlDyingLaunchTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine( diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java index 9958b7a3284..0de985b7a28 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +28,14 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase - * @run testng FailOverExecutionControlHangingLaunchTest + * @run junit FailOverExecutionControlHangingLaunchTest */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlHangingLaunchTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine( diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java index 4f29bfe9c7a..6d61bcb0322 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +28,16 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase - * @run testng FailOverExecutionControlHangingListenTest + * @run junit FailOverExecutionControlHangingListenTest * @key intermittent */ import java.net.InetAddress; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlHangingListenTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { String loopback = InetAddress.getLoopbackAddress().getHostAddress(); diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlTest.java index 80dc56d72c4..579029af4c0 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +28,14 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase - * @run testng FailOverExecutionControlTest + * @run junit FailOverExecutionControlTest */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("failover:0(expectedFailureNonExistent1), 1(expectedFailureNonExistent2), " diff --git a/test/langtools/jdk/jshell/FileManagerTest.java b/test/langtools/jdk/jshell/FileManagerTest.java index 9e4f063da9d..c8c6a7dded7 100644 --- a/test/langtools/jdk/jshell/FileManagerTest.java +++ b/test/langtools/jdk/jshell/FileManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8173845 * @summary test custom file managers * @build KullaTesting TestingInputStream - * @run testng FileManagerTest + * @run junit FileManagerTest */ @@ -37,12 +37,10 @@ import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.StandardJavaFileManager; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertTrue; - -@Test public class FileManagerTest extends KullaTesting { boolean encountered; @@ -100,12 +98,13 @@ public class FileManagerTest extends KullaTesting { } - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(b -> b.fileManager(fm -> new MyFileManager(fm))); } + @Test public void testSnippetMemberAssignment() { assertEval("java.lang.reflect.Array.get(new String[1], 0) == null"); assertTrue(encountered, "java.lang.reflect not encountered"); diff --git a/test/langtools/jdk/jshell/ForwardReferenceImportTest.java b/test/langtools/jdk/jshell/ForwardReferenceImportTest.java index 4e66eaa2196..4459a424092 100644 --- a/test/langtools/jdk/jshell/ForwardReferenceImportTest.java +++ b/test/langtools/jdk/jshell/ForwardReferenceImportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +25,18 @@ * @test 8173232 * @summary Test of forward referencing of snippets (related to import). * @build KullaTesting TestingInputStream - * @run testng ForwardReferenceImportTest + * @run junit ForwardReferenceImportTest */ import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; +import org.junit.jupiter.api.Test; -@Test public class ForwardReferenceImportTest extends KullaTesting { + @Test public void testImportDeclare() { Snippet singleImport = importKey(assertEval("import java.util.List;", added(VALID))); Snippet importOnDemand = importKey(assertEval("import java.util.*;", added(VALID))); @@ -57,6 +57,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardSingleImportMethodToMethod() { DeclarationSnippet string = methodKey(assertEval("String string() { return format(\"string\"); }", added(RECOVERABLE_DEFINED))); @@ -76,6 +77,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardImportMethodOnDemandToMethod() { DeclarationSnippet string = methodKey(assertEval("String string() { return format(\"string\"); }", added(RECOVERABLE_DEFINED))); @@ -95,6 +97,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardSingleImportFieldToMethod() { DeclarationSnippet pi = methodKey(assertEval("double pi() { return PI; }", added(RECOVERABLE_DEFINED))); @@ -114,6 +117,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardImportFieldOnDemandToMethod() { DeclarationSnippet pi = methodKey(assertEval("double pi() { return PI; }", added(RECOVERABLE_DEFINED))); @@ -133,6 +137,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardSingleImportMethodToClass1() { Snippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", added(RECOVERABLE_DEFINED))); @@ -153,6 +158,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } + @Test public void testForwardSingleImportMethodToClass2() { Snippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", added(RECOVERABLE_DEFINED))); @@ -173,6 +179,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } + @Test public void testForwardSingleImportClassToClass1() { Snippet a = classKey(assertEval("class A { static List list; }", added(RECOVERABLE_NOT_DEFINED))); @@ -195,6 +202,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); } + @Test public void testForwardSingleImportClassToClass2() { Snippet clsA = classKey(assertEval("class A extends ArrayList { }", added(RECOVERABLE_NOT_DEFINED))); @@ -219,6 +227,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(clsA, RECOVERABLE_NOT_DEFINED, VALID, true, arraylist)); } + @Test public void testForwardImportOnDemandMethodToClass1() { Snippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", added(RECOVERABLE_DEFINED))); @@ -241,6 +250,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertEval("x.s;", "\"10\""); } + @Test public void testForwardImportOnDemandMethodToClass2() { Snippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", added(RECOVERABLE_DEFINED))); @@ -261,6 +271,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } + @Test public void testForwardImportOnDemandClassToClass1() { Snippet a = classKey(assertEval("class A { static List list; }", added(RECOVERABLE_NOT_DEFINED))); @@ -282,6 +293,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); } + @Test public void testForwardImportOnDemandClassToClass2() { Snippet clsA = classKey(assertEval("class A extends ArrayList { }", added(RECOVERABLE_NOT_DEFINED))); @@ -305,6 +317,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(vara, RECOVERABLE_NOT_DEFINED, VALID, true, clsA)); } + @Test public void testForwardSingleImportFieldToClass1() { Snippet a = classKey(assertEval("class A { static double pi() { return PI; } }", added(RECOVERABLE_DEFINED))); @@ -326,6 +339,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } + @Test public void testForwardSingleImportFieldToClass2() { Snippet a = classKey(assertEval("class A { static double pi = PI; }", added(RECOVERABLE_DEFINED))); @@ -347,6 +361,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, true, list)); } + @Test public void testForwardImportOnDemandFieldToClass1() { Snippet a = classKey(assertEval("class A { static double pi() { return PI; } }", added(RECOVERABLE_DEFINED))); @@ -368,6 +383,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } + @Test public void testForwardImportOnDemandFieldToClass2() { Snippet a = classKey(assertEval("class A { static double pi = PI; }", added(RECOVERABLE_DEFINED))); diff --git a/test/langtools/jdk/jshell/ForwardReferenceTest.java b/test/langtools/jdk/jshell/ForwardReferenceTest.java index a010e9ed31a..841b1f60a8e 100644 --- a/test/langtools/jdk/jshell/ForwardReferenceTest.java +++ b/test/langtools/jdk/jshell/ForwardReferenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8173232 8010319 * @summary Test of forward referencing of snippets. * @build KullaTesting TestingInputStream - * @run testng ForwardReferenceTest + * @run junit ForwardReferenceTest */ import java.util.List; @@ -33,17 +33,17 @@ import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.VarSnippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import jdk.jshell.SnippetEvent; import jdk.jshell.UnresolvedReferenceException; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ForwardReferenceTest extends KullaTesting { + @Test public void testOverwriteMethodForwardReferenceClass() { Snippet k1 = methodKey(assertEval("int q(Boo b) { return b.x; }", added(RECOVERABLE_NOT_DEFINED))); @@ -56,6 +56,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testOverwriteMethodForwardReferenceClassImport() { MethodSnippet k1 = methodKey(assertEval("int ff(List lis) { return lis.size(); }", added(RECOVERABLE_NOT_DEFINED))); @@ -68,6 +69,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToMethod() { DeclarationSnippet t = methodKey(assertEval("int t() { return x; }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(t, RECOVERABLE_DEFINED, "variable x"); @@ -87,6 +89,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardMethodToMethod() { Snippet t = methodKey(assertEval("int t() { return f(); }", added(RECOVERABLE_DEFINED))); Snippet f = methodKey(assertEval("int f() { return g(); }", @@ -109,6 +112,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToMethod() { DeclarationSnippet t = methodKey(assertEval("int t() { return new A().f(); }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(t, RECOVERABLE_DEFINED, "class A"); @@ -133,6 +137,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToClass() { DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); @@ -150,6 +155,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToClassGeneric() { DeclarationSnippet a = classKey(assertEval("class A { final T x; A(T v) { this.x = v; } ; T get() { return x; } int core() { return g; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); @@ -159,9 +165,9 @@ public class ForwardReferenceTest extends KullaTesting { SnippetEvent ste = events.get(0); Snippet assn = ste.snippet(); DeclarationSnippet unsn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); - assertEquals(unsn.name(), "A", "Wrong with unresolved"); - assertEquals(getState().unresolvedDependencies(unsn).count(), 1, "Wrong size unresolved"); - assertEquals(getState().diagnostics(unsn).count(), 0L, "Expected no diagnostics"); + assertEquals("A", unsn.name(), "Wrong with unresolved"); + assertEquals(1, getState().unresolvedDependencies(unsn).count(), "Wrong size unresolved"); + assertEquals(0L, getState().diagnostics(unsn).count(), "Expected no diagnostics"); Snippet g = varKey(assertEval("int g = 10;", "10", added(VALID), @@ -174,6 +180,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToClassExtendsImplements() { DeclarationSnippet ik = classKey(assertEval("interface I { default int ii() { return 1; } }", added(VALID))); DeclarationSnippet jk = classKey(assertEval("interface J { default int jj() { return 2; } }", added(VALID))); @@ -200,6 +207,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToInterface() { DeclarationSnippet i = classKey(assertEval("interface I { default int f() { return x; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(i, RECOVERABLE_DEFINED, "variable x"); @@ -215,6 +223,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToEnum() { DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable fff"); @@ -232,6 +241,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardMethodToClass() { DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method g()"); @@ -251,6 +261,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToClass1() { Snippet a = classKey(assertEval("class A { B b = new B(); }", added(RECOVERABLE_NOT_DEFINED))); assertDeclareFail("new A().b;", "compiler.err.cant.resolve.location"); @@ -269,6 +280,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToClass2() { Snippet a = classKey(assertEval("class A extends B { }", added(RECOVERABLE_NOT_DEFINED))); assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); @@ -287,6 +299,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToClass3() { Snippet a = classKey(assertEval("interface A extends B { static int f() { return 10; } }", added(RECOVERABLE_NOT_DEFINED))); assertDeclareFail("A.f();", "compiler.err.cant.resolve.location"); @@ -305,12 +318,14 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVariable() { assertEval("int f() { return x; }", added(RECOVERABLE_DEFINED)); assertEvalUnresolvedException("f();", "f", 1, 0); assertActiveKeys(); } + @Test public void testLocalClassInUnresolved() { Snippet f = methodKey(assertEval("void f() { class A {} g(); }", added(RECOVERABLE_DEFINED))); assertEval("void g() {}", diff --git a/test/langtools/jdk/jshell/GetResourceTest.java b/test/langtools/jdk/jshell/GetResourceTest.java index f8b2b1af227..dfba8ed588b 100644 --- a/test/langtools/jdk/jshell/GetResourceTest.java +++ b/test/langtools/jdk/jshell/GetResourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +27,18 @@ * @summary Check that ClassLoader.getResource works as expected in the JShell agent. * @modules jdk.jshell * @build KullaTesting TestingInputStream - * @run testng GetResourceTest + * @run junit GetResourceTest */ import jdk.jshell.Snippet; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.VALID; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class GetResourceTest extends KullaTesting { + @Test public void checkGetResource() { assertEval("import java.util.Arrays;"); assertEval("boolean match(byte[] data, byte[] snippet) {\n" + @@ -57,6 +57,7 @@ public class GetResourceTest extends KullaTesting { assertEval("test()", "true"); } + @Test public void checkRedefine() { assertEval("import java.util.Arrays;"); assertEval("boolean match(byte[] data, byte[] snippet) {\n" + @@ -85,6 +86,7 @@ public class GetResourceTest extends KullaTesting { assertEval("test()", "true"); } + @Test public void checkResourceSize() { assertEval("import java.net.*;"); assertEval("boolean test() throws Exception {\n" + @@ -97,6 +99,7 @@ public class GetResourceTest extends KullaTesting { assertEval("test()", "true"); } + @Test public void checkTimestampCheck() { assertEval("import java.net.*;"); assertEval("import java.time.*;"); @@ -138,6 +141,7 @@ public class GetResourceTest extends KullaTesting { assertEval("nue[0] == nue[2]", "true"); } + @Test public void checkFieldAccess() { assertEval("import java.net.*;"); assertEval("Class c = new Object() {}.getClass().getEnclosingClass();"); @@ -154,6 +158,7 @@ public class GetResourceTest extends KullaTesting { assertEval("connection.getHeaderField(3) == null", "true"); } + @Test public void checkGetResources() { assertEval("import java.net.*;"); assertEval("Class c = new Object() {}.getClass().getEnclosingClass();"); diff --git a/test/langtools/jdk/jshell/HighlightUITest.java b/test/langtools/jdk/jshell/HighlightUITest.java index 954cb33117a..22403d5ae7e 100644 --- a/test/langtools/jdk/jshell/HighlightUITest.java +++ b/test/langtools/jdk/jshell/HighlightUITest.java @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile HighlightUITest.java - * @run testng HighlightUITest + * @run junit HighlightUITest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class HighlightUITest extends UITesting { public HighlightUITest() { super(true); } + @Test public void testHighlight() throws Exception { System.setProperty("test.enable.highlighter", "true"); doRunTest((inputSink, out) -> { diff --git a/test/langtools/jdk/jshell/HistoryTest.java b/test/langtools/jdk/jshell/HistoryTest.java index a07523d54cb..923d064c18a 100644 --- a/test/langtools/jdk/jshell/HistoryTest.java +++ b/test/langtools/jdk/jshell/HistoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @modules jdk.internal.le/jdk.internal.org.jline.reader * jdk.jshell/jdk.internal.jshell.tool:+open * @build HistoryTest - * @run testng HistoryTest + * @run junit HistoryTest */ import java.lang.reflect.Field; @@ -37,12 +37,12 @@ import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.internal.jshell.tool.JShellTool; import jdk.internal.jshell.tool.JShellToolBuilder; import jdk.internal.org.jline.reader.History; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class HistoryTest extends ReplToolTesting { @@ -180,16 +180,16 @@ public class HistoryTest extends ReplToolTesting { } assertCommand(a, "/exit", ""); }); - assertEquals(prefsMap.get("HISTORY_LINE_00"), "/debug 0"); - assertEquals(prefsMap.get("HISTORY_LINE_01"), "void test() {\\"); - assertEquals(prefsMap.get("HISTORY_LINE_02"), " System.err.println(1);\\"); - assertEquals(prefsMap.get("HISTORY_LINE_03"), " System.err.println(`\\\\\\\\\\"); - assertEquals(prefsMap.get("HISTORY_LINE_04"), " \\\\\\"); - assertEquals(prefsMap.get("HISTORY_LINE_05"), "`);\\"); - assertEquals(prefsMap.get("HISTORY_LINE_06"), "} //test"); - assertEquals(prefsMap.get("HISTORY_LINE_07"), "/debug 0"); - assertEquals(prefsMap.get("HISTORY_LINE_08"), "int i"); - assertEquals(prefsMap.get("HISTORY_LINE_09"), "/exit"); + assertEquals("/debug 0", prefsMap.get("HISTORY_LINE_00")); + assertEquals("void test() {\\", prefsMap.get("HISTORY_LINE_01")); + assertEquals(" System.err.println(1);\\", prefsMap.get("HISTORY_LINE_02")); + assertEquals(" System.err.println(`\\\\\\\\\\", prefsMap.get("HISTORY_LINE_03")); + assertEquals(" \\\\\\", prefsMap.get("HISTORY_LINE_04")); + assertEquals("`);\\", prefsMap.get("HISTORY_LINE_05")); + assertEquals("} //test", prefsMap.get("HISTORY_LINE_06")); + assertEquals("/debug 0", prefsMap.get("HISTORY_LINE_07")); + assertEquals("int i", prefsMap.get("HISTORY_LINE_08")); + assertEquals("/exit", prefsMap.get("HISTORY_LINE_09")); System.err.println("prefsMap: " + prefsMap); } @@ -204,10 +204,10 @@ public class HistoryTest extends ReplToolTesting { private void previousAndAssert(History history, String expected) { assertTrue(history.previous()); - assertEquals(history.current().toString(), expected); + assertEquals(expected, history.current().toString()); } - @BeforeMethod + @BeforeEach public void setUp() { super.setUp(); System.setProperty("jshell.test.allow.incomplete.inputs", "false"); diff --git a/test/langtools/jdk/jshell/HistoryUITest.java b/test/langtools/jdk/jshell/HistoryUITest.java index 3083fe46688..aa10010e270 100644 --- a/test/langtools/jdk/jshell/HistoryUITest.java +++ b/test/langtools/jdk/jshell/HistoryUITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile HistoryUITest.java - * @run testng HistoryUITest + * @run junit HistoryUITest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class HistoryUITest extends UITesting { public HistoryUITest() { super(true); } + @Test public void testPrevNextSnippet() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("void test1() {\nSystem.err.println(1);\n}\n"); @@ -78,6 +78,7 @@ public class HistoryUITest extends UITesting { }); } + @Test public void testReRun() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("System.err.println(\"RAN\");\n"); diff --git a/test/langtools/jdk/jshell/IOTest.java b/test/langtools/jdk/jshell/IOTest.java index 112b956fec3..988b73ec071 100644 --- a/test/langtools/jdk/jshell/IOTest.java +++ b/test/langtools/jdk/jshell/IOTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,28 +25,29 @@ * @test * @summary Test input/output * @build KullaTesting TestingInputStream - * @run testng IOTest + * @run junit IOTest */ -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class IOTest extends KullaTesting { String LINE_SEPARATOR = System.getProperty("line.separator"); + @Test public void testOutput() { assertEval("System.out.println(\"Test\");"); - assertEquals(getOutput(), "Test" + LINE_SEPARATOR); + assertEquals("Test" + LINE_SEPARATOR, getOutput()); } + @Test public void testErrorOutput() { assertEval("System.err.println(\"Oops\");"); - assertEquals(getErrorOutput(), "Oops" + LINE_SEPARATOR); + assertEquals("Oops" + LINE_SEPARATOR, getErrorOutput()); } + @Test public void testInput() { setInput("x"); assertEval("(char)System.in.read();", "'x'"); diff --git a/test/langtools/jdk/jshell/IdGeneratorTest.java b/test/langtools/jdk/jshell/IdGeneratorTest.java index e8a38dfe7f0..6c7f6177e03 100644 --- a/test/langtools/jdk/jshell/IdGeneratorTest.java +++ b/test/langtools/jdk/jshell/IdGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Test custom id generators * @build KullaTesting TestingInputStream - * @run testng IdGeneratorTest + * @run junit IdGeneratorTest */ import java.io.ByteArrayOutputStream; @@ -38,14 +38,13 @@ import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.UnresolvedReferenceException; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -@Test public class IdGeneratorTest { + @Test public JShell.Builder getBuilder() { TestingInputStream inStream = new TestingInputStream(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); @@ -57,6 +56,7 @@ public class IdGeneratorTest { .executionEngine(Presets.TEST_DEFAULT_EXECUTION); } + @Test public void testTempNameGenerator() { JShell.Builder builder = getBuilder().tempVariableNameGenerator(new Supplier() { int count = 0; @@ -69,11 +69,12 @@ public class IdGeneratorTest { try (JShell jShell = builder.build()) { for (int i = 0; i < 3; ++i) { VarSnippet v = (VarSnippet) jShell.eval("2 + " + (i + 1)).get(0).snippet(); - assertEquals("temp" + (i + 1), v.name(), "Custom id: "); + assertEquals(v.name(), "temp" + (i + 1), "Custom id: "); } } } + @Test public void testResetTempNameGenerator() { JShell.Builder builder = getBuilder().tempVariableNameGenerator(() -> { throw new AssertionError("Should not be called"); @@ -83,6 +84,7 @@ public class IdGeneratorTest { } } + @Test public void testIdGenerator() { JShell.Builder builder = getBuilder().idGenerator(((snippet, id) -> "custom" + id)); try (JShell jShell = builder.build()) { @@ -99,6 +101,7 @@ public class IdGeneratorTest { } } + @Test public void testIdInException() { JShell.Builder builder = getBuilder().idGenerator(((snippet, id) -> "custom" + id)); try (JShell jShell = builder.build()) { @@ -116,6 +119,7 @@ public class IdGeneratorTest { } } + @Test public void testResetIdGenerator() { JShell.Builder builder = getBuilder().idGenerator((sn, id) -> { throw new AssertionError("Should not be called"); diff --git a/test/langtools/jdk/jshell/IgnoreTest.java b/test/langtools/jdk/jshell/IgnoreTest.java index 023b5c99ac8..4350ce0cac3 100644 --- a/test/langtools/jdk/jshell/IgnoreTest.java +++ b/test/langtools/jdk/jshell/IgnoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +26,20 @@ * @bug 8129559 8246353 8247456 * @summary Test the ignoring of comments and certain modifiers * @build KullaTesting TestingInputStream - * @run testng IgnoreTest + * @run junit IgnoreTest */ -import org.testng.annotations.Test; import jdk.jshell.MethodSnippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Test; -@Test public class IgnoreTest extends KullaTesting { + @Test public void testComment() { assertVarKeyMatch("//t1\n int//t2\n x//t3\n =//t4\n 12//t5\n ;//t6\n", true, "x", VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "int", added(VALID)); @@ -58,6 +58,7 @@ public class IgnoreTest extends KullaTesting { false, "f", METHOD_SUBKIND, added(VALID)); } + @Test public void testVarModifier() { VarSnippet x1 = varKey(assertEval("public int x1;")); assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); @@ -71,6 +72,7 @@ public class IgnoreTest extends KullaTesting { assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); } + @Test public void testVarModifierAnnotation() { assertEval("@interface A { int value() default 0; }"); VarSnippet x1 = varKey(assertEval("@A public int x1;")); @@ -85,6 +87,7 @@ public class IgnoreTest extends KullaTesting { assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); } + @Test public void testVarModifierOtherModifier() { VarSnippet x1 = varKey(assertEval("volatile public int x1;")); assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); @@ -98,12 +101,14 @@ public class IgnoreTest extends KullaTesting { assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); } + @Test public void testMisplacedIgnoredModifier() { assertEvalFail("int public y;"); assertEvalFail("String private x;"); assertEvalFail("(protected 34);"); } + @Test public void testMethodModifier() { MethodSnippet m4 = methodKey(assertEval("static void m4() {}")); assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 0); @@ -111,6 +116,7 @@ public class IgnoreTest extends KullaTesting { assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 0); } + @Test public void testMethodModifierAnnotation() { assertEval("@interface A { int value() default 0; }"); MethodSnippet m4 = methodKey(assertEval("@A static void m4() {}")); @@ -119,6 +125,7 @@ public class IgnoreTest extends KullaTesting { assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 0); } + @Test public void testClassModifier() { TypeDeclSnippet c4 = classKey(assertEval("static class C4 {}")); assertTypeDeclSnippet(c4, "C4", VALID, CLASS_SUBKIND, 0, 0); @@ -126,6 +133,7 @@ public class IgnoreTest extends KullaTesting { assertTypeDeclSnippet(c5, "C5", VALID, CLASS_SUBKIND, 0, 0); } + @Test public void testInsideModifier() { assertEval("import static java.lang.reflect.Modifier.*;"); assertEval("class C {" diff --git a/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java b/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java index 3ba5910e8b5..f43778bb465 100644 --- a/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java +++ b/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Testing IllegalArgumentException. * @build KullaTesting TestingInputStream IllegalArgumentExceptionTest - * @run testng IllegalArgumentExceptionTest + * @run junit IllegalArgumentExceptionTest */ import java.util.function.Consumer; @@ -33,12 +33,10 @@ import java.util.function.Consumer; import jdk.jshell.DeclarationSnippet; import jdk.jshell.Snippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; - -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.Test; -@Test public class IllegalArgumentExceptionTest extends KullaTesting { private void testIllegalArgumentException(Consumer action) { @@ -54,22 +52,27 @@ public class IllegalArgumentExceptionTest extends KullaTesting { } } + @Test public void testVarValue() { testIllegalArgumentException((key) -> getState().varValue((VarSnippet) key)); } + @Test public void testStatus() { testIllegalArgumentException((key) -> getState().status(key)); } + @Test public void testDrop() { testIllegalArgumentException((key) -> getState().drop(key)); } + @Test public void testUnresolved() { testIllegalArgumentException((key) -> getState().unresolvedDependencies((DeclarationSnippet) key)); } + @Test public void testDiagnostics() { testIllegalArgumentException((key) -> getState().diagnostics(key)); } diff --git a/test/langtools/jdk/jshell/ImportTest.java b/test/langtools/jdk/jshell/ImportTest.java index 0e1dbfead96..916df3a2b77 100644 --- a/test/langtools/jdk/jshell/ImportTest.java +++ b/test/langtools/jdk/jshell/ImportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.jdeps/com.sun.tools.javap * @library /tools/lib * @build KullaTesting TestingInputStream toolbox.Task.ExpectedDiagnostic - * @run testng ImportTest + * @run junit ImportTest */ import java.lang.reflect.Method; @@ -42,7 +42,6 @@ import javax.tools.Diagnostic; import jdk.jshell.JShell; import jdk.jshell.Snippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.OVERWRITTEN; @@ -51,10 +50,13 @@ import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND; import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND; import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND; import static jdk.jshell.Snippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; -@Test public class ImportTest extends KullaTesting { + @Test public void testImport() { assertImportKeyMatch("import java.util.List;", "List", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); assertImportKeyMatch("import java.util.ArrayList;", "ArrayList", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); @@ -63,6 +65,7 @@ public class ImportTest extends KullaTesting { assertEval("list.size();", "1"); } + @Test public void testImportOnDemand() { assertImportKeyMatch("import java.util.*;", "java.util.*", TYPE_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertEval("List list = new ArrayList<>();"); @@ -70,16 +73,19 @@ public class ImportTest extends KullaTesting { assertEval("list.size();", "1"); } + @Test public void testImportStatic() { assertImportKeyMatch("import static java.lang.Math.PI;", "PI", SINGLE_STATIC_IMPORT_SUBKIND, added(VALID)); assertEval("Double.valueOf(PI).toString().substring(0, 16).equals(\"3.14159265358979\");", "true"); } + @Test public void testImportStaticOnDemand() { assertImportKeyMatch("import static java.lang.Math.*;", "java.lang.Math.*", STATIC_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertEval("abs(cos(PI / 2)) < 0.00001;", "true"); } + @Test public void testUnknownPackage() { assertDeclareFail("import unknown.qqq;", new ExpectedDiagnostic("compiler.err.doesnt.exist", 7, 18, 14, -1, -1, Diagnostic.Kind.ERROR)); @@ -87,22 +93,26 @@ public class ImportTest extends KullaTesting { new ExpectedDiagnostic("compiler.err.doesnt.exist", 7, 14, 7, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testBogusImportIgnoredInFuture() { assertDeclareFail("import unknown.qqq;", "compiler.err.doesnt.exist"); assertDeclareFail("import unknown.*;", "compiler.err.doesnt.exist"); assertEval("2 + 2;"); } + @Test public void testBadImport() { assertDeclareFail("import static java.lang.reflect.Modifier;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 14, 31, 23, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testBadSyntaxImport() { assertDeclareFail("import not found.*;", new ExpectedDiagnostic("compiler.err.expected", 10, 10, 10, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testImportRedefinition() { Compiler compiler = new Compiler(); Path path = Paths.get("testImport"); @@ -143,6 +153,7 @@ public class ImportTest extends KullaTesting { assertEval("new ArrayList();", "MyInnerList"); } + @Test public void testImportMemberRedefinition() { Compiler compiler = new Compiler(); Path path = Paths.get("testImport"); @@ -167,19 +178,21 @@ public class ImportTest extends KullaTesting { assertEval("method();", "\"A\""); } + @Test public void testImportWithComment() { assertImportKeyMatch("import java.util.List;//comment", "List", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); assertEval("List l = null;"); } + @Test public void testImportModule() { assertImportKeyMatch("import module java.base;", "java.base", MODULE_IMPORT_SUBKIND, added(VALID)); assertEval("MethodHandle m;"); } - @org.testng.annotations.BeforeMethod - public void setUp(Method m) { - switch (m.getName()) { + @BeforeEach + public void setUp(TestInfo testInfo) { + switch (testInfo.getTestMethod().orElseThrow().getName()) { case "testImportModule" -> super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); default -> diff --git a/test/langtools/jdk/jshell/InaccessibleExpressionTest.java b/test/langtools/jdk/jshell/InaccessibleExpressionTest.java index 9e6c95fd3f7..db82067d3de 100644 --- a/test/langtools/jdk/jshell/InaccessibleExpressionTest.java +++ b/test/langtools/jdk/jshell/InaccessibleExpressionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,23 +29,21 @@ * jdk.jdeps/com.sun.tools.javap * @library /tools/lib * @build KullaTesting Compiler - * @run testng InaccessibleExpressionTest + * @run junit InaccessibleExpressionTest */ import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.BeforeMethod; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class InaccessibleExpressionTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { Path path = Paths.get("eit"); @@ -76,20 +74,22 @@ public class InaccessibleExpressionTest extends KullaTesting { .compilerOptions("--class-path", tpath)); } + @Test public void testExternal() { assertEval("import static priv.GetPriv.*;"); VarSnippet down = varKey(assertEval("down()", "Packp")); - assertEquals(down.typeName(), "priv.Packp"); + assertEquals("priv.Packp", down.typeName()); assertEval(down.name() + ".get()", "5"); VarSnippet list = varKey(assertEval("list()", "[]")); - assertEquals(list.typeName(), "priv.MyList"); + assertEquals("priv.MyList", list.typeName()); assertEval(list.name() + ".size()", "0"); VarSnippet one = varKey(assertEval("priv()", "One")); - assertEquals(one.typeName(), "priv.GetPriv.Count"); + assertEquals("priv.GetPriv.Count", one.typeName()); assertEval("var v = down();", "Packp"); assertDeclareFail("v.toString()", "compiler.err.not.def.access.class.intf.cant.access"); } + @Test public void testInternal() { assertEval( "class Top {" + @@ -98,7 +98,7 @@ public class InaccessibleExpressionTest extends KullaTesting { " }" + " Inner n = new Inner(); }"); VarSnippet n = varKey(assertEval("new Top().n", "Inner")); - assertEquals(n.typeName(), "Top.Inner"); + assertEquals("Top.Inner", n.typeName()); } } diff --git a/test/langtools/jdk/jshell/IndentUITest.java b/test/langtools/jdk/jshell/IndentUITest.java index d7534b3e6b9..a771b9b1031 100644 --- a/test/langtools/jdk/jshell/IndentUITest.java +++ b/test/langtools/jdk/jshell/IndentUITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile IndentUITest.java - * @run testng IndentUITest + * @run junit IndentUITest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class IndentUITest extends UITesting { public IndentUITest() { super(true); } + @Test public void testIdent() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("void test1() {\nSystem.err.println(1);\n}\n"); diff --git a/test/langtools/jdk/jshell/InferTypeTest.java b/test/langtools/jdk/jshell/InferTypeTest.java index 080697666a2..a1455306f45 100644 --- a/test/langtools/jdk/jshell/InferTypeTest.java +++ b/test/langtools/jdk/jshell/InferTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +30,14 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng InferTypeTest + * @run junit InferTypeTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class InferTypeTest extends KullaTesting { + @Test public void testTypeInference() { assertInferredType("1", "int"); assertEval("import java.util.*;"); diff --git a/test/langtools/jdk/jshell/InputUITest.java b/test/langtools/jdk/jshell/InputUITest.java index 9df0597390c..1a420d2c345 100644 --- a/test/langtools/jdk/jshell/InputUITest.java +++ b/test/langtools/jdk/jshell/InputUITest.java @@ -35,14 +35,13 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile InputUITest.java - * @run testng/othervm -Dstderr.encoding=UTF-8 -Dstdin.encoding=UTF-8 -Dstdout.encoding=UTF-8 InputUITest + * @run junit/othervm -Dstderr.encoding=UTF-8 -Dstdin.encoding=UTF-8 -Dstdout.encoding=UTF-8 InputUITest */ import java.util.Map; import java.util.function.Function; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class InputUITest extends UITesting { static final String LINE_SEPARATOR = System.getProperty("line.separator"); @@ -53,6 +52,7 @@ public class InputUITest extends UITesting { super(true); } + @Test public void testUserInputWithSurrogates() throws Exception { Function genSnippet = realCharsToRead -> "new String(System.in.readNBytes(" + @@ -68,6 +68,7 @@ public class InputUITest extends UITesting { }, false); } + @Test public void testCloseInputSinkWhileReadingUserInputSimulatingCtrlD() throws Exception { var snippets = Map.of( "System.in.read()", " ==> -1", @@ -85,6 +86,7 @@ public class InputUITest extends UITesting { } } + @Test public void testUserInputWithCtrlDAndMultipleSnippets() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("IO.readln()\n" + CTRL_D); diff --git a/test/langtools/jdk/jshell/JLCollisionTest.java b/test/langtools/jdk/jshell/JLCollisionTest.java index 2859c1a49f7..88651e9311e 100644 --- a/test/langtools/jdk/jshell/JLCollisionTest.java +++ b/test/langtools/jdk/jshell/JLCollisionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +28,14 @@ * the same simple names * @modules jdk.jshell/jdk.jshell * @build KullaTesting - * @run testng JLCollisionTest + * @run junit JLCollisionTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JLCollisionTest extends KullaTesting { + @Test public void testObject() { assertEval("class Object {}"); assertEval("1"); @@ -43,6 +43,7 @@ public class JLCollisionTest extends KullaTesting { assertEval("$2 = \"\""); } + @Test public void testThrowable() { assertEval("class Throwable {}"); assertEval("1"); @@ -50,6 +51,7 @@ public class JLCollisionTest extends KullaTesting { assertEval("var _ = new Object() {};"); } + @Test public void testSuppressWarnings() { assertEval("class SuppressWarnings {}"); //var with an "enhanced" (non-denotable) type: diff --git a/test/langtools/jdk/jshell/JShellQueryTest.java b/test/langtools/jdk/jshell/JShellQueryTest.java index 352e639a29c..e487c294f3b 100644 --- a/test/langtools/jdk/jshell/JShellQueryTest.java +++ b/test/langtools/jdk/jshell/JShellQueryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,21 +26,21 @@ * @bug 8143964 * @summary test queries to the JShell that return Streams * @build KullaTesting - * @run testng JShellQueryTest + * @run junit JShellQueryTest */ import jdk.jshell.Snippet; -import org.testng.annotations.Test; import jdk.jshell.ImportSnippet; import jdk.jshell.MethodSnippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import static java.util.stream.Collectors.joining; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -@Test public class JShellQueryTest extends KullaTesting { + @Test public void testSnippets() { assertStreamMatch(getState().snippets()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -54,6 +54,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().snippets(), sx, sfoo, smm, svv, sc, si, simp); } + @Test public void testVars() { assertStreamMatch(getState().variables()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -67,6 +68,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().variables(), sx, sfoo); } + @Test public void testMethods() { assertStreamMatch(getState().methods()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -79,6 +81,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().methods(), smm, svv); } + @Test public void testTypes() { assertStreamMatch(getState().types()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -91,6 +94,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().types(), sc, si); } + @Test public void testImports() { assertStreamMatch(getState().imports()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -103,6 +107,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().imports(), simp); } + @Test public void testDiagnostics() { Snippet sx = varKey(assertEval("int x = 5;")); assertStreamMatch(getState().diagnostics(sx)); @@ -110,9 +115,10 @@ public class JShellQueryTest extends KullaTesting { String res = getState().diagnostics(broken) .map(d -> d.getCode()) .collect(joining("+")); - assertEquals(res, "compiler.err.cant.resolve.location.args+compiler.err.prob.found.req"); + assertEquals("compiler.err.cant.resolve.location.args+compiler.err.prob.found.req", res); } + @Test public void testUnresolvedDependencies() { VarSnippet sx = varKey(assertEval("int x = 5;")); assertStreamMatch(getState().unresolvedDependencies(sx)); diff --git a/test/langtools/jdk/jshell/JShellStateClosedTest.java b/test/langtools/jdk/jshell/JShellStateClosedTest.java index 2f8d1215667..62044dc1f2f 100644 --- a/test/langtools/jdk/jshell/JShellStateClosedTest.java +++ b/test/langtools/jdk/jshell/JShellStateClosedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8164277 * @summary Testing IllegalStateException. * @build KullaTesting TestingInputStream JShellStateClosedTest - * @run testng JShellStateClosedTest + * @run junit JShellStateClosedTest */ import java.util.function.Consumer; @@ -36,11 +36,9 @@ import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.fail; - -@Test public class JShellStateClosedTest extends KullaTesting { private void testStateClosedException(Runnable action) { @@ -53,6 +51,7 @@ public class JShellStateClosedTest extends KullaTesting { } } + @Test public void testClasses() { TypeDeclSnippet sc = classKey(assertEval("class C { }")); TypeDeclSnippet si = classKey(assertEval("interface I { }")); @@ -60,6 +59,7 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().types(), sc, si); } + @Test public void testVariables() { VarSnippet sx = varKey(assertEval("int x = 5;")); VarSnippet sfoo = varKey(assertEval("String foo;")); @@ -67,6 +67,7 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().variables(), sx, sfoo); } + @Test public void testMethods() { MethodSnippet smm = methodKey(assertEval("int mm() { return 6; }")); MethodSnippet svv = methodKey(assertEval("void vv() { }")); @@ -74,12 +75,14 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().methods(), smm, svv); } + @Test public void testImports() { ImportSnippet simp = importKey(assertEval("import java.lang.reflect.*;")); getState().close(); assertStreamMatch(getState().imports(), simp); } + @Test public void testSnippets() { VarSnippet sx = varKey(assertEval("int x = 5;")); VarSnippet sfoo = varKey(assertEval("String foo;")); @@ -92,6 +95,7 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().snippets(), sx, sfoo, smm, svv, sc, si, simp); } + @Test public void testEval() { testStateClosedException(() -> getState().eval("int a;")); } @@ -117,22 +121,27 @@ public class JShellStateClosedTest extends KullaTesting { } } + @Test public void testStatus() { testStateClosedWithoutException((key) -> getState().status(key)); } + @Test public void testVarValue() { testStateClosedException((key) -> getState().varValue((VarSnippet) key)); } + @Test public void testDrop() { testStateClosedException((key) -> getState().drop(key)); } + @Test public void testUnresolved() { testStateClosedWithoutException((key) -> getState().unresolvedDependencies((DeclarationSnippet) key)); } + @Test public void testDiagnostics() { testStateClosedWithoutException((key) -> getState().diagnostics(key)); } diff --git a/test/langtools/jdk/jshell/JavadocTest.java b/test/langtools/jdk/jshell/JavadocTest.java index 184921adf9a..463c23a4f31 100644 --- a/test/langtools/jdk/jshell/JavadocTest.java +++ b/test/langtools/jdk/jshell/JavadocTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng JavadocTest + * @run junit JavadocTest */ import java.io.IOException; @@ -43,13 +43,13 @@ import java.util.Arrays; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JavadocTest extends KullaTesting { private final Compiler compiler = new Compiler(); + @Test public void testJavadoc() { prepareZip(); assertJavadoc("test.Clazz|", "test.Clazz\n" + @@ -65,6 +65,7 @@ public class JavadocTest extends KullaTesting { assertJavadoc("clz.undef|"); } + @Test public void testVariableInRepl() { assertEval("Object o;"); assertSignature("o|", "o:java.lang.Object"); @@ -107,6 +108,7 @@ public class JavadocTest extends KullaTesting { addToClasspath(compiler.getClassDir()); } + @Test public void testCollectionsMin() { prepareJavaUtilZip(); assertJavadoc("java.util.Collections.min(|", diff --git a/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java index 199964abb0b..c45370c1a54 100644 --- a/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,22 +26,22 @@ * @bug 8169519 8166581 * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiBadOptionLaunchExecutionControlTest + * @run junit JdiBadOptionLaunchExecutionControlTest */ import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiBadOptionLaunchExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Failed remote launch: java.util.concurrent.ExecutionException: com.sun.jdi.connect.VMStartException: VM initialization failed"; + @Test public void badOptionLaunchTest() { try { // turn on logging of launch failures diff --git a/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java index bdf05c7bd7f..422c6c18b75 100644 --- a/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,22 +26,22 @@ * @bug 8169519 8166581 * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiBadOptionListenExecutionControlTest + * @run junit JdiBadOptionListenExecutionControlTest */ import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiBadOptionListenExecutionControlTest { private static final String EXPECTED_ERROR = "Unrecognized option: -BadBadOption"; + @Test public void badOptionListenTest() { try { // turn on logging of launch failures diff --git a/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java index 03659952279..7f0924229b7 100644 --- a/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,17 +26,16 @@ * @bug 8169519 8168615 8176474 * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiBogusHostListenExecutionControlTest + * @run junit JdiBogusHostListenExecutionControlTest */ import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiBogusHostListenExecutionControlTest { private static final String EXPECTED_ERROR = @@ -44,6 +43,7 @@ public class JdiBogusHostListenExecutionControlTest { private static final String EXPECTED_LOCATION = "@ com.sun.jdi.SocketListen"; + @Test public void badOptionListenTest() { try { // turn on logging of launch failures diff --git a/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java index 288983a05e5..6ce9df1ccf4 100644 --- a/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build DyingRemoteAgent - * @run testng JdiFailingLaunchExecutionControlTest + * @run junit JdiFailingLaunchExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiFailingLaunchExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void failLaunchTest() { try { System.err.printf("Unexpected return value: %s\n", DyingRemoteAgent.state(true, null).eval("33;")); diff --git a/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java index aaa3357a754..d8b52458551 100644 --- a/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build DyingRemoteAgent - * @run testng JdiFailingListenExecutionControlTest + * @run junit JdiFailingListenExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiFailingListenExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void failListenTest() { try { System.err.printf("Unexpected return value: %s\n", DyingRemoteAgent.state(true, null).eval("33;")); diff --git a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java index cb8fc2ea408..950bf0370ca 100644 --- a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java @@ -27,19 +27,19 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng/timeout=480 JdiHangingLaunchExecutionControlTest + * @run junit/timeout=480 JdiHangingLaunchExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiHangingLaunchExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void hangLaunchTimeoutTest() { try { System.err.printf("Unexpected return value: %s\n", diff --git a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java index d43c3f170bd..78cfe66220a 100644 --- a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java @@ -27,20 +27,20 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng/timeout=480 JdiHangingListenExecutionControlTest + * @run junit/timeout=480 JdiHangingListenExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiHangingListenExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void hangListenTimeoutTest() { try { System.err.printf("Unexpected return value: %s\n", diff --git a/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java b/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java index af9dce89bcf..35261ff6fa1 100644 --- a/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +27,16 @@ * @summary Tests for standard JDI connector (without failover) -- launching * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JdiLaunchingExecutionControlTest + * @run junit JdiLaunchingExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class JdiLaunchingExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("jdi:launch(true)")); diff --git a/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java b/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java index 700ec077e34..3cc2a9785a3 100644 --- a/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +27,16 @@ * @summary Tests for alternate JDI connector -- listening * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JdiListeningExecutionControlTest + * @run junit JdiListeningExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class JdiListeningExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("jdi")); diff --git a/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java b/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java index 241774d639e..2e38e9f9aae 100644 --- a/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +27,16 @@ * @summary Tests for alternate JDI connector -- listening to "localhost" * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JdiListeningLocalhostExecutionControlTest + * @run junit JdiListeningLocalhostExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class JdiListeningLocalhostExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("jdi:hostname(localhost)")); diff --git a/test/langtools/jdk/jshell/JdiStarterTest.java b/test/langtools/jdk/jshell/JdiStarterTest.java index 0beee9ceda1..d584f2e1ec5 100644 --- a/test/langtools/jdk/jshell/JdiStarterTest.java +++ b/test/langtools/jdk/jshell/JdiStarterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8319311 * @summary Tests JdiStarter * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiStarterTest + * @run junit JdiStarterTest */ import java.util.Collections; @@ -34,26 +34,26 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.execution.JdiDefaultExecutionControl.JdiStarter; import jdk.jshell.execution.JdiDefaultExecutionControl.JdiStarter.TargetDescription; import jdk.jshell.execution.JdiExecutionControlProvider; import jdk.jshell.execution.JdiInitiator; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -@Test public class JdiStarterTest { + @Test public void jdiStarter() { // turn on logging of launch failures Logger.getLogger("jdk.jshell.execution").setLevel(Level.ALL); JdiStarter starter = (env, parameters, port) -> { - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_HOST_NAME), ""); - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_LAUNCH), "false"); - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_REMOTE_AGENT), "jdk.jshell.execution.RemoteExecutionControl"); - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_TIMEOUT), "5000"); + assertEquals("", parameters.get(JdiExecutionControlProvider.PARAM_HOST_NAME)); + assertEquals("false", parameters.get(JdiExecutionControlProvider.PARAM_LAUNCH)); + assertEquals("jdk.jshell.execution.RemoteExecutionControl", parameters.get(JdiExecutionControlProvider.PARAM_REMOTE_AGENT)); + assertEquals("5000", parameters.get(JdiExecutionControlProvider.PARAM_TIMEOUT)); JdiInitiator jdii = new JdiInitiator(port, env.extraRemoteVMOptions(), diff --git a/test/langtools/jdk/jshell/KullaCompletenessStressTest.java b/test/langtools/jdk/jshell/KullaCompletenessStressTest.java index e79e043dd10..69830880dcb 100644 --- a/test/langtools/jdk/jshell/KullaCompletenessStressTest.java +++ b/test/langtools/jdk/jshell/KullaCompletenessStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,19 @@ * @summary Test SourceCodeAnalysis * @modules jdk.compiler/com.sun.tools.javac.api * @build KullaTesting TestingInputStream KullaCompletenessStressTest CompletenessStressTest - * @run testng KullaCompletenessStressTest + * @run junit KullaCompletenessStressTest */ import java.io.File; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class KullaCompletenessStressTest extends CompletenessStressTest { @Override + @Test public File[] getDirectoriesToTest() { String src = System.getProperty("test.src"); File file; @@ -44,11 +47,10 @@ public class KullaCompletenessStressTest extends CompletenessStressTest { } else { file = new File(src, "../../../src/jdk.jshell/share/classes"); } - if (!file.exists()) { - System.out.println("jdk.jshell sources are not exist. Test has been skipped. Path: " + file.toString()); - return new File[]{}; - }else { - return new File[]{file}; - } + + Assumptions.assumeTrue(file.exists(), + "jdk.jshell sources are not exist. Test has been skipped. Path: " + file.toString()); + + return new File[]{file}; } } diff --git a/test/langtools/jdk/jshell/KullaTesting.java b/test/langtools/jdk/jshell/KullaTesting.java index e3eb6ef2823..fd9348507c4 100644 --- a/test/langtools/jdk/jshell/KullaTesting.java +++ b/test/langtools/jdk/jshell/KullaTesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,8 +71,6 @@ import jdk.jshell.SourceCodeAnalysis.Completeness; import jdk.jshell.SourceCodeAnalysis.QualifiedNames; import jdk.jshell.SourceCodeAnalysis.Suggestion; import jdk.jshell.UnresolvedReferenceException; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; import jdk.jshell.Diag; @@ -80,9 +78,11 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static jdk.jshell.Snippet.SubKind.METHOD_SUBKIND; import jdk.jshell.SourceCodeAnalysis.Documentation; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; public class KullaTesting { @@ -166,7 +166,7 @@ public class KullaTesting { addToClasspath(path.toString()); } - @BeforeMethod + @BeforeEach public void setUp() { setUp(b -> {}); } @@ -202,7 +202,7 @@ public class KullaTesting { idToSnippet = new LinkedHashMap<>(); } - @AfterMethod + @AfterEach public void tearDown() { if (state != null) state.close(); state = null; @@ -226,16 +226,16 @@ public class KullaTesting { public List assertUnresolvedDependencies(DeclarationSnippet key, int unresolvedSize) { List unresolved = getState().unresolvedDependencies(key).collect(toList()); - assertEquals(unresolved.size(), unresolvedSize, "Input: " + key.source() + ", checking unresolved: "); + assertEquals(unresolvedSize, unresolved.size(), "Input: " + key.source() + ", checking unresolved: "); return unresolved; } public DeclarationSnippet assertUnresolvedDependencies1(DeclarationSnippet key, Status status, String name) { List unresolved = assertUnresolvedDependencies(key, 1); String input = key.source(); - assertEquals(unresolved.size(), 1, "Given input: " + input + ", checking unresolved"); - assertEquals(unresolved.get(0), name, "Given input: " + input + ", checking unresolved: "); - assertEquals(getState().status(key), status, "Given input: " + input + ", checking status: "); + assertEquals(1, unresolved.size(), "Given input: " + input + ", checking unresolved"); + assertEquals(name, unresolved.get(0), "Given input: " + input + ", checking unresolved: "); + assertEquals(status, getState().status(key), "Given input: " + input + ", checking status: "); return key; } @@ -243,24 +243,24 @@ public class KullaTesting { List events = assertEval(input, null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); SnippetEvent ste = events.get(0); DeclarationSnippet sn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); - assertEquals(sn.name(), name, "Given input: " + input + ", checking name"); - assertEquals(getState().unresolvedDependencies(sn).count(), unresolvedSize, "Given input: " + input + ", checking unresolved"); - assertEquals(getState().diagnostics(sn).count(), (long) diagnosticsSize, "Given input: " + input + ", checking diagnostics"); + assertEquals(name, sn.name(), "Given input: " + input + ", checking name"); + assertEquals(unresolvedSize, getState().unresolvedDependencies(sn).count(), "Given input: " + input + ", checking unresolved"); + assertEquals((long) diagnosticsSize, getState().diagnostics(sn).count(), "Given input: " + input + ", checking diagnostics"); return sn; } public Snippet assertKeyMatch(String input, boolean isExecutable, SubKind expectedSubKind, STEInfo mainInfo, STEInfo... updates) { Snippet key = key(assertEval(input, IGNORE_VALUE, mainInfo, updates)); String source = key.source(); - assertEquals(source, input, "Key \"" + input + "\" source mismatch, got: " + source + ", expected: " + input); + assertEquals(input, source, "Key \"" + input + "\" source mismatch, got: " + source + ", expected: " + input); SubKind subkind = key.subKind(); - assertEquals(subkind, expectedSubKind, "Key \"" + input + "\" subkind mismatch, got: " + assertEquals(expectedSubKind, subkind, "Key \"" + input + "\" subkind mismatch, got: " + subkind + ", expected: " + expectedSubKind); - assertEquals(subkind.isExecutable(), isExecutable, "Key \"" + input + "\", expected isExecutable: " + assertEquals(isExecutable, subkind.isExecutable(), "Key \"" + input + "\", expected isExecutable: " + isExecutable + ", got: " + subkind.isExecutable()); Snippet.Kind expectedKind = getKind(key); - assertEquals(key.kind(), expectedKind, "Checking kind: "); - assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: "); + assertEquals(expectedKind, key.kind(), "Checking kind: "); + assertEquals(expectedKind, expectedSubKind.kind(), "Checking kind: "); return key; } @@ -310,9 +310,9 @@ public class KullaTesting { assertTrue(key instanceof ImportSnippet, "Expected an ImportKey, got: " + key.getClass().getName()); ImportSnippet importKey = (ImportSnippet) key; - assertEquals(importKey.name(), name, "Input \"" + input + + assertEquals(name, importKey.name(), "Input \"" + input + "\" name mismatch, got: " + importKey.name() + ", expected: " + name); - assertEquals(importKey.kind(), Kind.IMPORT, "Checking kind: "); + assertEquals(Kind.IMPORT, importKey.kind(), "Checking kind: "); return importKey; } @@ -321,7 +321,7 @@ public class KullaTesting { assertTrue(key instanceof DeclarationSnippet, "Expected a DeclarationKey, got: " + key.getClass().getName()); DeclarationSnippet declKey = (DeclarationSnippet) key; - assertEquals(declKey.name(), name, "Input \"" + input + + assertEquals(name, declKey.name(), "Input \"" + input + "\" name mismatch, got: " + declKey.name() + ", expected: " + name); return declKey; } @@ -331,9 +331,9 @@ public class KullaTesting { assertTrue(sn instanceof VarSnippet, "Expected a VarKey, got: " + sn.getClass().getName()); VarSnippet variableKey = (VarSnippet) sn; String signature = variableKey.typeName(); - assertEquals(signature, typeName, "Key \"" + input + + assertEquals(typeName, signature, "Key \"" + input + "\" typeName mismatch, got: " + signature + ", expected: " + typeName); - assertEquals(variableKey.kind(), Kind.VAR, "Checking kind: "); + assertEquals(Kind.VAR, variableKey.kind(), "Checking kind: "); return variableKey; } @@ -341,11 +341,11 @@ public class KullaTesting { Snippet key = assertKeyMatch(input, true, kind, added(VALID)); assertTrue(key instanceof ExpressionSnippet, "Expected a ExpressionKey, got: " + key.getClass().getName()); ExpressionSnippet exprKey = (ExpressionSnippet) key; - assertEquals(exprKey.name(), name, "Input \"" + input + + assertEquals(name, exprKey.name(), "Input \"" + input + "\" name mismatch, got: " + exprKey.name() + ", expected: " + name); - assertEquals(exprKey.typeName(), typeName, "Key \"" + input + + assertEquals(typeName, exprKey.typeName(), "Key \"" + input + "\" typeName mismatch, got: " + exprKey.typeName() + ", expected: " + typeName); - assertEquals(exprKey.kind(), Kind.EXPRESSION, "Checking kind: "); + assertEquals(Kind.EXPRESSION, exprKey.kind(), "Checking kind: "); } // For expressions throwing an EvalException @@ -403,7 +403,7 @@ public class KullaTesting { void assertStreamMatch(Stream result, T... expected) { Set sns = result.collect(toSet()); Set exp = Stream.of(expected).collect(toSet()); - assertEquals(sns, exp); + assertEquals(exp, sns); } private Map closure(List events) { @@ -484,9 +484,9 @@ public class KullaTesting { }); List events = toTest.get(); getState().unsubscribe(token); - assertEquals(dispatched.size(), events.size(), "dispatched event size not the same as event size"); + assertEquals(events.size(), dispatched.size(), "dispatched event size not the same as event size"); for (int i = events.size() - 1; i >= 0; --i) { - assertEquals(dispatched.get(i), events.get(i), "Event element " + i + " does not match"); + assertEquals(events.get(i), dispatched.get(i), "Event element " + i + " does not match"); } dispatched.add(null); // mark end of dispatchs @@ -500,11 +500,11 @@ public class KullaTesting { if (old != null) { switch (evt.status()) { case DROPPED: - assertEquals(old, evt.snippet(), + assertEquals(evt.snippet(), old, "Drop: Old snippet must be what is dropped -- input: " + descriptor); break; case OVERWRITTEN: - assertEquals(old, evt.snippet(), + assertEquals(evt.snippet(), old, "Overwrite: Old snippet (" + old + ") must be what is overwritten -- input: " + descriptor + " -- " + evt); @@ -512,12 +512,12 @@ public class KullaTesting { default: if (evt.causeSnippet() == null) { // New source - assertNotEquals(old, evt.snippet(), + assertNotEquals(evt.snippet(), old, "New source: Old snippet must be different from the replacing -- input: " + descriptor); } else { // An update (key Overwrite??) - assertEquals(old, evt.snippet(), + assertEquals(evt.snippet(), old, "Update: Old snippet must be equal to the replacing -- input: " + descriptor); } @@ -557,7 +557,7 @@ public class KullaTesting { int impactId = 0; Map> groupedEvents = groupByCauseSnippet(events); - assertEquals(groupedEvents.size(), eventChains.length, "Number of main events"); + assertEquals(eventChains.length, groupedEvents.size(), "Number of main events"); for (Map.Entry> entry : groupedEvents.entrySet()) { EventChain eventChain = eventChains[impactId++]; SnippetEvent main = entry.getValue().get(0); @@ -580,12 +580,12 @@ public class KullaTesting { } } if (((Object) eventChain.value) != IGNORE_VALUE) { - assertEquals(main.value(), eventChain.value, "Expected execution value of: " + eventChain.value + + assertEquals(eventChain.value, main.value(), "Expected execution value of: " + eventChain.value + ", but got: " + main.value()); } if (eventChain.exceptionClass != IGNORE_EXCEPTION) { if (main.exception() == null) { - assertEquals(eventChain.exceptionClass, null, "Expected an exception of class " + assertEquals(null, eventChain.exceptionClass, "Expected an exception of class " + eventChain.exceptionClass + " got no exception"); } else if (eventChain.exceptionClass == null) { fail("Expected no exception but got " + main.exception().toString()); @@ -598,7 +598,7 @@ public class KullaTesting { List diagnostics = getState().diagnostics(mainKey).collect(toList()); switch (diagMain) { case DIAG_OK: - assertEquals(diagnostics.size(), 0, "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); + assertEquals(0, diagnostics.size(), "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); break; case DIAG_WARNING: assertFalse(hasFatalError(diagnostics), "Expected no errors, got: " + diagnosticsToString(diagnostics)); @@ -612,7 +612,7 @@ public class KullaTesting { diagnostics = getState().diagnostics(ste.snippet()).collect(toList()); switch (diagUpdates) { case DIAG_OK: - assertEquals(diagnostics.size(), 0, "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); + assertEquals(0, diagnostics.size(), "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); break; case DIAG_WARNING: assertFalse(hasFatalError(diagnostics), "Expected no errors, got: " + diagnosticsToString(diagnostics)); @@ -627,7 +627,7 @@ public class KullaTesting { // Use this for all EMPTY calls to eval() public void assertEvalEmpty(String input) { List events = getState().eval(input); - assertEquals(events.size(), 0, "Expected no events, got: " + events.size()); + assertEquals(0, events.size(), "Expected no events, got: " + events.size()); } public VarSnippet varKey(List events) { @@ -661,7 +661,7 @@ public class KullaTesting { public void assertVarValue(Snippet key, String expected) { String value = state.varValue((VarSnippet) key); - assertEquals(value, expected, "Expected var value of: " + expected + ", but got: " + value); + assertEquals(expected, value, "Expected var value of: " + expected + ", but got: " + value); } public Snippet assertDeclareFail(String input, String expectedErrorCode) { @@ -685,7 +685,7 @@ public class KullaTesting { DiagCheck.DIAG_ERROR, DiagCheck.DIAG_IGNORE, mainInfo, updates); SnippetEvent e = events.get(0); Snippet key = e.snippet(); - assertEquals(getState().status(key), REJECTED); + assertEquals(REJECTED, getState().status(key)); List diagnostics = getState().diagnostics(e.snippet()).collect(toList()); assertTrue(diagnostics.size() > 0, "Expected diagnostics, got none"); assertDiagnostic(input, diagnostics.get(0), expectedDiagnostic); @@ -728,7 +728,7 @@ public class KullaTesting { assertDeclarationSnippet(method, expectedName, expectedStatus, METHOD_SUBKIND, unressz, othersz); String signature = method.signature(); - assertEquals(signature, expectedSignature, + assertEquals(expectedSignature, signature, "Expected " + method.source() + " to have the name: " + expectedSignature + ", got: " + signature); } @@ -740,7 +740,7 @@ public class KullaTesting { assertDeclarationSnippet(var, expectedName, expectedStatus, expectedSubKind, unressz, othersz); String signature = var.typeName(); - assertEquals(signature, expectedTypeName, + assertEquals(expectedTypeName, signature, "Expected " + var.source() + " to have the type name: " + expectedTypeName + ", got: " + signature); } @@ -751,27 +751,27 @@ public class KullaTesting { int unressz, int othersz) { assertKey(declarationKey, expectedStatus, expectedSubKind); String source = declarationKey.source(); - assertEquals(declarationKey.name(), expectedName, + assertEquals(expectedName, declarationKey.name(), "Expected " + source + " to have the name: " + expectedName + ", got: " + declarationKey.name()); long unresolved = getState().unresolvedDependencies(declarationKey).count(); - assertEquals(unresolved, unressz, "Expected " + source + " to have " + unressz + assertEquals(unressz, unresolved, "Expected " + source + " to have " + unressz + " unresolved symbols, got: " + unresolved); long otherCorralledErrorsCount = getState().diagnostics(declarationKey).count(); - assertEquals(otherCorralledErrorsCount, othersz, "Expected " + source + " to have " + othersz + assertEquals(othersz, otherCorralledErrorsCount, "Expected " + source + " to have " + othersz + " other errors, got: " + otherCorralledErrorsCount); } public void assertKey(Snippet key, Status expectedStatus, SubKind expectedSubKind) { String source = key.source(); SubKind actualSubKind = key.subKind(); - assertEquals(actualSubKind, expectedSubKind, + assertEquals(expectedSubKind, actualSubKind, "Expected " + source + " to have the subkind: " + expectedSubKind + ", got: " + actualSubKind); Status status = getState().status(key); - assertEquals(status, expectedStatus, "Expected " + source + " to be " + assertEquals(expectedStatus, status, "Expected " + source + " to be " + expectedStatus + ", but it is " + status); Snippet.Kind expectedKind = getKind(key); - assertEquals(key.kind(), expectedKind, "Checking kind: "); - assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: "); + assertEquals(expectedKind, key.kind(), "Checking kind: "); + assertEquals(expectedKind, expectedSubKind.kind(), "Checking kind: "); } public void assertDrop(Snippet key, STEInfo mainInfo, STEInfo... updates) { @@ -796,36 +796,36 @@ public class KullaTesting { public void assertAnalyze(String input, Completeness status, String source, String remaining, Boolean isComplete) { CompletionInfo ci = getAnalysis().analyzeCompletion(input); - if (status != null) assertEquals(ci.completeness(), status, "Input : " + input + ", status: "); - assertEquals(ci.source(), source, "Input : " + input + ", source: "); - if (remaining != null) assertEquals(ci.remaining(), remaining, "Input : " + input + ", remaining: "); + if (status != null) assertEquals(status, ci.completeness(), "Input : " + input + ", status: "); + assertEquals(source, ci.source(), "Input : " + input + ", source: "); + if (remaining != null) assertEquals(remaining, ci.remaining(), "Input : " + input + ", remaining: "); if (isComplete != null) { boolean isExpectedComplete = isComplete; - assertEquals(ci.completeness().isComplete(), isExpectedComplete, "Input : " + input + ", isComplete: "); + assertEquals(isExpectedComplete, ci.completeness().isComplete(), "Input : " + input + ", isComplete: "); } } public void assertNumberOfActiveVariables(int cnt) { - assertEquals(getState().variables().count(), cnt, "Variables : " + getState().variables().collect(toList())); + assertEquals(cnt, getState().variables().count(), "Variables : " + getState().variables().collect(toList())); } public void assertNumberOfActiveMethods(int cnt) { - assertEquals(getState().methods().count(), cnt, "Methods : " + getState().methods().collect(toList())); + assertEquals(cnt, getState().methods().count(), "Methods : " + getState().methods().collect(toList())); } public void assertNumberOfActiveClasses(int cnt) { - assertEquals(getState().types().count(), cnt, "Types : " + getState().types().collect(toList())); + assertEquals(cnt, getState().types().count(), "Types : " + getState().types().collect(toList())); } public void assertKeys(MemberInfo... expected) { int index = 0; List snippets = getState().snippets().collect(toList()); - assertEquals(allSnippets.size(), snippets.size()); + assertEquals(snippets.size(), allSnippets.size()); for (Snippet sn : snippets) { if (sn.kind().isPersistent() && getState().status(sn).isActive()) { MemberInfo actual = getMemberInfo(sn); MemberInfo exp = expected[index]; - assertEquals(actual, exp, String.format("Difference in #%d. Expected: %s, actual: %s", + assertEquals(exp, actual, String.format("Difference in #%d. Expected: %s, actual: %s", index, exp, actual)); ++index; } @@ -841,7 +841,7 @@ public class KullaTesting { int index = 0; for (Snippet key : getState().snippets().collect(toList())) { if (state.status(key).isActive()) { - assertEquals(expected[index], key, String.format("Difference in #%d. Expected: %s, actual: %s", index, key, expected[index])); + assertEquals(key, expected[index], String.format("Difference in #%d. Expected: %s, actual: %s", index, key, expected[index])); ++index; } } @@ -853,7 +853,7 @@ public class KullaTesting { .collect(Collectors.toSet()); Set got = snippets .collect(Collectors.toSet()); - assertEquals(active, got, label); + assertEquals(got, active, label); } public void assertVariables() { @@ -873,8 +873,8 @@ public class KullaTesting { Set got = members .map(this::getMemberInfo) .collect(Collectors.toSet()); - assertEquals(got.size(), expected.size(), "Expected : " + expected + ", actual : " + members); - assertEquals(got, expected); + assertEquals(expected.size(), got.size(), "Expected : " + expected + ", actual : " + members); + assertEquals(expected, got); } public void assertVariables(MemberInfo...expected) { @@ -892,7 +892,7 @@ public class KullaTesting { } assertNotNull(expectedInfo, "Not found method: " + methodKey.name()); int lastIndexOf = expectedInfo.type.lastIndexOf(')'); - assertEquals(methodKey.parameterTypes(), expectedInfo.type.substring(1, lastIndexOf), "Parameter types"); + assertEquals(expectedInfo.type.substring(1, lastIndexOf), methodKey.parameterTypes(), "Parameter types"); }); } @@ -906,7 +906,7 @@ public class KullaTesting { public void assertCompletion(String code, Boolean isSmart, String... expected) { List completions = computeCompletions(code, isSmart); - assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString()); + assertEquals(Arrays.asList(expected), completions, "Input: " + code + ", " + completions.toString()); } public void assertCompletionIncludesExcludes(String code, Set expected, Set notExpected) { @@ -940,7 +940,7 @@ public class KullaTesting { public void assertInferredType(String code, String expectedType) { String inferredType = getAnalysis().analyzeType(code, code.length()); - assertEquals(inferredType, expectedType, "Input: " + code + ", " + inferredType); + assertEquals(expectedType, inferredType, "Input: " + code + ", " + inferredType); } public void assertInferredFQNs(String code, String... fqns) { @@ -952,9 +952,9 @@ public class KullaTesting { QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length()); - assertEquals(candidates.getNames(), Arrays.asList(fqns), "Input: " + code + ", candidates=" + candidates.getNames()); - assertEquals(candidates.getSimpleNameLength(), simpleNameLen, "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength()); - assertEquals(candidates.isResolvable(), resolvable, "Input: " + code + ", resolvable=" + candidates.isResolvable()); + assertEquals(Arrays.asList(fqns), candidates.getNames(), "Input: " + code + ", candidates=" + candidates.getNames()); + assertEquals(simpleNameLen, candidates.getSimpleNameLength(), "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength()); + assertEquals(resolvable, candidates.isResolvable(), "Input: " + code + ", resolvable=" + candidates.isResolvable()); } protected void waitIndexingFinished() { @@ -975,7 +975,7 @@ public class KullaTesting { List documentation = getAnalysis().documentation(code, cursor, false); Set docSet = documentation.stream().map(doc -> doc.signature()).collect(Collectors.toSet()); Set expectedSet = Stream.of(expected).collect(Collectors.toSet()); - assertEquals(docSet, expectedSet, "Input: " + code); + assertEquals(expectedSet, docSet, "Input: " + code); } public void assertJavadoc(String code, String... expected) { @@ -987,7 +987,7 @@ public class KullaTesting { .map(doc -> doc.signature() + "\n" + doc.javadoc()) .collect(Collectors.toSet()); Set expectedSet = Stream.of(expected).collect(Collectors.toSet()); - assertEquals(docSet, expectedSet, "Input: " + code); + assertEquals(expectedSet, docSet, "Input: " + code); } public enum ClassType { @@ -1183,7 +1183,7 @@ public class KullaTesting { assertStatusMatch(ste, ste.previousStatus(), previousStatus()); assertStatusMatch(ste, ste.status(), status()); if (checkIsSignatureChange) { - assertEquals(ste.isSignatureChange(), isSignatureChange(), + assertEquals(isSignatureChange(), ste.isSignatureChange(), "Expected " + (isSignatureChange()? "" : "no ") + "signature-change, got: " + @@ -1206,10 +1206,10 @@ public class KullaTesting { assertTrue(sn != testKey, "Main-event: Expected new snippet to be != : " + testKey + "\n got-event: " + toString(ste)); - assertEquals(sn.id(), testKey.id(), "Expected IDs to match: " + testKey + ", got: " + sn + assertEquals(testKey.id(), sn.id(), "Expected IDs to match: " + testKey + ", got: " + sn + "\n expected-event: " + this + "\n got-event: " + toString(ste)); } else { - assertEquals(sn, testKey, "Expected key to be: " + testKey + ", got: " + sn + assertEquals(testKey, sn, "Expected key to be: " + testKey + ", got: " + sn + "\n expected-event: " + this + "\n got-event: " + toString(ste)); } } @@ -1217,7 +1217,7 @@ public class KullaTesting { private void assertStatusMatch(SnippetEvent ste, Status status, Status expected) { if (expected != null) { - assertEquals(status, expected, "Expected status to be: " + expected + ", got: " + status + + assertEquals(expected, status, "Expected status to be: " + expected + ", got: " + status + "\n expected-event: " + this + "\n got-event: " + toString(ste)); } } diff --git a/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java b/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java index 6511c9a17fb..d53081b698d 100644 --- a/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java +++ b/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox toolbox.JavacTask LocalExecutionTestSupport - * @run testng/othervm LocalExecutionClassPathTest + * @run junit/othervm LocalExecutionClassPathTest */ import java.util.Locale; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LocalExecutionClassPathTest extends LocalExecutionTestSupport { @Override diff --git a/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java b/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java index e01ee879a8c..a4150379c75 100644 --- a/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java +++ b/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox toolbox.JavacTask LocalExecutionTestSupport - * @run testng/othervm LocalExecutionContextLoaderParentTest + * @run junit/othervm LocalExecutionContextLoaderParentTest */ import java.io.IOException; @@ -49,12 +49,14 @@ import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControlProvider; import jdk.jshell.spi.ExecutionEnv; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeTest; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LocalExecutionContextLoaderParentTest extends LocalExecutionTestSupport { - @BeforeTest + @BeforeAll public void installParentTestProvider() throws IOException { Path dir = createSubdir(classesDir, "META-INF/services"); Files.write(dir.resolve(ExecutionControlProvider.class.getName()), diff --git a/test/langtools/jdk/jshell/LocalExecutionTestSupport.java b/test/langtools/jdk/jshell/LocalExecutionTestSupport.java index 6c6e122dfa9..2eceb5a7120 100644 --- a/test/langtools/jdk/jshell/LocalExecutionTestSupport.java +++ b/test/langtools/jdk/jshell/LocalExecutionTestSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import org.testng.annotations.BeforeTest; +import org.junit.jupiter.api.BeforeAll; import toolbox.JavacTask; import toolbox.TestRunner; @@ -49,7 +49,7 @@ public class LocalExecutionTestSupport extends ReplToolTesting { protected Path classesDir; // classes directory // Install file "test/MyClass.class" in some temporary directory somewhere - @BeforeTest + @BeforeAll public void installMyClass() throws IOException { // Create directories diff --git a/test/langtools/jdk/jshell/LocalStopExecutionTest.java b/test/langtools/jdk/jshell/LocalStopExecutionTest.java index 501c5cf7df9..981fec13f04 100644 --- a/test/langtools/jdk/jshell/LocalStopExecutionTest.java +++ b/test/langtools/jdk/jshell/LocalStopExecutionTest.java @@ -27,7 +27,7 @@ * @summary Verify local execution can stop execution when there are no backward branches * @modules jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng LocalStopExecutionTest + * @run junit LocalStopExecutionTest */ import java.io.IOException; @@ -40,15 +40,13 @@ import jdk.internal.jshell.tool.StopDetectingInputStream; import jdk.internal.jshell.tool.StopDetectingInputStream.State; import jdk.jshell.JShell; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class LocalStopExecutionTest extends AbstractStopExecutionTest { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(b -> b.executionEngine("local")); diff --git a/test/langtools/jdk/jshell/MethodsTest.java b/test/langtools/jdk/jshell/MethodsTest.java index 85f63f82f77..9577f943c51 100644 --- a/test/langtools/jdk/jshell/MethodsTest.java +++ b/test/langtools/jdk/jshell/MethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456 8267221 8272135 * @summary Tests for EvaluationState.methods * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng MethodsTest + * @run junit MethodsTest */ import javax.tools.Diagnostic; @@ -34,21 +34,23 @@ import javax.tools.Diagnostic; import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet.Status; -import org.testng.annotations.Test; import java.util.List; import java.util.stream.Collectors; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class MethodsTest extends KullaTesting { + @Test public void noMethods() { assertNumberOfActiveMethods(0); } + @Test public void testSignature1() { MethodSnippet m1 = methodKey(assertEval("void f() { g(); }", added(RECOVERABLE_DEFINED))); assertMethodDeclSnippet(m1, "f", "()void", RECOVERABLE_DEFINED, 1, 0); @@ -58,6 +60,7 @@ public class MethodsTest extends KullaTesting { assertMethodDeclSnippet(m2, "g", "()void", VALID, 0, 0); } + @Test public void testSignature2() { MethodSnippet m1 = (MethodSnippet) assertDeclareFail("void f() { return g(); }", "compiler.err.prob.found.req"); assertMethodDeclSnippet(m1, "f", "()void", REJECTED, 0, 2); @@ -67,7 +70,8 @@ public class MethodsTest extends KullaTesting { assertMethodDeclSnippet(m2, "f", "()int", RECOVERABLE_DEFINED, 1, 0); } - @Test(enabled = false) // TODO 8081690 + @Test // TODO 8081690 + @Disabled public void testSignature3() { MethodSnippet m1 = methodKey(assertEval("void f(Bar b) { }", added(RECOVERABLE_NOT_DEFINED))); assertMethodDeclSnippet(m1, "f", "(Bar)void", RECOVERABLE_NOT_DEFINED, 1, 0); @@ -79,6 +83,7 @@ public class MethodsTest extends KullaTesting { } // 8080357 + @Test public void testNonReplUnresolved() { // internal case assertEval("class CCC {}", added(VALID)); @@ -87,6 +92,7 @@ public class MethodsTest extends KullaTesting { assertDeclareFail("void f2() { System.xxxx(); }", "compiler.err.cant.resolve.location.args"); } + @Test public void methods() { assertEval("int x() { return 10; }"); assertEval("String y() { return null; }"); @@ -95,6 +101,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodOverload() { assertEval("int m() { return 1; }"); assertEval("int m(int x) { return 2; }"); @@ -139,6 +146,7 @@ public class MethodsTest extends KullaTesting { } ***/ + @Test public void methodsRedeclaration1() { Snippet x = methodKey(assertEval("int x() { return 10; }")); Snippet y = methodKey(assertEval("String y() { return \"\"; }")); @@ -158,6 +166,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsRedeclaration2() { assertEval("int a() { return 1; }"); assertMethods(method("()int", "a")); @@ -179,6 +188,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsRedeclaration3() { Snippet x = methodKey(assertEval("int x(Object...a) { return 10; }")); assertMethods(method("(Object...)int", "x")); @@ -192,6 +202,7 @@ public class MethodsTest extends KullaTesting { } + @Test public void methodsRedeclaration4() { Snippet a = methodKey(assertEval("int foo(int a) { return a; }")); assertEval("int x = foo(10);"); @@ -204,6 +215,7 @@ public class MethodsTest extends KullaTesting { } // 8199762 + @Test public void methodsRedeclaration5() { Snippet m1 = methodKey(assertEval("int m(Object o) { return 10; }")); assertMethods(method("(Object)int", "m")); @@ -220,22 +232,23 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsAbstract() { MethodSnippet m1 = methodKey(assertEval("abstract String f();", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); - assertEquals(getState().unresolvedDependencies(m1).collect(Collectors.toList()), - List.of("method f()")); + assertEquals( List.of("method f()"), getState().unresolvedDependencies(m1).collect(Collectors.toList())); MethodSnippet m2 = methodKey(assertEval("abstract int mm(Blah b);", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_NOT_DEFINED, false, null))); List unr = getState().unresolvedDependencies(m2).collect(Collectors.toList()); - assertEquals(unr.size(), 2); + assertEquals(2, unr.size()); unr.remove("class Blah"); unr.remove("method mm(Blah)"); - assertEquals(unr.size(), 0, "unexpected entry: " + unr); + assertEquals(0, unr.size(), "unexpected entry: " + unr); assertNumberOfActiveMethods(2); assertActiveKeys(); } + @Test public void methodsErrors() { assertDeclareFail("String f();", new ExpectedDiagnostic("compiler.err.missing.meth.body.or.decl.abstract", 0, 11, 7, -1, -1, Diagnostic.Kind.ERROR)); @@ -267,6 +280,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void objectMethodNamedMethodsErrors() { assertDeclareFail("boolean equals(double d1, double d2) { return d1 == d2; }", new ExpectedDiagnostic("jdk.eval.error.object.method", 8, 14, 8, -1, -1, Diagnostic.Kind.ERROR)); @@ -286,6 +300,7 @@ public class MethodsTest extends KullaTesting { } + @Test public void methodsAccessModifierIgnored() { Snippet f = methodKey(assertEval("public String f() {return null;}", added(VALID))); @@ -305,6 +320,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsIgnoredModifiers() { Snippet f = methodKey(assertEval("static String f() {return null;}")); assertNumberOfActiveMethods(1); @@ -318,6 +334,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodSignatureUnresolved() { MethodSnippet key = (MethodSnippet) methodKey(assertEval("und m() { return new und(); }", added(RECOVERABLE_NOT_DEFINED))); assertMethodDeclSnippet(key, "m", "()und", RECOVERABLE_NOT_DEFINED, 1, 0); @@ -330,7 +347,8 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void classMethodsAreNotVisible() { assertEval( "class A {" + @@ -351,6 +369,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void lambdas() { assertEval("class Inner1 implements Runnable {" + "public Runnable lambda1 = () -> {};" + @@ -376,15 +395,17 @@ public class MethodsTest extends KullaTesting { } //JDK-8267221: + @Test public void testMethodArrayParameters() { MethodSnippet m1 = methodKey(assertEval("void m1(int... p) { }", added(VALID))); - assertEquals(m1.parameterTypes(), "int..."); + assertEquals("int...", m1.parameterTypes()); MethodSnippet m2 = methodKey(assertEval("void m2(int[]... p) { }", added(VALID))); - assertEquals(m2.parameterTypes(), "int[]..."); + assertEquals("int[]...", m2.parameterTypes()); MethodSnippet m3 = methodKey(assertEval("void m3(int[][] p) { }", added(VALID))); - assertEquals(m3.parameterTypes(), "int[][]"); + assertEquals("int[][]", m3.parameterTypes()); } + @Test public void testOverloadCalls() { MethodSnippet orig = methodKey(assertEval("int m(String s) { return 0; }")); MethodSnippet overload = methodKey(assertEval("int m(int i) { return 1; }")); diff --git a/test/langtools/jdk/jshell/ModifiersTest.java b/test/langtools/jdk/jshell/ModifiersTest.java index 2cbebc8b5b8..2cdb5ce28b6 100644 --- a/test/langtools/jdk/jshell/ModifiersTest.java +++ b/test/langtools/jdk/jshell/ModifiersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8167643 8129559 8247456 * @summary Tests for modifiers * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng ModifiersTest + * @run junit ModifiersTest */ import java.util.ArrayList; @@ -34,13 +34,14 @@ import java.util.List; import java.util.function.Consumer; import javax.tools.Diagnostic; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ModifiersTest extends KullaTesting { - @DataProvider(name = "ignoredModifiers") public Object[][] getTestCases() { List testCases = new ArrayList<>(); String[] ignoredModifiers = new String[] { @@ -77,7 +78,8 @@ public class ModifiersTest extends KullaTesting { return testCases.toArray(new Object[testCases.size()][]); } - @Test(dataProvider = "ignoredModifiers") + @ParameterizedTest + @MethodSource("getTestCases") public void ignoredModifiers(String modifier, ClassType classType, Consumer eval, String preface, String context) { if (context != null) { @@ -95,6 +97,7 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticFieldsOfClass() { assertEval("class A {" + "int x = 14;" + @@ -108,6 +111,7 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticMethodsOfClass() { assertEval("class A {" + "void x() {}" + @@ -119,6 +123,7 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticFieldsOfInterface() { assertEval("interface A {" + "int x = 14;" + @@ -134,12 +139,14 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticMethodsOfInterface() { assertEval("interface A { static void x() {} }"); assertEval("A.x();"); assertActiveKeys(); } + @Test public void finalMethod() { assertEval("class A { final void f() {} }"); assertDeclareFail("class B extends A { void f() {} }", @@ -148,6 +155,7 @@ public class ModifiersTest extends KullaTesting { } //TODO: is this the right semantics? + @Test public void finalConstructor() { assertDeclareFail("class A { final A() {} }", new ExpectedDiagnostic("compiler.err.mod.not.allowed.here", 10, 22, 16, -1, -1, Diagnostic.Kind.ERROR)); @@ -155,6 +163,7 @@ public class ModifiersTest extends KullaTesting { } //TODO: is this the right semantics? + @Test public void finalDefaultMethod() { assertDeclareFail("interface A { final default void a() {} }", new ExpectedDiagnostic("compiler.err.mod.not.allowed.here", 14, 39, 33, -1, -1, Diagnostic.Kind.ERROR)); diff --git a/test/langtools/jdk/jshell/MultipleDocumentationTest.java b/test/langtools/jdk/jshell/MultipleDocumentationTest.java index 8037381ccc8..d7894212016 100644 --- a/test/langtools/jdk/jshell/MultipleDocumentationTest.java +++ b/test/langtools/jdk/jshell/MultipleDocumentationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.io.PrintStream; import java.util.List; import java.util.stream.Collectors; import jdk.jshell.JShell; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /* * @test @@ -39,11 +39,11 @@ import static org.testng.Assert.assertEquals; * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build Compiler toolbox.ToolBox - * @run testng MultipleDocumentationTest + * @run junit MultipleDocumentationTest */ -@Test public class MultipleDocumentationTest { + @Test public void testMultipleDocumentation() { String input = "java.lang.String"; @@ -68,7 +68,7 @@ public class MultipleDocumentationTest { .map(d -> d.javadoc()) .collect(Collectors.toList()); - assertEquals(javadocs2, javadocs1); + assertEquals(javadocs1, javadocs2); } } } diff --git a/test/langtools/jdk/jshell/MyExecutionControl.java b/test/langtools/jdk/jshell/MyExecutionControl.java index 8493638db57..12a0ac6986d 100644 --- a/test/langtools/jdk/jshell/MyExecutionControl.java +++ b/test/langtools/jdk/jshell/MyExecutionControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.jshell.execution.Util; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl.EngineTerminationException; import jdk.jshell.spi.ExecutionEnv; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import static jdk.jshell.execution.Util.remoteInputOutput; class MyExecutionControl extends JdiExecutionControl { diff --git a/test/langtools/jdk/jshell/NullTest.java b/test/langtools/jdk/jshell/NullTest.java index b365b5155f8..c4759aca87f 100644 --- a/test/langtools/jdk/jshell/NullTest.java +++ b/test/langtools/jdk/jshell/NullTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ * @test * @summary null test * @build KullaTesting TestingInputStream - * @run testng NullTest + * @run junit NullTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class NullTest extends KullaTesting { + @Test public void testNull() { assertEval("null;", "null"); assertEval("(Object)null;", "null"); diff --git a/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java index 8ec8ded1741..350a6659c52 100644 --- a/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java +++ b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build PasteAndMeasurementsUITest - * @run testng/othervm PasteAndMeasurementsUITest + * @run junit/othervm PasteAndMeasurementsUITest */ import java.io.Console; @@ -46,15 +46,15 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import jdk.internal.org.jline.reader.impl.LineReaderImpl; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class PasteAndMeasurementsUITest extends UITesting { public PasteAndMeasurementsUITest() { super(true); } + @Test public void testPrevNextSnippet() throws Exception { Field cons = System.class.getDeclaredField("cons"); cons.setAccessible(true); @@ -77,6 +77,7 @@ public class PasteAndMeasurementsUITest extends UITesting { } private static final String LOC = "\033[12;1R"; + @Test public void testBracketedPaste() throws Exception { Field cons = System.class.getDeclaredField("cons"); cons.setAccessible(true); @@ -91,6 +92,7 @@ public class PasteAndMeasurementsUITest extends UITesting { }); } + @Test public void testBracketedPasteNonAscii() throws Exception { Field cons = System.class.getDeclaredField("cons"); cons.setAccessible(true); diff --git a/test/langtools/jdk/jshell/PipeInputStreamTest.java b/test/langtools/jdk/jshell/PipeInputStreamTest.java index 867a1f254a4..0062c6006e1 100644 --- a/test/langtools/jdk/jshell/PipeInputStreamTest.java +++ b/test/langtools/jdk/jshell/PipeInputStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Verify PipeInputStream works. * @modules jdk.compiler/com.sun.tools.javac.util * jdk.jshell/jdk.jshell.execution.impl:open - * @run testng PipeInputStreamTest + * @run junit PipeInputStreamTest */ import java.io.InputStream; @@ -34,28 +34,28 @@ import java.io.OutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import org.testng.annotations.Test; import com.sun.tools.javac.util.Pair; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class PipeInputStreamTest { + @Test public void testReadArrayNotBlocking() throws Exception { Pair streams = createPipeStream(); InputStream in = streams.fst; OutputStream out = streams.snd; out.write('a'); byte[] data = new byte[12]; - assertEquals(in.read(data), 1); - assertEquals(data[0], 'a'); + assertEquals(1, in.read(data)); + assertEquals('a', data[0]); out.write('a'); out.write('b'); out.write('c'); - assertEquals(in.read(data), 3); - assertEquals(data[0], 'a'); - assertEquals(data[1], 'b'); - assertEquals(data[2], 'c'); + assertEquals(3, in.read(data)); + assertEquals('a', data[0]); + assertEquals('b', data[1]); + assertEquals('c', data[2]); } private Pair createPipeStream() throws Exception { diff --git a/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java b/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java index f967b14d280..4d59e11e38b 100644 --- a/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java +++ b/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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,42 +25,46 @@ * @bug 8304487 8325257 * @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Preview) * @build KullaTesting TestingInputStream - * @run testng PrimitiveInstanceOfTest + * @run junit PrimitiveInstanceOfTest */ import jdk.jshell.JShell; -import org.testng.annotations.Test; import java.util.function.Consumer; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class PrimitiveInstanceOfTest extends KullaTesting { + @Test public void testInstanceOf() { assertEval("int i = 42;"); assertEval("i instanceof Integer"); assertEval("i instanceof int"); } + @Test public void testInstanceOfRef() { assertEval("Integer i = 42;"); assertEval("i instanceof Integer"); assertEval("i instanceof Number"); } + @Test public void testInstanceOfObjectToPrimitive() { assertEval("Object o = 1L;"); assertEval("o instanceof long"); assertEval("o instanceof Long"); } + @Test public void testInstanceOfPrimitiveToPrimitiveInvokingExactnessMethod() { assertEval("int b = 1024;"); assertEval("b instanceof byte"); } - @org.testng.annotations.BeforeMethod + @BeforeEach public void setUp() { super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); } diff --git a/test/langtools/jdk/jshell/RecordsTest.java b/test/langtools/jdk/jshell/RecordsTest.java index 69aaae8e46f..fdf75aed3ab 100644 --- a/test/langtools/jdk/jshell/RecordsTest.java +++ b/test/langtools/jdk/jshell/RecordsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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,27 +27,27 @@ * @summary Tests for evalution of records * @modules jdk.jshell * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng RecordsTest + * @run junit RecordsTest */ -import org.testng.annotations.Test; import javax.lang.model.SourceVersion; import jdk.jshell.Snippet.Status; import jdk.jshell.UnresolvedReferenceException; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -@Test public class RecordsTest extends KullaTesting { + @Test public void testRecordClass() { assertEval("record R(String s, int i) { }"); - assertEquals(varKey(assertEval("R r = new R(\"r\", 42);")).name(), "r"); + assertEquals("r", varKey(assertEval("R r = new R(\"r\", 42);")).name()); assertEval("r.s()", "\"r\""); assertEval("r.i()", "42"); } + @Test public void testRecordCorralling() { //simple record with a mistake that can be fixed by corralling: assertEval("record R1(int i) { int g() { return j; } }", ste(MAIN_SNIPPET, Status.NONEXISTENT, Status.RECOVERABLE_DEFINED, true, null)); @@ -66,13 +66,15 @@ public class RecordsTest extends KullaTesting { assertEval("R5 r5 = new R5(1);", null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, added(Status.VALID)); } + @Test public void testRecordField() { - assertEquals(varKey(assertEval("String record = \"\";")).name(), "record"); + assertEquals("record", varKey(assertEval("String record = \"\";")).name()); assertEval("record.length()", "0"); } + @Test public void testRecordMethod() { - assertEquals(methodKey(assertEval("String record(String record) { return record + record; }")).name(), "record"); + assertEquals("record", methodKey(assertEval("String record(String record) { return record + record; }")).name()); assertEval("record(\"r\")", "\"rr\""); assertEval("record(\"r\").length()", "2"); } diff --git a/test/langtools/jdk/jshell/RejectedFailedTest.java b/test/langtools/jdk/jshell/RejectedFailedTest.java index 5411d5d8aee..5e97a03d399 100644 --- a/test/langtools/jdk/jshell/RejectedFailedTest.java +++ b/test/langtools/jdk/jshell/RejectedFailedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ * @test 8080352 * @summary Tests for hard errors, like syntax errors * @build KullaTesting - * @run testng RejectedFailedTest + * @run junit RejectedFailedTest */ import java.util.List; import jdk.jshell.Snippet.SubKind; -import org.testng.annotations.Test; import jdk.jshell.Diag; import jdk.jshell.Snippet; @@ -40,31 +39,31 @@ import jdk.jshell.Snippet.Status; import jdk.jshell.SnippetEvent; import static java.util.stream.Collectors.toList; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class RejectedFailedTest extends KullaTesting { private String bad(String input, Kind kind, String prevId) { List events = assertEvalFail(input); - assertEquals(events.size(), 1, "Expected one event, got: " + events.size()); + assertEquals(1, events.size(), "Expected one event, got: " + events.size()); SnippetEvent e = events.get(0); List diagnostics = getState().diagnostics(e.snippet()).collect(toList()); assertTrue(diagnostics.size() > 0, "Expected diagnostics, got none"); - assertEquals(e.exception(), null, "Expected exception to be null."); - assertEquals(e.value(), null, "Expected value to be null."); + assertEquals(null, e.exception(), "Expected exception to be null."); + assertEquals(null, e.value(), "Expected value to be null."); Snippet key = e.snippet(); assertTrue(key != null, "key must be non-null, but was null."); - assertEquals(key.kind(), kind, "Expected kind: " + kind + ", got: " + key.kind()); + assertEquals(kind, key.kind(), "Expected kind: " + kind + ", got: " + key.kind()); SubKind expectedSubKind = kind == Kind.ERRONEOUS ? SubKind.UNKNOWN_SUBKIND : SubKind.METHOD_SUBKIND; - assertEquals(key.subKind(), expectedSubKind, "SubKind: "); + assertEquals(expectedSubKind, key.subKind(), "SubKind: "); assertTrue(key.id().compareTo(prevId) > 0, "Current id: " + key.id() + ", previous: " + prevId); - assertEquals(getState().diagnostics(key).collect(toList()), diagnostics, "Expected retrieved diagnostics to match, but didn't."); - assertEquals(key.source(), input, "Expected retrieved source: " + + assertEquals(diagnostics, getState().diagnostics(key).collect(toList()), "Expected retrieved diagnostics to match, but didn't."); + assertEquals(input, key.source(), "Expected retrieved source: " + key.source() + " to match input: " + input); - assertEquals(getState().status(key), Status.REJECTED, "Expected status of REJECTED, got: " + getState().status(key)); + assertEquals(Status.REJECTED, getState().status(key), "Expected status of REJECTED, got: " + getState().status(key)); return key.id(); } @@ -75,6 +74,7 @@ public class RejectedFailedTest extends KullaTesting { } } + @Test public void testErroneous() { String[] inputsErroneous = { "%&^%&", @@ -86,6 +86,7 @@ public class RejectedFailedTest extends KullaTesting { checkByKind(inputsErroneous, Kind.ERRONEOUS); } + @Test public void testBadMethod() { String[] inputsMethod = { "transient int m() { return x; }", diff --git a/test/langtools/jdk/jshell/ReplToolTesting.java b/test/langtools/jdk/jshell/ReplToolTesting.java index 5ca010af3c2..429a0a7ce02 100644 --- a/test/langtools/jdk/jshell/ReplToolTesting.java +++ b/test/langtools/jdk/jshell/ReplToolTesting.java @@ -46,14 +46,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.annotations.BeforeMethod; import jdk.jshell.tool.JavaShellToolBuilder; import static java.util.stream.Collectors.toList; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; public class ReplToolTesting { @@ -132,7 +132,7 @@ public class ReplToolTesting { .filter(l -> !l.isEmpty()) .collect(Collectors.toList()); int previousId = Integer.MIN_VALUE; - assertEquals(lines.size(), keys.size(), "Number of keys"); + assertEquals(keys.size(), lines.size(), "Number of keys"); for (int i = 0; i < lines.size(); ++i) { String line = lines.get(i); Matcher matcher = idPattern.matcher(line); @@ -155,7 +155,7 @@ public class ReplToolTesting { .filter(l -> !l.isEmpty()) .filter(l -> !l.startsWith("| ")) // error/unresolved info .collect(Collectors.toList()); - assertEquals(lines.size(), set.size(), message + " : expected: " + set.keySet() + "\ngot:\n" + lines); + assertEquals(set.size(), lines.size(), message + " : expected: " + set.keySet() + "\ngot:\n" + lines); for (String line : lines) { Matcher matcher = extractPattern.matcher(line); assertTrue(matcher.find(), line); @@ -271,7 +271,7 @@ public class ReplToolTesting { } } - @BeforeMethod + @BeforeEach public void setUp() { prefsMap = new HashMap<>(); prefsMap.put("INDENT", "0"); @@ -331,8 +331,7 @@ public class ReplToolTesting { String ueos = getUserErrorOutput(); assertTrue((cos.isEmpty() || cos.startsWith("| Goodbye") || !locale.equals(Locale.ROOT)), "Expected a goodbye, but got: " + cos); - assertEquals(ceos, - expectedErrorOutput, + assertEquals( expectedErrorOutput, ceos, "Expected \"" + expectedErrorOutput + "\" command error output, got: \"" + ceos + "\""); assertTrue(uos.isEmpty(), "Expected empty user output, got: " + uos); @@ -563,7 +562,7 @@ public class ReplToolTesting { public void assertOutput(String got, String expected, String display) { if (expected != null) { - assertEquals(got, expected, display + ".\n"); + assertEquals(expected, got, display + ".\n"); } } diff --git a/test/langtools/jdk/jshell/ReplaceTest.java b/test/langtools/jdk/jshell/ReplaceTest.java index e4c2c8575c0..02ebb27fcb9 100644 --- a/test/langtools/jdk/jshell/ReplaceTest.java +++ b/test/langtools/jdk/jshell/ReplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8080069 8152925 * @summary Test of Snippet redefinition and replacement. * @build KullaTesting TestingInputStream - * @run testng ReplaceTest + * @run junit ReplaceTest */ import java.util.Iterator; @@ -34,16 +34,16 @@ import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertFalse; import static jdk.jshell.Snippet.Status.*; import static jdk.jshell.Snippet.SubKind.*; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class ReplaceTest extends KullaTesting { + @Test public void testRedefine() { Snippet vx = varKey(assertEval("int x;")); Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); @@ -69,6 +69,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceClassToVar() { Snippet oldA = classKey(assertEval("class A { public String toString() { return \"old\"; } }")); Snippet v = varKey(assertEval("A a = new A();", "old")); @@ -92,6 +93,7 @@ public class ReplaceTest extends KullaTesting { assertFalse(it.hasNext(), "expected exactly one"); } + @Test public void testReplaceVarToMethod() { Snippet x = varKey(assertEval("int x;")); MethodSnippet musn = methodKey(assertEval("double mu() { return x * 4; }")); @@ -106,6 +108,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceMethodToMethod() { Snippet a = methodKey(assertEval("double a() { return 2; }")); Snippet b = methodKey(assertEval("double b() { return a() * 10; }")); @@ -119,6 +122,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceClassToMethod() { Snippet c = classKey(assertEval("class C { int f() { return 7; } }")); Snippet m = methodKey(assertEval("int m() { return new C().f(); }")); @@ -130,6 +134,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceVarToClass() { Snippet x = varKey(assertEval("int x;")); TypeDeclSnippet c = classKey(assertEval("class A { double a = 4 * x; }")); @@ -144,6 +149,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceMethodToClass() { Snippet x = methodKey(assertEval("int x() { return 0; }")); TypeDeclSnippet c = classKey(assertEval("class A { double a = 4 * x(); }")); @@ -159,6 +165,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceClassToClass() { TypeDeclSnippet a = classKey(assertEval("class A {}")); assertTypeDeclSnippet(a, "A", VALID, CLASS_SUBKIND, 0, 0); @@ -178,6 +185,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testOverwriteReplaceMethod() { MethodSnippet k1 = methodKey(assertEval("String m(Integer i) { return i.toString(); }")); MethodSnippet k2 = methodKey(assertEval("String m(java.lang.Integer i) { return \"java.lang.\" + i.toString(); }", @@ -193,6 +201,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testImportDeclare() { Snippet singleImport = importKey(assertEval("import java.util.List;", added(VALID))); Snippet importOnDemand = importKey(assertEval("import java.util.*;", added(VALID))); @@ -213,7 +222,8 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8129420 + @Test // TODO 8129420 + @Disabled public void testLocalClassEvolve() { Snippet j = methodKey(assertEval("Object j() { return null; }", added(VALID))); assertEval("Object j() { class B {}; return null; }", @@ -227,6 +237,7 @@ public class ReplaceTest extends KullaTesting { assertEval("j();", "Yep"); } + @Test public void testReplaceCausesMethodReferenceError() { Snippet l = classKey(assertEval("interface Logger { public void log(String message); }", added(VALID))); Snippet v = varKey(assertEval("Logger l = System.out::println;", added(VALID))); @@ -238,6 +249,7 @@ public class ReplaceTest extends KullaTesting { ste(v, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); } + @Test public void testReplaceCausesClassCompilationError() { Snippet l = classKey(assertEval("interface L { }", added(VALID))); Snippet c = classKey(assertEval("class C implements L { }", added(VALID))); @@ -249,6 +261,7 @@ public class ReplaceTest extends KullaTesting { ste(c, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); } + @Test public void testOverwriteNoUpdate() { String xsi = "int x = 5;"; String xsd = "double x = 3.14159;"; diff --git a/test/langtools/jdk/jshell/SealedClassesTest.java b/test/langtools/jdk/jshell/SealedClassesTest.java index ba4f8c8f008..c45bc767769 100644 --- a/test/langtools/jdk/jshell/SealedClassesTest.java +++ b/test/langtools/jdk/jshell/SealedClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @summary Test sealed class in jshell * @modules jdk.jshell * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng SealedClassesTest + * @run junit SealedClassesTest */ import javax.lang.model.SourceVersion; @@ -35,14 +35,13 @@ import javax.lang.model.SourceVersion; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.Snippet.Status; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.Test; -@Test public class SealedClassesTest extends KullaTesting { + @Test public void testSealed() { TypeDeclSnippet base = classKey( assertEval("sealed class B permits I {}", @@ -53,6 +52,7 @@ public class SealedClassesTest extends KullaTesting { assertEval("new I()"); } + @Test public void testInterface() { TypeDeclSnippet base = classKey( assertEval("sealed interface I permits C {}", @@ -63,6 +63,7 @@ public class SealedClassesTest extends KullaTesting { assertEval("new C()"); } + @Test public void testNonSealed() { TypeDeclSnippet base = classKey( assertEval("sealed class B permits I {}", @@ -74,6 +75,7 @@ public class SealedClassesTest extends KullaTesting { assertEval("new I2()"); } + @Test public void testNonSealedInterface() { TypeDeclSnippet base = classKey( assertEval("sealed interface B permits C {}", diff --git a/test/langtools/jdk/jshell/ShutdownTest.java b/test/langtools/jdk/jshell/ShutdownTest.java index d97b83950cc..9b68ab6f46b 100644 --- a/test/langtools/jdk/jshell/ShutdownTest.java +++ b/test/langtools/jdk/jshell/ShutdownTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Shutdown tests * @build KullaTesting TestingInputStream - * @run testng ShutdownTest + * @run junit ShutdownTest */ import java.io.IOException; @@ -37,11 +37,13 @@ import java.util.function.Consumer; import jdk.jshell.JShell; import jdk.jshell.JShell.Subscription; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; public class ShutdownTest extends KullaTesting { @@ -51,12 +53,13 @@ public class ShutdownTest extends KullaTesting { ++shutdownCount; } - @Test(enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testExit() { shutdownCount = 0; getState().onShutdown(this::shutdownCounter); assertEval("System.exit(1);"); - assertEquals(shutdownCount, 1); + assertEquals(1, shutdownCount); } @Test @@ -64,7 +67,7 @@ public class ShutdownTest extends KullaTesting { shutdownCount = 0; getState().onShutdown(this::shutdownCounter); getState().close(); - assertEquals(shutdownCount, 1); + assertEquals(1, shutdownCount); } @Test @@ -73,7 +76,7 @@ public class ShutdownTest extends KullaTesting { Subscription token = getState().onShutdown(this::shutdownCounter); getState().unsubscribe(token); getState().close(); - assertEquals(shutdownCount, 0); + assertEquals(0, shutdownCount); } @Test @@ -85,46 +88,56 @@ public class ShutdownTest extends KullaTesting { getState().unsubscribe(subscription1); getState().close(); - assertEquals(listener1.getEvents(), 0, "Checking got events"); - assertEquals(listener2.getEvents(), 1, "Checking got events"); + assertEquals(0, listener1.getEvents(), "Checking got events"); + assertEquals(1, listener2.getEvents(), "Checking got events"); getState().close(); - assertEquals(listener1.getEvents(), 0, "Checking got events"); - assertEquals(listener2.getEvents(), 1, "Checking got events"); + assertEquals(0, listener1.getEvents(), "Checking got events"); + assertEquals(1, listener2.getEvents(), "Checking got events"); getState().unsubscribe(subscription2); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testCloseException() { - getState().close(); - getState().eval("45"); + Assertions.assertThrows(IllegalStateException.class, () -> { + getState().close(); + getState().eval("45"); + }); } - @Test(expectedExceptions = IllegalStateException.class, - enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testShutdownException() { - assertEval("System.exit(0);"); - getState().eval("45"); + Assertions.assertThrows(IllegalStateException.class, () -> { + assertEval("System.exit(0);"); + getState().eval("45"); + }); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullCallback() { - getState().onShutdown(null); + Assertions.assertThrows(NullPointerException.class, () -> { + getState().onShutdown(null); + }); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testSubscriptionAfterClose() { - getState().close(); - getState().onShutdown(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + getState().close(); + getState().onShutdown(e -> {}); + }); } - @Test(expectedExceptions = IllegalStateException.class, - enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testSubscriptionAfterShutdown() { - assertEval("System.exit(0);"); - getState().onShutdown(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + assertEval("System.exit(0);"); + getState().onShutdown(e -> {}); + }); } @Test @@ -150,13 +163,13 @@ public class ShutdownTest extends KullaTesting { private Method currentTestMethod; - @BeforeMethod - public void setUp(Method testMethod) { - currentTestMethod = testMethod; + @BeforeEach + public void setUp(TestInfo testInfo) { + currentTestMethod = testInfo.getTestMethod().orElseThrow(); super.setUp(); } - @BeforeMethod + @BeforeEach public void setUp() { } diff --git a/test/langtools/jdk/jshell/SimpleRegressionTest.java b/test/langtools/jdk/jshell/SimpleRegressionTest.java index 1e347cfd207..4cd7c8b71eb 100644 --- a/test/langtools/jdk/jshell/SimpleRegressionTest.java +++ b/test/langtools/jdk/jshell/SimpleRegressionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8130450 8158906 8154374 8166400 8171892 8173807 8173848 8282434 * @summary simple regression test * @build KullaTesting TestingInputStream - * @run testng SimpleRegressionTest + * @run junit SimpleRegressionTest */ @@ -36,53 +36,56 @@ import javax.tools.Diagnostic; import jdk.jshell.Snippet; import jdk.jshell.VarSnippet; import jdk.jshell.SnippetEvent; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND; import static jdk.jshell.Snippet.Status.VALID; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class SimpleRegressionTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("local")); } + @Test public void testSnippetMemberAssignment() { assertEval("class C { int y; }"); assertEval("C c = new C();"); assertVarKeyMatch("c.y = 4;", true, "$1", TEMP_VAR_EXPRESSION_SUBKIND, "int", added(VALID)); } + @Test public void testUserTakesTempVarName() { assertEval("int $2 = 4;"); assertEval("String $1;"); assertVarKeyMatch("1234;", true, "$3", TEMP_VAR_EXPRESSION_SUBKIND, "int", added(VALID)); } + @Test public void testCompileThrow() { assertEvalException("throw new Exception();"); } + @Test public void testMultiSnippetDependencies() { List events = assertEval("int a = 3, b = a+a, c = b *100;", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, chain(added(VALID)), chain(added(VALID)), chain(added(VALID))); - assertEquals(events.get(0).value(), "3"); - assertEquals(events.get(1).value(), "6"); - assertEquals(events.get(2).value(), "600"); + assertEquals("3", events.get(0).value()); + assertEquals("6", events.get(1).value()); + assertEquals("600", events.get(2).value()); assertEval("c;", "600"); } + @Test public void testLessThanParsing() { assertEval("int x = 3;", "3"); assertEval("int y = 4;", "4"); @@ -92,18 +95,22 @@ public class SimpleRegressionTest extends KullaTesting { assertEval("x < y && y < z", "true"); } + @Test public void testNotStmtCannotResolve() { assertDeclareFail("dfasder;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 7, 0, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testNotStmtIncomparable() { assertDeclareFail("true == 5.0;", new ExpectedDiagnostic("compiler.err.incomparable.types", 0, 11, 5, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testStringAdd() { assertEval("String s = \"a\" + \"b\";", "\"ab\""); } + @Test public void testExprSanity() { assertEval("int x = 3;", "3"); assertEval("int y = 4;", "4"); @@ -111,13 +118,15 @@ public class SimpleRegressionTest extends KullaTesting { assertActiveKeys(); } + @Test public void testGenericMethodCrash() { assertDeclareWarn1(" void f(T...a) {}", (ExpectedDiagnostic) null); Snippet sn = methodKey(assertEval(" R n(R x) { return x; }", added(VALID))); VarSnippet sne = varKey(assertEval("n(5)", added(VALID))); - assertEquals(sne.typeName(), "Integer"); + assertEquals("Integer", sne.typeName()); } + @Test public void testLongRemoteStrings() { //8158906 assertEval("String m(int x) { byte[] b = new byte[x]; for (int i = 0; i < x; ++i) b[i] = (byte) 'a'; return new String(b); }"); boolean[] shut = new boolean[1]; @@ -127,12 +136,13 @@ public class SimpleRegressionTest extends KullaTesting { for (String len : new String[]{"12345", "64000", "65535", "65536", "120000"}) { List el = assertEval("m(" + len + ");"); assertFalse(shut[0], "JShell died with long string"); - assertEquals(el.size(), 1, "Excepted one event"); + assertEquals(1, el.size(), "Excepted one event"); assertTrue(el.get(0).value().length() > 10000, "Expected truncated but long String, got: " + el.get(0).value().length()); } } + @Test public void testLongRemoteJapaneseStrings() { //8158906 assertEval("import java.util.stream.*;"); assertEval("String m(int x) { return Stream.generate(() -> \"\u3042\").limit(x).collect(Collectors.joining()); }"); @@ -143,13 +153,14 @@ public class SimpleRegressionTest extends KullaTesting { for (String len : new String[]{"12345", "21843", "21844", "21845", "21846", "64000", "65535", "65536", "120000"}) { List el = assertEval("m(" + len + ");"); assertFalse(shut[0], "JShell died with long string"); - assertEquals(el.size(), 1, "Excepted one event"); + assertEquals(1, el.size(), "Excepted one event"); assertTrue(el.get(0).value().length() > 10000, "Expected truncated but long String, got: " + el.get(0).value().length()); } } // 8130450 + @Test public void testDuplicate() { Snippet snm = methodKey(assertEval("void mm() {}", added(VALID))); assertEval("void mm() {}", @@ -161,11 +172,13 @@ public class SimpleRegressionTest extends KullaTesting { ste(snv, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); } + @Test public void testContextClassLoader() { assertEval("class C {}"); assertEval("C.class.getClassLoader() == Thread.currentThread().getContextClassLoader()", "true"); } + @Test public void testArrayRepresentation() { assertEval("new int[4]", "int[4] { 0, 0, 0, 0 }"); assertEval("new int[0]", "int[0] { }"); @@ -183,6 +196,7 @@ public class SimpleRegressionTest extends KullaTesting { "Object[3] { \"howdy\", int[3] { 33, 44, 55 }, String[2] { \"up\", \"down\" } }"); } + @Test public void testMultiDimArrayRepresentation() { assertEval("new int[3][1]", "int[3][] { int[1] { 0 }, int[1] { 0 }, int[1] { 0 } }"); @@ -199,6 +213,7 @@ public class SimpleRegressionTest extends KullaTesting { "boolean[2][][] { boolean[1][] { boolean[3] { false, false, false } }, boolean[1][] { boolean[3] { false, false, false } } }"); } + @Test public void testStringRepresentation() { assertEval("\"A!\\rB!\"", "\"A!\\rB!\""); @@ -220,6 +235,7 @@ public class SimpleRegressionTest extends KullaTesting { "\"a\u032Ea\""); } + @Test public void testCharRepresentation() { for (String s : new String[]{"'A'", "'Z'", "'0'", "'9'", "'a'", "'z'", "'*'", "'%'", diff --git a/test/langtools/jdk/jshell/SnippetEventToStringTest.java b/test/langtools/jdk/jshell/SnippetEventToStringTest.java index 7d2de387951..7dacafe93d2 100644 --- a/test/langtools/jdk/jshell/SnippetEventToStringTest.java +++ b/test/langtools/jdk/jshell/SnippetEventToStringTest.java @@ -25,7 +25,7 @@ * @test * @bug 8350808 * @summary Check for proper formatting of SnippetEvent.toString() - * @run testng SnippetEventToStringTest + * @run junit SnippetEventToStringTest */ import java.util.Map; @@ -35,13 +35,14 @@ import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.execution.LocalExecutionControlProvider; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SnippetEventToStringTest { - @DataProvider(name = "cases") public String[][] sourceLevels() { return new String[][] { { "*", ",causeSnippet=null" }, @@ -50,11 +51,12 @@ public class SnippetEventToStringTest { }; } - @Test(dataProvider = "cases") - private void verifySnippetEvent(String source, String match) { + @ParameterizedTest + @MethodSource("sourceLevels") + void verifySnippetEvent(String source, String match) { try (JShell jsh = JShell.builder().executionEngine(new LocalExecutionControlProvider(), Map.of()).build()) { List result = jsh.eval(source); - assertEquals(result.size(), 1); + assertEquals(1, result.size()); String string = result.get(0).toString(); if (!string.contains(match)) throw new AssertionError(String.format("\"%s\" not found in \"%s\"", match, string)); diff --git a/test/langtools/jdk/jshell/SnippetHighlightTest.java b/test/langtools/jdk/jshell/SnippetHighlightTest.java index 902d4347f74..dbf3418af83 100644 --- a/test/langtools/jdk/jshell/SnippetHighlightTest.java +++ b/test/langtools/jdk/jshell/SnippetHighlightTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,22 +32,22 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng SnippetHighlightTest + * @run junit SnippetHighlightTest */ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import org.testng.annotations.Test; import jdk.jshell.SourceCodeAnalysis.Highlight; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class SnippetHighlightTest extends KullaTesting { + @Test public void testMemberExpr() { assertEval("@Deprecated class TestClass { }"); assertEval("class TestConstructor { @Deprecated TestConstructor() {} }"); @@ -99,6 +99,7 @@ public class SnippetHighlightTest extends KullaTesting { "Highlight[start=5, end=11, attributes=[DECLARATION]]"); } + @Test public void testClassErrorRecovery() { //JDK-8301580 assertHighlights(""" class C { @@ -114,6 +115,7 @@ public class SnippetHighlightTest extends KullaTesting { "Highlight[start=32, end=38, attributes=[KEYWORD]]"); } + @Test public void testNoCrashOnLexicalErrors() { //JDK-8359497 assertHighlights(""" " @@ -122,7 +124,7 @@ public class SnippetHighlightTest extends KullaTesting { private void assertHighlights(String code, String... expected) { List completions = computeHighlights(code); - assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString()); + assertEquals(Arrays.asList(expected), completions, "Input: " + code + ", " + completions.toString()); } private List computeHighlights(String code) { diff --git a/test/langtools/jdk/jshell/SnippetStatusListenerTest.java b/test/langtools/jdk/jshell/SnippetStatusListenerTest.java index 14ea0b956a7..205749af277 100644 --- a/test/langtools/jdk/jshell/SnippetStatusListenerTest.java +++ b/test/langtools/jdk/jshell/SnippetStatusListenerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 * @summary Subscribe tests * @build KullaTesting TestingInputStream - * @run testng SnippetStatusListenerTest + * @run junit SnippetStatusListenerTest */ import java.util.ArrayList; @@ -37,14 +37,16 @@ import jdk.jshell.DeclarationSnippet; import jdk.jshell.JShell.Subscription; import jdk.jshell.SnippetEvent; import jdk.jshell.TypeDeclSnippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class SnippetStatusListenerTest extends KullaTesting { + @Test public void testTwoSnippetEventListeners() { SnippetListener listener1 = new SnippetListener(); SnippetListener listener2 = new SnippetListener(); @@ -61,45 +63,52 @@ public class SnippetStatusListenerTest extends KullaTesting { assertEval("int a = 0;"); List events1 = Collections.unmodifiableList(listener1.getEvents()); - assertEquals(events1, listener2.getEvents(), "Checking got events"); + assertEquals(listener2.getEvents(), events1, "Checking got events"); getState().unsubscribe(subscription1); assertDrop(f, DiagCheck.DIAG_IGNORE, DiagCheck.DIAG_IGNORE, ste(f, REJECTED, DROPPED, false, null)); assertEval("void f() { }", added(VALID)); assertEvalException("throw new RuntimeException();"); - assertEquals(listener1.getEvents(), events1, "Checking that unsubscribed listener does not get events"); + assertEquals(events1, listener1.getEvents(), "Checking that unsubscribed listener does not get events"); List events2 = new ArrayList<>(listener2.getEvents()); events2.removeAll(events1); - assertEquals(events2.size(), 3, "The second listener got events"); + assertEquals(3, events2.size(), "The second listener got events"); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullCallback() { - getState().onSnippetEvent(null); + Assertions.assertThrows(NullPointerException.class, () -> { + getState().onSnippetEvent(null); + }); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testSubscriptionAfterClose() { - getState().close(); - getState().onSnippetEvent(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + getState().close(); + getState().onSnippetEvent(e -> {}); + }); } - @Test(expectedExceptions = IllegalStateException.class, - enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testSubscriptionAfterShutdown() { - assertEval("System.exit(0);"); - getState().onSnippetEvent(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + assertEval("System.exit(0);"); + getState().onSnippetEvent(e -> {}); + }); } + @Test public void testSubscriptionToAnotherState() { SnippetListener listener = new SnippetListener(); Subscription subscription = getState().onSnippetEvent(listener); tearDown(); setUp(); assertEval("int x;"); - assertEquals(Collections.emptyList(), listener.getEvents(), "No events"); + assertEquals(listener.getEvents(), Collections.emptyList(), "No events"); getState().unsubscribe(subscription); } diff --git a/test/langtools/jdk/jshell/SnippetTest.java b/test/langtools/jdk/jshell/SnippetTest.java index 3ccd0e42f4b..3e5bdbbf324 100644 --- a/test/langtools/jdk/jshell/SnippetTest.java +++ b/test/langtools/jdk/jshell/SnippetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * 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,74 +26,86 @@ * @bug 8139829 * @summary test accessors of Snippet * @build KullaTesting TestingInputStream - * @run testng SnippetTest + * @run junit SnippetTest */ import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet.Status; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class SnippetTest extends KullaTesting { + @Test public void testImportKey() { assertImportKeyMatch("import java.util.List;", "List", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); assertImportKeyMatch("import java.util.*;", "java.util.*", TYPE_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertImportKeyMatch("import static java.lang.String.*;", "java.lang.String.*", STATIC_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); } + @Test public void testClassKey() { assertDeclarationKeyMatch("class X {}", false, "X", CLASS_SUBKIND, added(VALID)); } + @Test public void testInterfaceKey() { assertDeclarationKeyMatch("interface I {}", false, "I", INTERFACE_SUBKIND, added(VALID)); } + @Test public void testEnumKey() { assertDeclarationKeyMatch("enum E {}", false, "E", ENUM_SUBKIND, added(VALID)); } + @Test public void testAnnotationKey() { assertDeclarationKeyMatch("@interface A {}", false, "A", ANNOTATION_TYPE_SUBKIND, added(VALID)); } + @Test public void testMethodKey() { assertDeclarationKeyMatch("void m() {}", false, "m", METHOD_SUBKIND, added(VALID)); } + @Test public void testVarDeclarationKey() { assertVarKeyMatch("int a;", true, "a", VAR_DECLARATION_SUBKIND, "int", added(VALID)); } + @Test public void testVarDeclarationWithInitializerKey() { assertVarKeyMatch("double b = 9.0;", true, "b", VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "double", added(VALID)); } + @Test public void testTempVarExpressionKey() { assertVarKeyMatch("47;", true, "$1", TEMP_VAR_EXPRESSION_SUBKIND, "int", added(VALID)); } + @Test public void testVarValueKey() { assertEval("double x = 4;", "4.0"); assertExpressionKeyMatch("x;", "x", VAR_VALUE_SUBKIND, "double"); } + @Test public void testAssignmentKey() { assertEval("int y;"); assertExpressionKeyMatch("y = 4;", "y", ASSIGNMENT_SUBKIND, "int"); } + @Test public void testStatementKey() { assertKeyMatch("if (true) {}", true, STATEMENT_SUBKIND, added(VALID)); assertKeyMatch("while (true) { break; }", true, STATEMENT_SUBKIND, added(VALID)); @@ -101,10 +113,12 @@ public class SnippetTest extends KullaTesting { assertKeyMatch("for (;;) { break; }", true, STATEMENT_SUBKIND, added(VALID)); } + @Test public void noKeys() { assertActiveKeys(new DeclarationSnippet[0]); } + @Test public void testKeyId1() { Snippet a = classKey(assertEval("class A { }")); assertEval("void f() { }"); @@ -116,7 +130,8 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void testKeyId2() { Snippet g = methodKey(assertEval("void g() { f(); }", added(RECOVERABLE_DEFINED))); Snippet f = methodKey(assertEval("void f() { }", @@ -136,6 +151,7 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); } + @Test public void testKeyId3() { Snippet g = methodKey(assertEval("void g() { f(); }", added(RECOVERABLE_DEFINED))); Snippet f = methodKey(assertEval("void f() { }", @@ -154,6 +170,7 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); } + @Test public void testBooleanSnippetQueries() { Snippet nd = varKey(assertEval("blort x;", added(RECOVERABLE_NOT_DEFINED))); assertTrue(nd.kind().isPersistent(), "nd.isPersistent"); diff --git a/test/langtools/jdk/jshell/SourceLevelTest.java b/test/langtools/jdk/jshell/SourceLevelTest.java index ce5572e6f71..f1092a5d2e8 100644 --- a/test/langtools/jdk/jshell/SourceLevelTest.java +++ b/test/langtools/jdk/jshell/SourceLevelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +26,16 @@ * @bug 8259820 * @summary Check JShell can handle -source 8 * @modules jdk.jshell - * @run testng SourceLevelTest + * @run junit SourceLevelTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SourceLevelTest extends ReplToolTesting { - @DataProvider(name="sourceLevels") public Object[][] sourceLevels() { return new Object[][] { new Object[] {"8"}, @@ -42,7 +43,8 @@ public class SourceLevelTest extends ReplToolTesting { }; } - @Test(dataProvider="sourceLevels") + @ParameterizedTest + @MethodSource("sourceLevels") public void testSourceLevel(String sourceLevel) { test(new String[] {"-C", "-source", "-C", sourceLevel}, (a) -> assertCommand(a, "1 + 1", "$1 ==> 2"), diff --git a/test/langtools/jdk/jshell/StartOptionTest.java b/test/langtools/jdk/jshell/StartOptionTest.java index 0d6a9d0d65f..0271d7df57b 100644 --- a/test/langtools/jdk/jshell/StartOptionTest.java +++ b/test/langtools/jdk/jshell/StartOptionTest.java @@ -32,7 +32,7 @@ * jdk.jshell/jdk.internal.jshell.tool.resources:+open * @library /tools/lib * @build Compiler toolbox.ToolBox - * @run testng/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch StartOptionTest + * @run junit/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch StartOptionTest */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -52,16 +52,15 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import jdk.jshell.JShell; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import jdk.jshell.tool.JavaShellToolBuilder; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class StartOptionTest { protected ByteArrayOutputStream cmdout; @@ -116,7 +115,7 @@ public class StartOptionTest { if (checkOut != null) { checkOut.accept(out); } else { - assertEquals(out, "", label + ": Expected empty -- "); + assertEquals("", out, label + ": Expected empty -- "); } } catch (Throwable t) { logOutput("cmdout", cmdout); @@ -139,7 +138,7 @@ public class StartOptionTest { if (checkCode != null) { checkCode.accept(ec); } else { - assertEquals(ec, 0, "Expected standard exit code (0), but found: " + ec); + assertEquals(0, ec, "Expected standard exit code (0), but found: " + ec); } } @@ -188,8 +187,7 @@ public class StartOptionTest { // Start with an exit code and command error check protected void startExCe(int eec, Consumer checkError, String... args) { - StartOptionTest.this.startExCoUoCeCn( - (Integer ec) -> assertEquals((int) ec, eec, + StartOptionTest.this.startExCoUoCeCn((Integer ec) -> assertEquals(eec, (int) ec, "Expected error exit code (" + eec + "), but found: " + ec), null, null, checkError, null, args); } @@ -202,7 +200,7 @@ public class StartOptionTest { private Consumer assertOrNull(String expected, String label) { return expected == null ? null - : s -> assertEquals(s.replaceAll("\\r\\n?", "\n").trim(), expected.trim(), label); + : s -> assertEquals(expected.trim(), s.replaceAll("\\r\\n?", "\n").trim(), label); } // Start and check the resultant: exit code (Ex), command output (Co), @@ -213,10 +211,9 @@ public class StartOptionTest { String expectedError, String expectedConsole, String... args) { - startExCoUoCeCn( - expectedExitCode == 0 + startExCoUoCeCn(expectedExitCode == 0 ? null - : (Integer i) -> assertEquals((int) i, expectedExitCode, + : (Integer i) -> assertEquals(expectedExitCode, (int) i, "Expected exit code (" + expectedExitCode + "), but found: " + i), assertOrNull(expectedCmdOutput, "cmdout: "), assertOrNull(expectedUserOutput, "userout: "), @@ -240,7 +237,7 @@ public class StartOptionTest { startExCoUoCeCn(0, null, expectedUserOutput, null, null, args); } - @BeforeMethod + @BeforeEach public void setUp() { cmdout = new ByteArrayOutputStream(); cmderr = new ByteArrayOutputStream(); @@ -267,6 +264,7 @@ public class StartOptionTest { } // Test load files + @Test public void testCommandFile() { String fn = writeToFile("String str = \"Hello \"\n" + "/list\n" + @@ -281,6 +279,7 @@ public class StartOptionTest { } // Test that the usage message is printed + @Test public void testUsage() { for (String opt : new String[]{"-?", "-h", "--help"}) { startCo(s -> { @@ -293,6 +292,7 @@ public class StartOptionTest { } // Test the --help-extra message + @Test public void testHelpExtra() { for (String opt : new String[]{"-X", "--help-extra"}) { startCo(s -> { @@ -305,12 +305,14 @@ public class StartOptionTest { } // Test handling of bogus options + @Test public void testUnknown() { startExCe(1, "Unknown option: u", "-unknown"); startExCe(1, "Unknown option: unknown", "--unknown"); } // Test that input is read with "-" and there is no extra output. + @Test public void testHypenFile() { setIn("System.out.print(\"Hello\");\n"); startUo("Hello", "-"); @@ -327,6 +329,7 @@ public class StartOptionTest { } // Test that user specified exit codes are propagated + @Test public void testExitCode() { setIn("/exit 57\n"); startExCoUoCeCn(57, null, null, null, "-> /exit 57", "-s"); @@ -341,11 +344,13 @@ public class StartOptionTest { } // Test that non-existent load file sends output to stderr and does not startExCe (no welcome). + @Test public void testUnknownLoadFile() { startExCe(1, "File 'UNKNOWN' for 'jshell' is not found.", "UNKNOWN"); } // Test bad usage of the --startup option + @Test public void testStartup() { String fn = writeToFile(""); startExCe(1, "Argument to startup missing.", "--startup"); @@ -355,18 +360,21 @@ public class StartOptionTest { } // Test an option that causes the back-end to fail is propagated + @Test public void testStartupFailedOption() { startExCe(1, s -> assertTrue(s.contains("Unrecognized option: -hoge-foo-bar"), "cmderr: " + s), "-R-hoge-foo-bar"); } // Test the use of non-existant files with the --startup option + @Test public void testStartupUnknown() { startExCe(1, "File 'UNKNOWN' for '--startup' is not found.", "--startup", "UNKNOWN"); startExCe(1, "File 'UNKNOWN' for '--startup' is not found.", "--startup", "DEFAULT", "--startup", "UNKNOWN"); } // Test bad usage of --class-path option + @Test public void testClasspath() { for (String cp : new String[]{"--class-path"}) { startExCe(1, "Only one --class-path option may be used.", cp, ".", "--class-path", "."); @@ -375,12 +383,14 @@ public class StartOptionTest { } // Test bogus module on --add-modules option + @Test public void testUnknownModule() { startExCe(1, s -> assertTrue(s.contains("rror") && s.contains("unKnown"), "cmderr: " + s), "--add-modules", "unKnown"); } // Test that muliple feedback options fail + @Test public void testFeedbackOptionConflict() { startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "concise", "--feedback", "verbose"); @@ -395,12 +405,14 @@ public class StartOptionTest { } // Test bogus arguments to the --feedback option + @Test public void testNegFeedbackOption() { startExCe(1, "Argument to feedback missing.", "--feedback"); startExCe(1, "Does not match any current feedback mode: blorp -- --feedback blorp", "--feedback", "blorp"); } // Test --version + @Test public void testVersion() { startCo(s -> { assertTrue(s.startsWith("jshell"), "unexpected version: " + s); @@ -410,6 +422,7 @@ public class StartOptionTest { } // Test --show-version + @Test public void testShowVersion() { startExCoUoCeCn(null, s -> { @@ -422,6 +435,7 @@ public class StartOptionTest { "--show-version"); } + @Test public void testPreviewEnabled() { String fn = writeToFile( """ @@ -430,18 +444,18 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + startCheckUserOutput(s -> assertEquals("prefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), fn); String fn24 = writeToFile( """ System.out.println(\"test\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C--release", "-C24", fn24); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C--source", "-C24", fn24); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C-source", "-C24", fn24); //JDK-8341631: String fn2 = writeToFile( @@ -451,7 +465,7 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\ntest\nsuffix\n"), + startCheckUserOutput(s -> assertEquals("prefix\ntest\nsuffix\n", s), fn2); //verify the correct resource is selected when --enable-preview, relies on //--patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch @@ -462,7 +476,7 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\nHello!\nsuffix\n"), + startCheckUserOutput(s -> assertEquals("prefix\nHello!\nsuffix\n", s), "--enable-preview", fn2Preview, "-"); @@ -482,7 +496,7 @@ public class StartOptionTest { """ /exit """); - startCheckUserOutput(s -> assertEquals(s, "Custom start script\n"), + startCheckUserOutput(s -> assertEquals("Custom start script\n", s), exit); String clearStartup = writeToFile( """ @@ -498,16 +512,16 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckCommandUserOutput(s -> assertEquals(s, "/set start -retain -default\n"), - s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), - s -> assertEquals(s, "/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + startCheckCommandUserOutput(s -> assertEquals("/set start -retain -default\n", s), + s -> assertEquals("prefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), + s -> assertEquals("/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), retainTest); String retainTest24 = writeToFile( """ System.out.println(\"test\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C--release", "-C24", retainTest24); String set24DefaultTest = writeToFile( @@ -526,12 +540,13 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckCommandUserOutput(s -> assertEquals(s, "/set start -retain -default\n"), - s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), - s -> assertEquals(s, "/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + startCheckCommandUserOutput(s -> assertEquals("/set start -retain -default\n", s), + s -> assertEquals("prefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), + s -> assertEquals("/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), checkDefaultAfterSet24Test); } + @Test public void testInput() { //readLine(String): String readLinePrompt = writeToFile( @@ -540,7 +555,7 @@ public class StartOptionTest { System.out.println(v); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prompt: null\n"), + startCheckUserOutput(s -> assertEquals("prompt: null\n", s), readLinePrompt); //readPassword(String): String readPasswordPrompt = writeToFile( @@ -549,10 +564,11 @@ public class StartOptionTest { System.out.println(java.util.Arrays.toString(v)); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prompt: null\n"), + startCheckUserOutput(s -> assertEquals("prompt: null\n", s), readPasswordPrompt); } + @Test public void testErroneousFile() { String code = """ var v = ( @@ -567,12 +583,12 @@ public class StartOptionTest { .getString("jshell.err.incomplete.input"); String expectedError = new MessageFormat(expectedErrorFormat).format(new Object[] {code}); - startCheckError(s -> assertEquals(s, expectedError), + startCheckError(s -> assertEquals(expectedError, s), readLinePrompt); } - @AfterMethod + @AfterEach public void tearDown() { cmdout = null; cmderr = null; diff --git a/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java b/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java index b0695ae8636..918e8f7984d 100644 --- a/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java +++ b/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +31,16 @@ * @library /tools/lib * @build toolbox.ToolBox * @build KullaTesting Compiler - * @run testng StartupWithFormatSpecifierTest + * @run junit StartupWithFormatSpecifierTest */ import java.nio.file.Path; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class StartupWithFormatSpecifierTest extends ReplToolTesting { + @Test public void testStartupWithFormatSpecifier() { Compiler compiler = new Compiler(); String startupScript = "String.format(\"This is a %s.\", \"test\");"; diff --git a/test/langtools/jdk/jshell/StopExecutionTest.java b/test/langtools/jdk/jshell/StopExecutionTest.java index b1584c0eb89..eae515da6e5 100644 --- a/test/langtools/jdk/jshell/StopExecutionTest.java +++ b/test/langtools/jdk/jshell/StopExecutionTest.java @@ -27,7 +27,7 @@ * @summary Test JShell#stop * @modules jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng StopExecutionTest + * @run junit StopExecutionTest */ import java.io.IOException; @@ -39,28 +39,31 @@ import java.util.function.Consumer; import jdk.internal.jshell.tool.StopDetectingInputStream; import jdk.internal.jshell.tool.StopDetectingInputStream.State; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class StopExecutionTest extends AbstractStopExecutionTest { - @Test(enabled = false) // TODO 8129546 + @Test // TODO 8129546 + @Disabled public void testStopLoop() throws InterruptedException { scheduleStop("while (true) ;"); } - @Test(enabled = false) // TODO 8129546 + @Test // TODO 8129546 + @Disabled public void testStopASleep() throws InterruptedException { scheduleStop("while (true) { try { Thread.sleep(100); } catch (InterruptedException ex) { } }"); } - @Test(enabled = false) // TODO 8129546 + @Test // TODO 8129546 + @Disabled public void testScriptCatchesStop() throws Exception { scheduleStop("for (int i = 0; i < 30; i++) { try { Thread.sleep(100); } catch (Throwable ex) { } }"); } + @Test public void testStopDetectingInputRandom() throws IOException { long seed = System.nanoTime(); Random r = new Random(seed); @@ -86,10 +89,11 @@ public class StopExecutionTest extends AbstractStopExecutionTest { for (int c = 0; c < chunkSize; c++) { int read = buffer.read(); - assertEquals(read, c); + assertEquals(c, read); } } + @Test public void testStopDetectingInputBufferWaitStop() throws Exception { Runnable shouldNotHappenRun = () -> { throw new AssertionError("Should not happen."); }; diff --git a/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java b/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java index 8cf92545bb5..21cb37e65b3 100644 --- a/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java +++ b/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +27,14 @@ * @summary Test Smashing Error when user language is Japanese * @library /tools/lib /jdk/jshell * @build KullaTesting - * @run testng/othervm -Duser.language=ja JShellTest8146368 + * @run junit/othervm -Duser.language=ja JShellTest8146368 */ import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JShellTest8146368 extends KullaTesting { + @Test public void test() { assertEval("class A extends B {}", added(RECOVERABLE_NOT_DEFINED)); assertEval("und m() { return new und(); }", added(RECOVERABLE_NOT_DEFINED)); diff --git a/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java b/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java index 101083c0e27..3a7db71be71 100644 --- a/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java +++ b/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,13 +28,13 @@ * @modules jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib /jdk/jshell * @build ReplToolTesting - * @run testng/othervm -Duser.language=ja JShellToolTest8146368 + * @run junit/othervm -Duser.language=ja JShellToolTest8146368 */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JShellToolTest8146368 extends ReplToolTesting { + @Test public void test() { test( a -> assertCommand(a, "class A extends B {}", "| created class A, however, it cannot be referenced until class B is declared\n"), diff --git a/test/langtools/jdk/jshell/Test8294583.java b/test/langtools/jdk/jshell/Test8294583.java index 3d2ce2e3638..281911b7113 100644 --- a/test/langtools/jdk/jshell/Test8294583.java +++ b/test/langtools/jdk/jshell/Test8294583.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,22 +26,23 @@ * @bug 8294583 * @summary JShell: NPE in switch with non existing record pattern * @build KullaTesting TestingInputStream - * @run testng Test8294583 + * @run junit Test8294583 */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class Test8294583 extends KullaTesting { + @Test public void test() { assertEvalFail("switch (new Object()) {\n" + " case Foo() -> {}\n" + "};"); } - @org.testng.annotations.BeforeMethod + @BeforeEach public void setUp() { super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); } diff --git a/test/langtools/jdk/jshell/Test8296012.java b/test/langtools/jdk/jshell/Test8296012.java index 73e5cc06ae0..4f08861b952 100644 --- a/test/langtools/jdk/jshell/Test8296012.java +++ b/test/langtools/jdk/jshell/Test8296012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,21 +26,22 @@ * @bug 8296012 * @summary jshell crashes on mismatched record pattern * @build KullaTesting TestingInputStream - * @run testng Test8296012 + * @run junit Test8296012 */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class Test8296012 extends KullaTesting { + @Test public void test() { assertEval("record Foo(int x, int y) {}"); assertEvalFail("switch (new Foo(1, 2)) { case Foo(int z) -> z; }"); } - @org.testng.annotations.BeforeMethod + @BeforeEach public void setUp() { super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); } diff --git a/test/langtools/jdk/jshell/ToolBasicTest.java b/test/langtools/jdk/jshell/ToolBasicTest.java index b5128de738a..5015d1f64b1 100644 --- a/test/langtools/jdk/jshell/ToolBasicTest.java +++ b/test/langtools/jdk/jshell/ToolBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng/timeout=600 ToolBasicTest + * @run junit/timeout=600 ToolBasicTest * @key intermittent */ @@ -57,19 +57,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.sun.net.httpserver.HttpServer; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.fail; - -@Test public class ToolBasicTest extends ReplToolTesting { + @Test public void elideStartUpFromList() { - test( - (a) -> assertCommandOutputContains(a, "123", "==> 123"), + test((a) -> assertCommandOutputContains(a, "123", "==> 123"), (a) -> assertCommandCheckOutput(a, "/list", (s) -> { int cnt; try (Scanner scanner = new Scanner(s)) { @@ -81,11 +80,12 @@ public class ToolBasicTest extends ReplToolTesting { } } } - assertEquals(cnt, 1, "Expected only one listed line"); + assertEquals(1, cnt, "Expected only one listed line"); }) ); } + @Test public void elideStartUpFromSave() throws IOException { Compiler compiler = new Compiler(); Path path = compiler.getPath("myfile"); @@ -94,10 +94,11 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertCommand(a, "/save " + path.toString(), "") ); try (Stream lines = Files.lines(path)) { - assertEquals(lines.count(), 1, "Expected only one saved line"); + assertEquals(1, lines.count(), "Expected only one saved line"); } } + @Test public void testInterrupt() { ReplTest interrupt = (a) -> assertCommand(a, "\u0003", ""); for (String s : new String[] { "", "\u0003" }) { @@ -132,6 +133,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testCtrlD() { test(false, new String[]{"--no-startup"}, a -> { @@ -193,6 +195,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testStop() { test( (a) -> assertStop(a, "while (true) {}", ""), @@ -200,6 +203,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRerun() { test(false, new String[] {"--no-startup"}, (a) -> assertCommand(a, "/0", "| No snippet with ID: 0"), @@ -221,7 +225,7 @@ public class ToolBasicTest extends ReplToolTesting { final int finalI = i; Consumer check = (s) -> { String[] ss = s.split("\n"); - assertEquals(ss[0], codes[finalI]); + assertEquals(codes[finalI], ss[0]); assertTrue(ss.length > 1, s); }; tests.add((a) -> assertCommandCheckOutput(a, "/" + (finalI + 1), check)); @@ -231,7 +235,7 @@ public class ToolBasicTest extends ReplToolTesting { final int finalI = i; Consumer check = (s) -> { String[] ss = s.split("\n"); - assertEquals(ss[0], codes[codes.length - finalI - 1]); + assertEquals(codes[codes.length - finalI - 1], ss[0]); assertTrue(ss.length > 1, s); }; tests.add((a) -> assertCommandCheckOutput(a, "/-" + (2 * finalI + 1), check)); @@ -241,11 +245,12 @@ public class ToolBasicTest extends ReplToolTesting { tests.toArray(new ReplTest[tests.size()])); } + @Test public void test8142447() { Function> assertRerun = cmd -> (code, assertionCount) -> (a) -> assertCommandCheckOutput(a, cmd, s -> { String[] ss = s.split("\n"); - assertEquals(ss[0], code); + assertEquals(code, ss[0]); loadVariable(a, "int", "assertionCount", Integer.toString(assertionCount), Integer.toString(assertionCount)); }); ReplTest assertVariables = (a) -> assertCommandCheckOutput(a, "/v", assertVariables()); @@ -256,7 +261,7 @@ public class ToolBasicTest extends ReplToolTesting { "void add(int n) { assertionCount += n; }"); test(new String[]{"--startup", startup.toString()}, (a) -> assertCommand(a, "add(1)", ""), // id: 1 - (a) -> assertCommandCheckOutput(a, "add(ONE)", s -> assertEquals(s.split("\n")[0], "| Error:")), // id: e1 + (a) -> assertCommandCheckOutput(a, "add(ONE)", s -> assertEquals("| Error:", s.split("\n")[0])), // id: e1 (a) -> assertVariable(a, "int", "ONE", "1", "1"), assertRerun.apply("/1").apply("add(1)", 2), assertVariables, assertRerun.apply("/e1").apply("add(ONE)", 3), assertVariables, @@ -270,6 +275,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testClasspathDirectory() { Compiler compiler = new Compiler(); Path outDir = Paths.get("testClasspathDirectory"); @@ -285,6 +291,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testEnvInStartUp() { Compiler compiler = new Compiler(); Path outDir = Paths.get("testClasspathDirectory"); @@ -320,6 +327,7 @@ public class ToolBasicTest extends ReplToolTesting { return compiler.getPath(outDir).resolve(jarName).toString(); } + @Test public void testClasspathJar() { String jarPath = makeSimpleJar(); test( @@ -332,6 +340,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testClasspathUserHomeExpansion() { String jarPath = makeSimpleJar(); String tilde = "~" + File.separator; @@ -346,6 +355,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testBadClasspath() { String jarPath = makeSimpleJar(); Compiler compiler = new Compiler(); @@ -373,6 +383,7 @@ public class ToolBasicTest extends ReplToolTesting { return compiler.getPath(outDir).resolve(jarName).toString(); } + @Test public void testBadSourceJarClasspath() { String jarPath = makeBadSourceJar(); test( @@ -391,6 +402,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testModulePath() { Compiler compiler = new Compiler(); Path modsDir = Paths.get("mods"); @@ -406,6 +418,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testModulePathUserHomeExpansion() { String tilde = "~" + File.separatorChar; test( @@ -415,6 +428,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testBadModulePath() { Compiler compiler = new Compiler(); Path t1 = compiler.getPath("whatever/thing.zip"); @@ -425,6 +439,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testStartupFileOption() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("StartupFileOption/startup.txt"); @@ -440,6 +455,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testLoadingFromArgs() { Compiler compiler = new Compiler(); Path path = compiler.getPath("loading.repl"); @@ -450,6 +466,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testReset() { test( (a) -> assertReset(a, "/res"), @@ -470,6 +487,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testOpen() { Compiler compiler = new Compiler(); Path path = compiler.getPath("testOpen.repl"); @@ -504,6 +522,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testOpenLocalFileUrl() { Compiler compiler = new Compiler(); Path path = compiler.getPath("testOpen.repl"); @@ -518,6 +537,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testOpenFileOverHttp() throws IOException { var script = "int a = 10;int b = 20;int c = a + b;"; @@ -549,6 +569,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testOpenResource() { test(new String[]{"-R", "-Duser.language=en", "-R", "-Duser.country=US"}, (a) -> assertCommand(a, "/open PRINTING", ""), @@ -559,6 +580,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testSave() throws IOException { Compiler compiler = new Compiler(); Path path = compiler.getPath("testSave.repl"); @@ -573,7 +595,7 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), (a) -> assertCommand(a, "/save " + path.toString(), "") ); - assertEquals(Files.readAllLines(path), list); + assertEquals(list, Files.readAllLines(path)); } { List output = new ArrayList<>(); @@ -589,7 +611,7 @@ public class ToolBasicTest extends ReplToolTesting { .collect(Collectors.toList()))), (a) -> assertCommand(a, "/save -all " + path.toString(), "") ); - assertEquals(Files.readAllLines(path), output); + assertEquals(output, Files.readAllLines(path)); } { List output = new ArrayList<>(); @@ -606,7 +628,7 @@ public class ToolBasicTest extends ReplToolTesting { .collect(Collectors.toList()))), (a) -> assertCommand(a, "/save 2-3 1 4 " + path.toString(), "") ); - assertEquals(Files.readAllLines(path), output); + assertEquals(output, Files.readAllLines(path)); } { List output = new ArrayList<>(); @@ -621,10 +643,11 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertCommand(a, "/save -history " + path.toString(), "") ); output.add("/save -history " + path.toString()); - assertEquals(Files.readAllLines(path), output); + assertEquals(output, Files.readAllLines(path)); } } + @Test public void testStartRetain() { Compiler compiler = new Compiler(); Path startUpFile = compiler.getPath("startUp.txt"); @@ -655,6 +678,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testStartSave() throws IOException { Compiler compiler = new Compiler(); Path startSave = compiler.getPath("startSave.txt"); @@ -662,9 +686,10 @@ public class ToolBasicTest extends ReplToolTesting { List lines = Files.lines(startSave) .filter(s -> !s.isEmpty()) .collect(Collectors.toList()); - assertEquals(lines, START_UP); + assertEquals(START_UP, lines); } + @Test public void testConstrainedUpdates() { test( a -> assertClass(a, "class XYZZY { }", "class", "XYZZY"), @@ -674,6 +699,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRemoteExit() { test( a -> assertVariable(a, "int", "x"), @@ -686,11 +712,13 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testFeedbackNegative() { test(a -> assertCommandCheckOutput(a, "/set feedback aaaa", assertStartsWith("| Does not match any current feedback mode"))); } + @Test public void testFeedbackSilent() { for (String off : new String[]{"s", "silent"}) { test( @@ -702,6 +730,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testFeedbackNormal() { Compiler compiler = new Compiler(); Path testNormalFile = compiler.getPath("testConciseNormal"); @@ -728,6 +757,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testVarsWithNotActive() { test( a -> assertVariable(a, "Blath", "x"), @@ -735,6 +765,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testHistoryReference() { test(false, new String[]{"--no-startup"}, a -> assertCommand(a, "System.err.println(99)", "", "", null, "", "99\n"), @@ -767,6 +798,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRerunIdRange() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("rangeStartup"); @@ -825,7 +857,8 @@ public class ToolBasicTest extends ReplToolTesting { ); } - @Test(enabled = false) // TODO 8158197 + @Test // TODO 8158197 + @Disabled public void testHeadlessEditPad() { String prevHeadless = System.getProperty("java.awt.headless"); try { @@ -838,6 +871,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testAddExports() { test(false, new String[]{"--no-startup"}, a -> assertCommandOutputStartsWith(a, "import jdk.internal.misc.VM;", "| Error:") @@ -854,6 +888,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRedeclareVariableNoInit() { test( a -> assertCommand(a, "Integer a;", "a ==> null"), @@ -865,6 +900,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testWarningUnchecked() { //8223688 test(false, new String[]{"--no-startup"}, a -> assertCommand(a, "abstract class A { A(T t){} }", "| created class A"), @@ -876,6 +912,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testIndent() { //8223688 prefsMap.remove("INDENT"); test(false, new String[]{"--no-startup"}, @@ -887,6 +924,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testSystemExitStartUp() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("SystemExitStartUp/startup.txt"); diff --git a/test/langtools/jdk/jshell/ToolCommandOptionTest.java b/test/langtools/jdk/jshell/ToolCommandOptionTest.java index affeabacb7a..aea2fd93f17 100644 --- a/test/langtools/jdk/jshell/ToolCommandOptionTest.java +++ b/test/langtools/jdk/jshell/ToolCommandOptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +30,16 @@ * jdk.compiler/com.sun.tools.javac.main * @library /tools/lib * @build ToolCommandOptionTest ReplToolTesting - * @run testng ToolCommandOptionTest + * @run junit ToolCommandOptionTest */ import java.nio.file.Path; -import org.testng.annotations.Test; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ToolCommandOptionTest extends ReplToolTesting { + @Test public void listTest() { test( (a) -> assertCommand(a, "int x;", @@ -67,6 +67,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void typesTest() { test( (a) -> assertCommand(a, "int x", @@ -92,6 +93,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void dropTest() { test(false, new String[]{"--no-startup"}, (a) -> assertCommand(a, "int x = 5;", @@ -120,6 +122,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setEditorTest() { test( (a) -> assertCommand(a, "/set editor -furball", @@ -157,6 +160,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainEditorTest() { test( (a) -> assertCommand(a, "/set editor -retain -furball", @@ -211,6 +215,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setEditorEnvTest() { setEnvVar("EDITOR", "best one"); setEditorEnvSubtest(); @@ -244,6 +249,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setStartTest() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("StartTest/startup.txt"); @@ -288,6 +294,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainStartTest() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("StartTest/startup.txt"); @@ -337,6 +344,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setModeTest() { test( (a) -> assertCommandOutputContains(a, "/set mode", @@ -399,6 +407,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setModeSmashTest() { test( (a) -> assertCommand(a, "/set mode mymode -command", @@ -428,6 +437,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainModeTest() { test( (a) -> assertCommandOutputStartsWith(a, "/set mode -retain", @@ -531,6 +541,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainModeDeleteLocalTest() { test( (a) -> assertCommand(a, "/set mode rmdlt normal -command", diff --git a/test/langtools/jdk/jshell/ToolCompletionTest.java b/test/langtools/jdk/jshell/ToolCompletionTest.java index 9997db45c4d..9cd07e0684b 100644 --- a/test/langtools/jdk/jshell/ToolCompletionTest.java +++ b/test/langtools/jdk/jshell/ToolCompletionTest.java @@ -34,14 +34,14 @@ * java.desktop * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build ReplToolTesting TestingInputStream Compiler - * @run testng ToolCompletionTest + * @run junit ToolCompletionTest */ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ToolCompletionTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java b/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java index 212301c0fd8..54cae875d89 100644 --- a/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java +++ b/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ * @bug 8268725 * @summary Tests for the --enable-native-access option * @modules jdk.jshell - * @run testng ToolEnableNativeAccessTest + * @run junit ToolEnableNativeAccessTest */ -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class ToolEnableNativeAccessTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java index 1825e7b39ad..d6d01389ac0 100644 --- a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java +++ b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8199193 * @summary Tests for the --enable-preview option - * @run testng ToolEnablePreviewTest + * @run junit ToolEnablePreviewTest */ import java.io.IOException; @@ -33,9 +33,8 @@ import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class ToolEnablePreviewTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/ToolFormatTest.java b/test/langtools/jdk/jshell/ToolFormatTest.java index 3aaf5e79ea5..5d25fb99928 100644 --- a/test/langtools/jdk/jshell/ToolFormatTest.java +++ b/test/langtools/jdk/jshell/ToolFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,21 +31,22 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng ToolFormatTest + * @run junit ToolFormatTest */ import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class ToolFormatTest extends ReplToolTesting { + @Test public void testSetFormat() { try { test( @@ -86,6 +87,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetFormatOverride() { test( (a) -> assertCommand(a, "/set mode tm -c", "| Created new feedback mode: tm"), @@ -138,6 +140,7 @@ public class ToolFormatTest extends ReplToolTesting { ); } + @Test public void testSetFormatSelectorSample() { test( (a) -> assertCommandOutputStartsWith(a, "/set mode ate -quiet", @@ -197,7 +200,8 @@ public class ToolFormatTest extends ReplToolTesting { // A sampling of these has been added (above: testSetFormatSelectorSample). // See 8173007 // Save for possible future deep testing or debugging - @Test(enabled = false) + @Test + @Disabled public void testSetFormatSelector() { List tests = new ArrayList<>(); tests.add((a) -> assertCommandOutputStartsWith(a, "/set mode ate -quiet", @@ -278,6 +282,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetTruncation() { try { test( @@ -309,6 +314,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testDefaultTruncation() { test( (a) -> assertCommand(a, "char[] cs = new char[2000];", null), @@ -331,9 +337,9 @@ public class ToolFormatTest extends ReplToolTesting { ); } + @Test public void testPrompt() { - test( - (a) -> assertCommand(a, "/set mode tp -quiet", "| Created new feedback mode: tp"), + test((a) -> assertCommand(a, "/set mode tp -quiet", "| Created new feedback mode: tp"), (a) -> assertCommand(a, "/set prompt tp 'aaa' 'bbb'", ""), (a) -> assertCommand(a, "/set prompt tp", "| /set prompt tp \"aaa\" \"bbb\""), @@ -347,21 +353,21 @@ public class ToolFormatTest extends ReplToolTesting { (s) -> { try { BufferedReader rdr = new BufferedReader(new StringReader(s)); - assertEquals(rdr.readLine(), "| /set mode tp -quiet", + assertEquals("| /set mode tp -quiet", rdr.readLine(), "| /set mode tp -quiet"); - assertEquals(rdr.readLine(), "| /set prompt tp \"aaa\" \"bbb\"", + assertEquals("| /set prompt tp \"aaa\" \"bbb\"", rdr.readLine(), "| /set prompt tp \"aaa\" \"bbb\""); String l = rdr.readLine(); while (l.startsWith("| /set format tp ")) { l = rdr.readLine(); } - assertEquals(l, "| /set mode -retain tp", + assertEquals("| /set mode -retain tp", l, "| /set mode -retain tp"); - assertEquals(rdr.readLine(), "| ", + assertEquals("| ", rdr.readLine(), "| "); - assertEquals(rdr.readLine(), "| /set mode tp -quiet", + assertEquals("| /set mode tp -quiet", rdr.readLine(), "| /set mode tp -quiet"); - assertEquals(rdr.readLine(), "| /set prompt tp \"ccc\" \"ddd\"", + assertEquals("| /set prompt tp \"ccc\" \"ddd\"", rdr.readLine(), "| /set prompt tp \"ccc\" \"ddd\""); } catch (IOException ex) { fail("threw " + ex); @@ -370,12 +376,14 @@ public class ToolFormatTest extends ReplToolTesting { ); } + @Test public void testShowFeedbackModes() { test( (a) -> assertCommandOutputContains(a, "/set feedback", "normal") ); } + @Test public void testSetNewModeQuiet() { try { test( @@ -396,6 +404,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetError() { try { test( @@ -473,6 +482,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetHelp() { try { test( diff --git a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java index 6af4b82dbb9..a1122c0ddfa 100644 --- a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java @@ -30,12 +30,12 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream ToolSimpleTest - * @run testng/othervm/timeout=480 ToolLocalSimpleTest + * @run junit/othervm/timeout=480 ToolLocalSimpleTest */ import java.util.Locale; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class ToolLocalSimpleTest extends ToolSimpleTest { @@ -51,12 +51,12 @@ public class ToolLocalSimpleTest extends ToolSimpleTest { @Test public void verifyLocal() { System.setProperty("LOCAL_CHECK", "Here"); - assertEquals(System.getProperty("LOCAL_CHECK"), "Here"); + assertEquals("Here", System.getProperty("LOCAL_CHECK")); test(new String[]{"--no-startup"}, a -> assertCommand(a, "System.getProperty(\"LOCAL_CHECK\")", "$1 ==> \"Here\""), a -> assertCommand(a, "System.setProperty(\"LOCAL_CHECK\", \"After\")", "$2 ==> \"Here\"") ); - assertEquals(System.getProperty("LOCAL_CHECK"), "After"); + assertEquals("After", System.getProperty("LOCAL_CHECK")); } @Override diff --git a/test/langtools/jdk/jshell/ToolLocaleMessageTest.java b/test/langtools/jdk/jshell/ToolLocaleMessageTest.java index 6111320f1af..c3e4a421143 100644 --- a/test/langtools/jdk/jshell/ToolLocaleMessageTest.java +++ b/test/langtools/jdk/jshell/ToolLocaleMessageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,16 +31,15 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng ToolLocaleMessageTest + * @run junit ToolLocaleMessageTest * @key intermittent */ import java.util.Locale; -import org.testng.annotations.Test; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ToolLocaleMessageTest extends ReplToolTesting { void testLocale(ReplTest... tests) { @@ -67,12 +66,14 @@ public class ToolLocaleMessageTest extends ReplToolTesting { }); } + @Test public void testTerminate() { testLocale( (a) -> assertCommandOK(a, "System.exit(1)", "/reload") ); } + @Test public void testSample() { try { testLocale( @@ -98,6 +99,7 @@ public class ToolLocaleMessageTest extends ReplToolTesting { } } + @Test public void testCommand() { try { testLocale( @@ -132,6 +134,7 @@ public class ToolLocaleMessageTest extends ReplToolTesting { } } + @Test public void testHelp() { testLocale( (a) -> assertCommandOK(a, "/help", "/list", "/save", "/set", "[-restore]"), @@ -153,6 +156,7 @@ public class ToolLocaleMessageTest extends ReplToolTesting { ); } + @Test public void testFeedbackError() { try { testLocale( diff --git a/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java b/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java index 1850f6c3639..e3cbba3f20d 100644 --- a/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java +++ b/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +31,18 @@ * jdk.jshell/jdk.jshell:open * @build UITesting * @build ToolMultilineSnippetHistoryTest - * @run testng ToolMultilineSnippetHistoryTest + * @run junit ToolMultilineSnippetHistoryTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolMultilineSnippetHistoryTest extends UITesting { public ToolMultilineSnippetHistoryTest() { super(true); } + @Test public void testUpArrow() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("int x=\n44\n"); diff --git a/test/langtools/jdk/jshell/ToolProviderTest.java b/test/langtools/jdk/jshell/ToolProviderTest.java index 1a600efe737..8312ec49ab6 100644 --- a/test/langtools/jdk/jshell/ToolProviderTest.java +++ b/test/langtools/jdk/jshell/ToolProviderTest.java @@ -29,8 +29,8 @@ import java.util.function.Function; import javax.tools.Tool; import jdk.internal.jshell.tool.JShellToolProvider; import jdk.jshell.tool.JavaShellToolBuilder; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /* * @test @@ -43,9 +43,8 @@ import static org.testng.Assert.assertTrue; * jdk.jshell/jdk.internal.jshell.tool.resources:+open * @library /tools/lib * @build Compiler toolbox.ToolBox - * @run testng/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch ToolProviderTest + * @run junit/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch ToolProviderTest */ -@Test public class ToolProviderTest extends StartOptionTest { // Through the provider, the console and console go to command out (we assume, @@ -102,6 +101,7 @@ public class ToolProviderTest extends StartOptionTest { // Test --show-version @Override + @Test public void testShowVersion() { startCo(s -> { assertTrue(s.startsWith("jshell "), "unexpected version: " + s); diff --git a/test/langtools/jdk/jshell/ToolReloadTest.java b/test/langtools/jdk/jshell/ToolReloadTest.java index 4709584cd12..c4193f602be 100644 --- a/test/langtools/jdk/jshell/ToolReloadTest.java +++ b/test/langtools/jdk/jshell/ToolReloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +32,20 @@ * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng ToolReloadTest + * @run junit ToolReloadTest */ import java.nio.file.Path; import java.nio.file.Paths; import java.util.function.Function; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ToolReloadTest extends ReplToolTesting { + @Test public void testReloadSnippets() { test( (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -63,6 +63,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadClasspath() { Function prog = (s) -> String.format( "package pkg; public class A { public String toString() { return \"%s\"; } }\n", s); @@ -89,6 +90,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadDrop() { test(false, new String[]{"--no-startup"}, a -> assertVariable(a, "int", "a"), @@ -112,6 +114,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadQuiet() { test(false, new String[]{"--no-startup"}, a -> assertVariable(a, "int", "a"), @@ -129,6 +132,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadRepeat() { test(false, new String[]{"--no-startup"}, (a) -> assertVariable(a, "int", "c", "7", "7"), @@ -149,6 +153,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadIgnore() { test(false, new String[]{"--no-startup"}, (a) -> assertCommand(a, "(-)", null), @@ -162,6 +167,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadResetRestore() { test( (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -180,6 +186,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadCrashRestore() { test( (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -200,6 +207,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testEnvBadModule() { test(new String[] {"--execution", Presets.TEST_STANDARD_EXECUTION}, (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -221,6 +229,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadExitRestore() { test(false, new String[]{"--no-startup"}, (a) -> assertVariable(a, "int", "x", "5", "5"), diff --git a/test/langtools/jdk/jshell/ToolRetainTest.java b/test/langtools/jdk/jshell/ToolRetainTest.java index 452a3d8dac2..adf3dd0343e 100644 --- a/test/langtools/jdk/jshell/ToolRetainTest.java +++ b/test/langtools/jdk/jshell/ToolRetainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +27,15 @@ * @summary Tests of what information is retained across jshell tool runs * @modules jdk.jshell/jdk.internal.jshell.tool * @build ToolRetainTest ReplToolTesting - * @run testng ToolRetainTest + * @run junit ToolRetainTest */ import java.util.Locale; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolRetainTest extends ReplToolTesting { + @Test public void testRetainMode() { test( (a) -> assertCommand(a, "/set mode trm -quiet", "| Created new feedback mode: trm"), @@ -53,6 +53,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetain2Mode() { test( (a) -> assertCommand(a, "/set mode trm1 -quiet", "| Created new feedback mode: trm1"), @@ -81,6 +82,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainFeedback() { test( (a) -> assertCommand(a, "/set feedback -retain verbose", "| Feedback mode: verbose"), @@ -95,6 +97,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainFeedbackBlank() { String feedbackOut = "| /set feedback -retain verbose\n" + @@ -116,6 +119,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainEditor() { test( (a) -> assertCommand(a, "/set editor -retain nonexistent", @@ -130,6 +134,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainEditorBlank() { test( (a) -> assertCommand(a, "/set editor nonexistent", "| Editor set to: nonexistent"), @@ -142,6 +147,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainModeNeg() { test( (a) -> assertCommandOutputStartsWith(a, "/set mode -retain verbose", @@ -151,6 +157,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainFeedbackNeg() { test( (a) -> assertCommandOutputStartsWith(a, "/set feedback -retain babble1", @@ -167,6 +174,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testNoRetainMode() { test( (a) -> assertCommand(a, "/set mode trm -quiet", "| Created new feedback mode: trm"), @@ -182,6 +190,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testNoRetainFeedback() { test( (a) -> assertCommand(a, "/set feedback verbose", "| Feedback mode: verbose"), diff --git a/test/langtools/jdk/jshell/ToolShiftTabTest.java b/test/langtools/jdk/jshell/ToolShiftTabTest.java index 87f616678cb..84f1a65c67b 100644 --- a/test/langtools/jdk/jshell/ToolShiftTabTest.java +++ b/test/langtools/jdk/jshell/ToolShiftTabTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +31,18 @@ * jdk.jshell/jdk.jshell:open * @build UITesting * @build ToolShiftTabTest - * @run testng/timeout=300 ToolShiftTabTest + * @run junit/timeout=300 ToolShiftTabTest */ import java.util.regex.Pattern; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolShiftTabTest extends UITesting { // Shift-tab as escape sequence private String FIX = "\033\133\132"; + @Test public void testFixVariable() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("3+4"); @@ -54,6 +54,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixMethod() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("5.5 >= 3.1415926535"); @@ -68,6 +69,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixMethodVoid() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("System.out.println(\"Testing\")"); @@ -81,6 +83,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixMethodNoLeaks() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("4"); @@ -106,6 +109,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixImport() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("Frame"); @@ -126,6 +130,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixBad() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("123"); diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 4ed0e741d49..39ce248a521 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -35,7 +35,7 @@ * jdk.jshell/jdk.internal.jshell.tool * java.desktop * @build KullaTesting TestingInputStream - * @run testng/timeout=480 ToolSimpleTest + * @run junit/timeout=480 ToolSimpleTest */ import java.util.ArrayList; @@ -47,10 +47,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class ToolSimpleTest extends ReplToolTesting { @@ -543,7 +542,7 @@ public class ToolSimpleTest extends ReplToolTesting { String[] res = trimmed.isEmpty() ? new String[0] : trimmed.split("\n"); - assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res)); + assertEquals(match.size(), res.length, "Got: " + Arrays.asList(res)); for (int i = 0; i < match.size(); ++i) { assertTrue(res[i].contains(match.get(i))); } @@ -619,7 +618,7 @@ public class ToolSimpleTest extends ReplToolTesting { a -> assertCommandCheckOutput(a, "/methods print println printf", s -> checkLineToList(s, printingMethodList)), a -> assertCommandCheckOutput(a, "/methods println", - s -> assertEquals(s.trim().split("\n").length, 10)), + s -> assertEquals(10, s.trim().split("\n").length)), a -> assertCommandCheckOutput(a, "/methods", s -> checkLineToList(s, printingMethodList)), a -> assertCommandOutputStartsWith(a, "/methods " + arg, diff --git a/test/langtools/jdk/jshell/ToolTabCommandTest.java b/test/langtools/jdk/jshell/ToolTabCommandTest.java index f2f3111c4fa..3dcc81e77be 100644 --- a/test/langtools/jdk/jshell/ToolTabCommandTest.java +++ b/test/langtools/jdk/jshell/ToolTabCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +34,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build ToolTabCommandTest - * @run testng ToolTabCommandTest + * @run junit ToolTabCommandTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolTabCommandTest extends UITesting { public ToolTabCommandTest() { super(true); } + @Test public void testCommand() throws Exception { // set terminal height so that help output won't hit page breaks System.setProperty("test.terminal.height", "1000000"); @@ -133,6 +133,7 @@ public class ToolTabCommandTest extends UITesting { }); } + @Test public void testRerunCommands() throws Exception { // set terminal height so that help output won't hit page breaks System.setProperty("test.terminal.height", "1000000"); @@ -170,6 +171,7 @@ public class ToolTabCommandTest extends UITesting { }); } + @Test public void testHelp() throws Exception { // set terminal height so that help output won't hit page breaks System.setProperty("test.terminal.height", "1000000"); diff --git a/test/langtools/jdk/jshell/ToolTabSnippetTest.java b/test/langtools/jdk/jshell/ToolTabSnippetTest.java index 252d57f4a6f..39189da8686 100644 --- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java +++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build ToolTabSnippetTest - * @run testng/timeout=300 ToolTabSnippetTest + * @run junit/timeout=300 ToolTabSnippetTest */ import java.io.IOException; @@ -48,15 +48,15 @@ import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import jdk.internal.jshell.tool.ConsoleIOContextTestSupport; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolTabSnippetTest extends UITesting { public ToolTabSnippetTest() { super(true); } + @Test public void testExpression() throws Exception { Path classes = prepareZip(); doRunTest((inputSink, out) -> { @@ -208,6 +208,7 @@ public class ToolTabSnippetTest extends UITesting { }); } + @Test public void testCleaningCompletionTODO() throws Exception { doRunTest((inputSink, out) -> { CountDownLatch testCompleteComputationStarted = new CountDownLatch(1); @@ -241,6 +242,7 @@ public class ToolTabSnippetTest extends UITesting { }); } + @Test public void testNoRepeat() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("String xyzAA;\n"); @@ -266,6 +268,7 @@ public class ToolTabSnippetTest extends UITesting { }); } + @Test public void testCrash8221759() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("java.io.File.path" + TAB); @@ -331,6 +334,7 @@ public class ToolTabSnippetTest extends UITesting { //where: private final Compiler compiler = new Compiler(); + @Test public void testDocumentationAfterInsert() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("import java.time.*\n"); diff --git a/test/langtools/jdk/jshell/ToolingTest.java b/test/langtools/jdk/jshell/ToolingTest.java index f0d0e3f68eb..6f1c899c884 100644 --- a/test/langtools/jdk/jshell/ToolingTest.java +++ b/test/langtools/jdk/jshell/ToolingTest.java @@ -30,11 +30,10 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng ToolingTest + * @run junit ToolingTest */ -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ToolingTest extends ReplToolTesting { @Test diff --git a/test/langtools/jdk/jshell/TypeNameTest.java b/test/langtools/jdk/jshell/TypeNameTest.java index dc2b2152ca8..cbcde20a541 100644 --- a/test/langtools/jdk/jshell/TypeNameTest.java +++ b/test/langtools/jdk/jshell/TypeNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +26,12 @@ * @bug 8144903 8171981 8191802 8191842 * @summary Tests for determining the type from the expression * @build KullaTesting TestingInputStream - * @run testng TypeNameTest + * @run junit TypeNameTest */ -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class TypeNameTest extends KullaTesting { @@ -42,10 +40,11 @@ public class TypeNameTest extends KullaTesting { } private void assertType(String expr, String type, String inferType) { - assertEquals(varKey(assertEval(expr)).typeName(), type); + assertEquals(type, varKey(assertEval(expr)).typeName()); assertInferredType(expr, inferType); } + @Test public void testTypeInference() { assertEval("import java.util.List;"); assertEval("import java.util.ArrayList;"); @@ -75,6 +74,7 @@ public class TypeNameTest extends KullaTesting { assertType("(P) null", "P"); } + @Test public void testConditionals() { assertEval("import java.util.List;"); assertEval("import java.util.ArrayList;"); @@ -95,6 +95,7 @@ public class TypeNameTest extends KullaTesting { assertType("b? new B() : new C()", "X"); } + @Test public void testJEP286NonDenotable() { assertEval("import java.util.List;"); assertEval("import java.util.Arrays;"); @@ -144,6 +145,7 @@ public class TypeNameTest extends KullaTesting { assertType("unbStringIter().iterator().next().get(0)", "Object"); } + @Test public void testJEP286NonDenotable2() { assertEval("import java.util.List;"); assertEval("import java.util.Arrays;"); @@ -197,6 +199,7 @@ public class TypeNameTest extends KullaTesting { "Number"); } + @Test public void testVariableTypeName() { assertType("\"x\"", "String"); @@ -213,30 +216,36 @@ public class TypeNameTest extends KullaTesting { assertType("java.util.Locale.Category.FORMAT", "Category"); } + @Test public void testReplNestedClassName() { assertEval("class D { static class E {} }"); assertType("new D.E();", "D.E"); } + @Test public void testAnonymousClassName() { assertEval("class C {}"); assertType("new C();", "C"); assertType("new C() { int x; };", "", "C"); } + @Test public void testCapturedTypeName() { assertType("\"\".getClass();", "Class"); assertType("\"\".getClass().getEnumConstants();", "String[]"); } + @Test public void testJavaLang() { assertType("\"\";", "String"); } + @Test public void testNotOverEagerPackageEating() { assertType("\"\".getClass().getDeclaredMethod(\"hashCode\");", "java.lang.reflect.Method"); } + @Test public void testBounds() { assertEval("java.util.List list1 = java.util.Arrays.asList(\"\");"); assertType("list1.iterator().next()", "String"); diff --git a/test/langtools/jdk/jshell/UITesting.java b/test/langtools/jdk/jshell/UITesting.java index e7daa4df8e6..a1bd8f35dee 100644 --- a/test/langtools/jdk/jshell/UITesting.java +++ b/test/langtools/jdk/jshell/UITesting.java @@ -63,11 +63,11 @@ public class UITesting { this.laxLineEndings = laxLineEndings; } - protected void doRunTest(Test test) throws Exception { + protected void doRunTest(UITest test) throws Exception { doRunTest(test, true); } - protected void doRunTest(Test test, boolean setUserInput) throws Exception { + protected void doRunTest(UITest test, boolean setUserInput) throws Exception { // turn on logging of launch failures Logger.getLogger("jdk.jshell.execution").setLevel(Level.ALL); @@ -141,7 +141,7 @@ public class UITesting { } } - protected interface Test { + protected interface UITest { public void test(Writer inputSink, StringBuilder out) throws Exception; } diff --git a/test/langtools/jdk/jshell/UndefinedClassTest.java b/test/langtools/jdk/jshell/UndefinedClassTest.java index eb0cf3699cf..3891aa7b4cd 100644 --- a/test/langtools/jdk/jshell/UndefinedClassTest.java +++ b/test/langtools/jdk/jshell/UndefinedClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build UndefinedClassTest - * @run testng UndefinedClassTest + * @run junit UndefinedClassTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class UndefinedClassTest extends UITesting { public UndefinedClassTest() { super(true); } + @Test public void testUndefinedClassWithStaticAccess() throws Exception{ String code = "@FunctionalInterface\n" + "interface RunnableWithThrowable {\n" + @@ -62,6 +62,7 @@ public class UndefinedClassTest extends UITesting { }); } + @Test public void testUndefinedClassWithDefaultAccess() throws Exception{ String code = "@FunctionalInterface\n" + "interface RunnableWithThrowable {\n" + diff --git a/test/langtools/jdk/jshell/UnicodeTest.java b/test/langtools/jdk/jshell/UnicodeTest.java index 6812dcf1a50..13dd30f0975 100644 --- a/test/langtools/jdk/jshell/UnicodeTest.java +++ b/test/langtools/jdk/jshell/UnicodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * 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,27 +26,28 @@ * @bug 8248157 * @summary test Unicode characters in Snippets * @build KullaTesting TestingInputStream - * @run testng UnicodeTest + * @run junit UnicodeTest */ import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import jdk.jshell.Snippet.Status; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Test; -@Test public class UnicodeTest extends KullaTesting { + @Test public void testVarDeclarationKey() { assertVarKeyMatch("int \\u00aa;", true, "\u00aa", VAR_DECLARATION_SUBKIND, "int", added(VALID)); assertEval("\\u00aa", "0"); } + @Test public void testVarDeclarationWithInitializerKey() { assertVarKeyMatch("double \\u00ba\\u0044\\u0577 = 9.4;", true, "\u00ba\u0044\u0577", VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "double", added(VALID)); diff --git a/test/langtools/jdk/jshell/UnnamedTest.java b/test/langtools/jdk/jshell/UnnamedTest.java index 9c7bb6ba5a2..65d2b83c856 100644 --- a/test/langtools/jdk/jshell/UnnamedTest.java +++ b/test/langtools/jdk/jshell/UnnamedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,20 +30,20 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jshell * @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng UnnamedTest + * @run junit UnnamedTest */ import java.util.function.Consumer; import jdk.jshell.SourceCodeAnalysis; import jdk.jshell.VarSnippet; -import org.testng.Assert; -import org.testng.annotations.Test; import jdk.jshell.JShell; import static jdk.jshell.SourceCodeAnalysis.Completeness.COMPLETE; import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class UnnamedTest extends KullaTesting { @@ -51,8 +51,8 @@ public class UnnamedTest extends KullaTesting { public void unnamed() { VarSnippet sn1 = varKey(assertEval("int _ = 0;")); VarSnippet sn2 = varKey(assertEval("String _ = \"x\";")); - Assert.assertEquals(getState().varValue(sn1), "0"); - Assert.assertEquals(getState().varValue(sn2), "\"x\""); + Assertions.assertEquals("0", getState().varValue(sn1)); + Assertions.assertEquals("\"x\"", getState().varValue(sn2)); } static final String[] definitely_incomplete = new String[]{ diff --git a/test/langtools/jdk/jshell/UserExecutionControlTest.java b/test/langtools/jdk/jshell/UserExecutionControlTest.java index 90c99db4a8f..41719f9ff2a 100644 --- a/test/langtools/jdk/jshell/UserExecutionControlTest.java +++ b/test/langtools/jdk/jshell/UserExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,29 +26,29 @@ * @bug 8156101 8159935 8159122 8168615 * @summary Tests for ExecutionControl SPI * @build KullaTesting ExecutionControlTestBase - * @run testng UserExecutionControlTest + * @run junit UserExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class UserExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("local")); } + @Test public void verifyLocal() throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { System.setProperty("LOCAL_CHECK", "TBD"); - assertEquals(System.getProperty("LOCAL_CHECK"), "TBD"); + assertEquals("TBD", System.getProperty("LOCAL_CHECK")); assertEval("System.getProperty(\"LOCAL_CHECK\")", "\"TBD\""); assertEval("System.setProperty(\"LOCAL_CHECK\", \"local\")"); - assertEquals(System.getProperty("LOCAL_CHECK"), "local"); + assertEquals("local", System.getProperty("LOCAL_CHECK")); } } diff --git a/test/langtools/jdk/jshell/UserInputTest.java b/test/langtools/jdk/jshell/UserInputTest.java index 392278abef1..c0246acdf63 100644 --- a/test/langtools/jdk/jshell/UserInputTest.java +++ b/test/langtools/jdk/jshell/UserInputTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,18 +26,18 @@ * @bug 8131023 8167461 * @summary Verify that the user's code can read System.in * @build KullaTesting TestingInputStream - * @run testng UserInputTest + * @run junit UserInputTest * @key intermittent */ import java.io.IOException; import java.io.InputStream; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class UserInputTest extends KullaTesting { + @Test public void testReadInput() { setInput("AB\n"); assertEval("System.in.read()", "65"); @@ -45,6 +45,7 @@ public class UserInputTest extends KullaTesting { assertEval("System.in.read()", "67"); } + @Test public void testScanner() { assertEval("import java.util.Scanner;"); assertEval("Scanner s = new Scanner(System.in);"); @@ -52,6 +53,7 @@ public class UserInputTest extends KullaTesting { assertEval("s.nextInt();", "12"); } + @Test public void testClose() { setInput(new InputStream() { private final byte[] data = new byte[] {0, 1, 2}; @@ -73,6 +75,7 @@ public class UserInputTest extends KullaTesting { assertEval("System.in.read();", "-1"); } + @Test public void testException() { setInput(new InputStream() { private final int[] data = new int[] {0, 1, -2, 2}; @@ -99,6 +102,7 @@ public class UserInputTest extends KullaTesting { assertEval("System.in.read();", "-1"); } + @Test public void testNoConsole() { assertEval("System.console()", "null"); } diff --git a/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java b/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java index 02c725cffa4..094c705bce6 100644 --- a/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java +++ b/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,46 +26,48 @@ * @bug 8160128 8159935 8168615 * @summary Tests for Aux channel, custom remote agents, custom JDI implementations. * @build KullaTesting ExecutionControlTestBase MyExecutionControl MyRemoteExecutionControl MyExecutionControlProvider - * @run testng UserJdiUserRemoteTest + * @run junit UserJdiUserRemoteTest * @key intermittent */ import java.io.ByteArrayOutputStream; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import jdk.jshell.Snippet; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.VALID; import jdk.jshell.VarSnippet; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl.ExecutionControlException; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class UserJdiUserRemoteTest extends ExecutionControlTestBase { ExecutionControl currentEC; ByteArrayOutputStream auxStream; - @BeforeMethod + @BeforeEach @Override public void setUp() { auxStream = new ByteArrayOutputStream(); setUp(builder -> builder.executionEngine(new MyExecutionControlProvider(this), null)); } + @Test public void testVarValue() { VarSnippet dv = varKey(assertEval("double aDouble = 1.5;")); String vd = getState().varValue(dv); - assertEquals(vd, "1.5"); - assertEquals(auxStream.toString(), "aDouble"); + assertEquals("1.5", vd); + assertEquals("aDouble", auxStream.toString()); } + @Test public void testExtension() throws ExecutionControlException { assertEval("42;"); Object res = currentEC.extensionCommand("FROG", "test"); - assertEquals(res, "ribbit"); + assertEquals("ribbit", res); } + @Test public void testRedefine() { Snippet vx = varKey(assertEval("int x;")); Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 64d25e8a63c..94dcbbf7c8d 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jshell * @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng/timeout=480 VariablesTest + * @run junit/timeout=480 VariablesTest */ import java.nio.file.Path; @@ -44,18 +44,19 @@ import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import jdk.jshell.Snippet.SubKind; import jdk.jshell.SnippetEvent; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import static java.util.stream.Collectors.toList; import static jdk.jshell.Snippet.Status.*; import static jdk.jshell.Snippet.SubKind.VAR_DECLARATION_SUBKIND; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class VariablesTest extends KullaTesting { + @Test public void noVariables() { assertNumberOfActiveVariables(0); } @@ -69,6 +70,7 @@ public class VariablesTest extends KullaTesting { } } + @Test public void testVarValue1() { VarSnippet v1 = varKey(assertEval("und1 a;", added(RECOVERABLE_NOT_DEFINED))); badVarValue(v1); @@ -89,6 +91,7 @@ public class VariablesTest extends KullaTesting { badVarValue(v2); } + @Test public void testVarValue2() { VarSnippet v1 = (VarSnippet) assertDeclareFail("int a = 0.0;", "compiler.err.prob.found.req"); badVarValue(v1); @@ -97,6 +100,7 @@ public class VariablesTest extends KullaTesting { badVarValue(v2); } + @Test public void testSignature1() { VarSnippet v1 = varKey(assertEval("und1 a;", added(RECOVERABLE_NOT_DEFINED))); assertVariableDeclSnippet(v1, "a", "und1", RECOVERABLE_NOT_DEFINED, VAR_DECLARATION_SUBKIND, 1, 0); @@ -116,6 +120,7 @@ public class VariablesTest extends KullaTesting { assertVariableDeclSnippet(v2, "a", "und2", RECOVERABLE_NOT_DEFINED, VAR_DECLARATION_SUBKIND, 1, 0); } + @Test public void testSignature2() { VarSnippet v1 = (VarSnippet) assertDeclareFail("int a = 0.0;", "compiler.err.prob.found.req"); assertVariableDeclSnippet(v1, "a", "int", REJECTED, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 1); @@ -126,6 +131,7 @@ public class VariablesTest extends KullaTesting { assertVariableDeclSnippet(v2, "a", "int", DROPPED, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 0); } + @Test public void variables() { VarSnippet snx = varKey(assertEval("int x = 10;")); VarSnippet sny = varKey(assertEval("String y = \"hi\";")); @@ -137,22 +143,25 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesArray() { VarSnippet sn = varKey(assertEval("int[] a = new int[12];")); - assertEquals(sn.typeName(), "int[]"); + assertEquals("int[]", sn.typeName()); assertEval("int len = a.length;", "12"); assertVariables(variable("int[]", "a"), variable("int", "len")); assertActiveKeys(); } + @Test public void variablesArrayOld() { VarSnippet sn = varKey(assertEval("int a[] = new int[12];")); - assertEquals(sn.typeName(), "int[]"); + assertEquals("int[]", sn.typeName()); assertEval("int len = a.length;", "12"); assertVariables(variable("int[]", "a"), variable("int", "len")); assertActiveKeys(); } + @Test public void variablesRedefinition() { Snippet x = varKey(assertEval("int x = 10;")); Snippet y = varKey(assertEval("String y = \"\";", added(VALID))); @@ -170,6 +179,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesTemporary() { assertEval("int $1 = 10;", added(VALID)); assertEval("2 * $1;", added(VALID)); @@ -180,6 +190,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesTemporaryNull() { assertEval("null;", added(VALID)); assertVariables(variable("Object", "$1")); @@ -194,6 +205,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesTemporaryArrayOfCapturedType() { assertEval("class Test { T[][] get() { return null; } }", added(VALID)); assertEval("Test test() { return new Test<>(); }", added(VALID)); @@ -204,6 +216,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesClassReplace() { assertEval("import java.util.*;", added(VALID)); Snippet var = varKey(assertEval("List list = new ArrayList<>();", "[]", @@ -223,12 +236,14 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesErrors() { assertDeclareFail("String;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 6, 0, -1, -1, Diagnostic.Kind.ERROR)); assertNumberOfActiveVariables(0); assertActiveKeys(); } + @Test public void variablesUnresolvedActiveFailed() { VarSnippet key = varKey(assertEval("und x;", added(RECOVERABLE_NOT_DEFINED))); assertVariableDeclSnippet(key, "x", "und", RECOVERABLE_NOT_DEFINED, VAR_DECLARATION_SUBKIND, 1, 0); @@ -237,12 +252,14 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesUnresolvedError() { assertDeclareFail("und y = null;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 3, 0, -1, -1, Diagnostic.Kind.ERROR)); assertNumberOfActiveVariables(0); assertActiveKeys(); } + @Test public void variablesMultiByteCharacterType() { assertEval("class \u3042 {}"); assertEval("\u3042 \u3042 = null;", added(VALID)); @@ -261,7 +278,8 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void methodVariablesAreNotVisible() { Snippet foo = varKey(assertEval("int foo() {" + "int x = 10;" + @@ -283,7 +301,8 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void classFieldsAreNotVisible() { Snippet key = classKey(assertEval("class clazz {" + "int x = 10;" + @@ -303,6 +322,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void multiVariables() { List abc = assertEval("int a, b, c = 10;", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, @@ -324,12 +344,14 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void syntheticVariables() { assertEval("assert false;"); assertNumberOfActiveVariables(0); assertActiveKeys(); } + @Test public void undefinedReplaceVariable() { Snippet key = varKey(assertEval("int d = 234;", "234")); assertVariables(variable("int", "d")); @@ -339,13 +361,14 @@ public class VariablesTest extends KullaTesting { ste(key, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); //assertEquals(getState().source(snippet), src); //assertEquals(snippet, undefKey); - assertEquals(getState().status(undefKey), RECOVERABLE_NOT_DEFINED); + assertEquals(RECOVERABLE_NOT_DEFINED, getState().status(undefKey)); List unr = getState().unresolvedDependencies((VarSnippet) undefKey).collect(toList()); - assertEquals(unr.size(), 1); - assertEquals(unr.get(0), "class undefined"); + assertEquals(1, unr.size()); + assertEquals("class undefined", unr.get(0)); assertVariables(variable("undefined", "d")); } + @Test public void lvti() { assertEval("var d = 234;", "234"); assertEval("class Test { T[][] get() { return null; } }", added(VALID)); @@ -410,12 +433,14 @@ public class VariablesTest extends KullaTesting { assertEval("var r16d = r16d();"); } + @Test public void test8191842() { assertEval("import java.util.stream.*;"); assertEval("var list = Stream.of(1, 2, 3).map(j -> new Object() { int i = j; }).collect(Collectors.toList());"); assertEval("list.stream().map(a -> String.valueOf(a.i)).collect(Collectors.joining(\", \"));", "\"1, 2, 3\""); } + @Test public void lvtiRecompileDependentsWithIntersectionTypes() { assertEval(" Z get1() { return null; }", added(VALID)); assertEval("var i1 = get1();", added(VALID)); @@ -428,27 +453,32 @@ public class VariablesTest extends KullaTesting { assertEval("void t2() { i2.run(); i2.count(); }", added(VALID)); } + @Test public void arrayInit() { assertEval("int[] d = {1, 2, 3};"); } + @Test public void testAnonymousVar() { assertEval("new Object() { public String get() { return \"a\"; } }"); assertEval("$1.get()", "\"a\""); } + @Test public void testIntersectionVar() { assertEval(" Z get() { return null; }", added(VALID)); assertEval("get();", added(VALID)); assertEval("void t1() { $1.run(); $1.length(); }", added(VALID)); } + @Test public void multipleCaptures() { assertEval("class D { D(int foo, String bar) { this.foo = foo; this.bar = bar; } int foo; String bar; } "); assertEval("var d = new D(34, \"hi\") { String z = foo + bar; };"); assertEval("d.z", "\"34hi\""); } + @Test public void multipleAnonymous() { VarSnippet v1 = varKey(assertEval("new Object() { public int i = 42; public int i1 = i; public int m1() { return i1; } };")); VarSnippet v2 = varKey(assertEval("new Object() { public int i = 42; public int i2 = i; public int m2() { return i2; } };")); @@ -466,6 +496,7 @@ public class VariablesTest extends KullaTesting { -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void displayName() { assertVarDisplayName("var v1 = 234;", "int"); assertVarDisplayName("var v2 = new int[] {234};", "int[]"); @@ -478,6 +509,7 @@ public class VariablesTest extends KullaTesting { assertVarDisplayName("var v6 = new Runnable() { public void run() { } };", ""); } + @Test public void varType() { assertEval("import java.util.*;"); var firstVar = varKey(assertEval("var v1 = List.of(1);", added(VALID))); @@ -487,6 +519,7 @@ public class VariablesTest extends KullaTesting { assertEval("v2", "[1]"); } + @Test public void varDeclNoInit() { assertVarDeclNoInit("byte", "b", "0"); assertVarDeclNoInit("short", "h", "0"); @@ -500,6 +533,7 @@ public class VariablesTest extends KullaTesting { assertVarDeclNoInit("String", "s", "null"); } + @Test public void varDeclRedefNoInit() { assertVarDeclRedefNoInit("byte", "b", "1", "0"); assertVarDeclRedefNoInit("short", "h", "2", "0"); @@ -513,6 +547,7 @@ public class VariablesTest extends KullaTesting { assertVarDeclRedefNoInit("String", "s", "\"hi\"", "null"); } + @Test public void badPkgVarDecl() { Compiler compiler = new Compiler(); Path nopkgdirpath = Paths.get("cp", "xyz"); @@ -545,16 +580,16 @@ public class VariablesTest extends KullaTesting { private VarSnippet assertVarDeclNoInit(String typeName, String name, String dvalue, STEInfo mainInfo, STEInfo... updates) { VarSnippet vs = varKey(assertEval(typeName + " " + name + ";", dvalue, mainInfo, updates)); - assertEquals(vs.typeName(), typeName); + assertEquals(typeName, vs.typeName()); assertEval(name, dvalue, added(VALID)); return vs; } private void assertVarDisplayName(String var, String typeName) { - assertEquals(varKey(assertEval(var)).typeName(), typeName); + assertEquals(typeName, varKey(assertEval(var)).typeName()); } - @BeforeMethod + @BeforeEach @Override public void setUp() { Path path = Paths.get("cp"); @@ -611,22 +646,26 @@ public class VariablesTest extends KullaTesting { .compilerOptions("--class-path", tpath)); } + @Test public void varIntersection() { assertEval("interface Marker {}"); assertEval("var v = (Marker & Runnable) () -> {};", added(VALID)); assertEval("v.run()"); } + @Test public void varAnonymousClassAndStaticField() { //JDK-8294431 assertEval("var obj = new Object() { public static final String msg = \"hello\"; };"); } + @Test public void underscoreAsLambdaParameter() { //JDK-8322532 assertAnalyze("Func f = _ -> 0; int i;", "Func f = _ -> 0;", " int i;", true); } + @Test public void intersectionTypeAsTypeArgument() { //JDK-8322003 assertEval("interface Shape {}"); assertEval("record Square(int edge) implements Shape {}"); diff --git a/test/langtools/jdk/jshell/WrapperTest.java b/test/langtools/jdk/jshell/WrapperTest.java index 8986c99b4b3..9903f04676f 100644 --- a/test/langtools/jdk/jshell/WrapperTest.java +++ b/test/langtools/jdk/jshell/WrapperTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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,28 +27,28 @@ * @summary test wrappers and dependencies * @modules jdk.jshell/jdk.jshell * @build KullaTesting - * @run testng WrapperTest + * @run junit WrapperTest */ import java.util.Collection; import java.util.List; -import org.testng.annotations.Test; import jdk.jshell.ErroneousSnippet; import jdk.jshell.Snippet; import jdk.jshell.Snippet.Kind; import jdk.jshell.SourceCodeAnalysis.SnippetWrapper; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.Test; -@Test public class WrapperTest extends KullaTesting { + @Test public void testMethod() { String src = "void glib() { System.out.println(\"hello\"); }"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.METHOD, "void", "glib", "println"); assertPosition(swl.get(0), src, 0, 4); assertPosition(swl.get(0), src, 5, 4); @@ -63,6 +63,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testMethodCorralled() { String src = "void glib() { f(); }"; // _123456789_123456789 @@ -75,6 +76,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testClassCorralled0() { String src = "class AAA { float mmm(double d1234) { return (float) (f0 * d1234); } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -91,6 +93,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testClassCorralled() { String src = "class AAA { int xxx = x0 + 4; float mmm(float ffff) { return f0 * ffff; } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -109,6 +112,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testClassWithConstructorCorralled() { String src = "public class AAA { AAA(String b) {} int xxx = x0 + 4; float mmm(float ffff) { return f0 * ffff; } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -130,6 +134,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testInterfaceCorralled() { String src = "interface AAA { default float mmm(double d1234) { return (float) (f0 * d1234); } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -147,6 +152,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testEnumCorralled() { String src = "public enum Planet {\n" + @@ -182,25 +188,27 @@ public class WrapperTest extends KullaTesting { "radius", "surfaceGravity", "surfaceWeight"); } + @Test public void testMethodBad() { String src = "void flob() { ?????; }"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.METHOD, "void", "flob", "?????"); assertPosition(swl.get(0), src, 9, 2); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.METHOD); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.METHOD, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.METHOD, "void", "flob", "?????"); assertPosition(swl.get(0), src, 14, 5); } + @Test public void testVar() { String src = "int gx = 1234;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.VAR, "int", "gx", "1234"); assertPosition(swl.get(0), src, 4, 2); @@ -210,25 +218,27 @@ public class WrapperTest extends KullaTesting { assertPosition(swg, src, 0, 3); } + @Test public void testVarBad() { String src = "double dd = ?????;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.VAR, "double", "dd", "?????"); assertPosition(swl.get(0), src, 9, 2); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.VAR); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.VAR, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.VAR, "double", "dd", "?????"); assertPosition(swl.get(0), src, 12, 5); } + @Test public void testImport() { String src = "import java.lang.*;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.IMPORT, "import", "java.lang"); assertPosition(swl.get(0), src, 7, 4); @@ -238,61 +248,65 @@ public class WrapperTest extends KullaTesting { assertPosition(swg, src, 0, 6); } + @Test public void testImportBad() { String src = "import java.?????;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.IMPORT, "import", "?????"); assertPosition(swl.get(0), src, 7, 4); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.IMPORT); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.IMPORT, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.IMPORT, "import", "?????"); assertPosition(swl.get(0), src, 0, 6); } + @Test public void testErroneous() { String src = "@@@@@@@@@@"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.ERRONEOUS, "@@@@@@@@@@"); assertPosition(swl.get(0), src, 0, 10); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.ERRONEOUS); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.ERRONEOUS, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.ERRONEOUS, "@@@@@@@@@@"); assertPosition(swl.get(0), src, 0, 10); } + @Test public void testEmpty() { String src = ""; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 0, "expected empty list"); + assertEquals(0, swl.size(), "expected empty list"); } + @Test public void testDependencies() { Snippet a = key(assertEval("int aaa = 6;", added(VALID))); Snippet b = key(assertEval("class B { B(int x) { aaa = x; } }", added(VALID))); Snippet c = key(assertEval("B ccc() { return new B(aaa); }", added(VALID))); Collection dep; dep = getState().sourceCodeAnalysis().dependents(c); - assertEquals(dep.size(), 0); + assertEquals(0, dep.size()); dep = getState().sourceCodeAnalysis().dependents(b); - assertEquals(dep.size(), 1); + assertEquals(1, dep.size()); assertTrue(dep.contains(c)); dep = getState().sourceCodeAnalysis().dependents(a); - assertEquals(dep.size(), 2); + assertEquals(2, dep.size()); assertTrue(dep.contains(c)); assertTrue(dep.contains(b)); } private void assertWrapperHas(SnippetWrapper sw, String source, Kind kind, String... has) { - assertEquals(sw.source(), source); - assertEquals(sw.kind(), kind); + assertEquals(source, sw.source()); + assertEquals(kind, sw.kind()); String s = sw.wrapped(); if (kind == Kind.IMPORT) { assertHas(s, "import"); @@ -322,8 +336,8 @@ public class WrapperTest extends KullaTesting { //System.err.printf("# wrapped @ wrappedPos: %s\n", wrappedPart); //System.err.printf("# source @ start: %s\n", sourcePart); - assertEquals(wrappedPart, sourcePart, + assertEquals(sourcePart, wrappedPart, "position " + wpg + " in " + sw.wrapped()); - assertEquals(sw.wrappedToSourcePosition(wpg), start); + assertEquals(start, sw.wrappedToSourcePosition(wpg)); } } From f9dc640ef07ea5569b3581360041db2bb7e30c40 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 06:33:30 +0000 Subject: [PATCH 167/295] 8351260: java.lang.AssertionError: Unexpected type tree: (ERROR) = (ERROR) Reviewed-by: vromero --- .../sun/tools/javac/parser/JavacParser.java | 9 +++ .../tools/javac/parser/JavacParserTest.java | 65 ++++++++++++++++++- .../tools/javac/recovery/AttrRecovery.java | 20 +++++- 3 files changed, 92 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 fb8d3aaeecd..dacf2daf4db 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 @@ -1104,6 +1104,11 @@ public class JavacParser implements Parser { syntaxError(result.pos, Errors.RestrictedTypeNotAllowedHere(restrictedTypeName)); } + if ((lastmode & TYPE) == 0) { + //if the mode was switched to expression while expecting type, wrap with Erroneous: + result = F.Erroneous(List.of(result)); + } + return result; } @@ -1431,6 +1436,7 @@ public class JavacParser implements Parser { protected JCExpression term3() { int pos = token.pos; JCExpression t; + int startMode = mode; List typeArgs = typeArgumentsOpt(EXPR); switch (token.kind) { case QUES: @@ -1760,6 +1766,9 @@ public class JavacParser implements Parser { } // Not reachable. default: + if (typeArgs != null && (startMode & TYPE) != 0) { + return F.at(pos).TypeApply(F.Erroneous(), typeArgs); + } return illegal(); } return term3Rest(t, typeArgs); diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 9c6ad617132..7d34a14f1d7 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 8344706 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 8344706 8351260 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -3013,6 +3013,69 @@ public class JavacParserTest extends TestCase { }"""); } + @Test //JDK-8351260 + void testVeryBrokenTypeWithAnnotations() throws IOException { + String code = """ + package tests; + class ListUtilsTest { + void test(List<@AlphaChars <@StringLength(int value = 5)String> s){ + } + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testVeryBrokenTypeWithAnnotations: " + codes, + List.of("3:32:compiler.err.illegal.start.of.type", + "3:51:compiler.err.dot.class.expected", + "3:57:compiler.err.expected2", + "3:60:compiler.err.expected2", + "3:61:compiler.err.expected2", + "3:67:compiler.err.not.stmt", + "3:70:compiler.err.expected", + "5:2:compiler.err.premature.eof"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + class ListUtilsTest { + \n\ + void test(List<@AlphaChars (ERROR: (ERROR)<@StringLength(int) value, (ERROR)> = 5), (ERROR: )> ) { + (ERROR: String > s); + { + } + } + }"""); + } + + @Test //JDK-8351260 + void testVeryBrokenTypeWithAnnotationsMinimal() throws IOException { + String code = """ + B<@C<@D(e f= + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + //no exceptions: + ct.parse().iterator().next(); + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index c5d393a23b3..a5370884f62 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -322,4 +322,22 @@ public class AttrRecovery extends TestRunner { } } + @Test //JDK-8351260 + public void testVeryBrokenAnnotation() throws Exception { + String code = """ + class ListUtilsTest { + void test(List<@AlphaChars <@StringLength(int value = 5)String> s){ + } + } + """; + Path curPath = Path.of("."); + //should not fail with an exception: + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .writeAll(); + } } From fb1924d2e34f77dc834094485dccb1751bc5b3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 8 Sep 2025 06:33:49 +0000 Subject: [PATCH 168/295] 8366874: Test gc/arguments/TestParallelGCErgo.java fails with UseTransparentHugePages Reviewed-by: ayang, shade, stefank, tschatzl --- test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java index 63c51c25149..b9e5629d875 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java @@ -27,7 +27,7 @@ package gc.arguments; * @test TestParallelGCErgo * @bug 8272364 * @requires vm.gc.Parallel - * @requires vm.opt.UseLargePages == null | !vm.opt.UseLargePages + * @requires !vm.opt.final.UseLargePages * @summary Verify ParallelGC minimum young and old ergonomics are setup correctly * @modules java.base/jdk.internal.misc * @library /test/lib From 051f39e12ce8845d13c7d4813dabc556a834892d Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 8 Sep 2025 07:10:12 +0000 Subject: [PATCH 169/295] 8366864: Sort os/linux includes Reviewed-by: ayang, dholmes --- .../os/linux/cgroupSubsystem_linux.cpp | 11 ++-- .../os/linux/cgroupSubsystem_linux.hpp | 6 +-- src/hotspot/os/linux/cgroupUtil_linux.cpp | 2 +- src/hotspot/os/linux/cgroupUtil_linux.hpp | 2 +- .../os/linux/cgroupV1Subsystem_linux.cpp | 11 ++-- .../os/linux/cgroupV1Subsystem_linux.hpp | 4 +- .../os/linux/cgroupV2Subsystem_linux.cpp | 2 +- src/hotspot/os/linux/osContainer_linux.cpp | 13 ++--- src/hotspot/os/linux/osContainer_linux.hpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 51 +++++++++---------- src/hotspot/os/linux/os_linux.inline.hpp | 2 +- src/hotspot/os/linux/os_perf_linux.cpp | 22 ++++---- src/hotspot/os/linux/waitBarrier_linux.cpp | 3 +- .../jtreg/sources/TestIncludesAreSorted.java | 1 + 14 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 3186d97ec61..f935e2cbb9c 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -22,14 +22,10 @@ * */ -#include -#include -#include -#include #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_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" @@ -37,6 +33,11 @@ #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +#include +#include +#include +#include + // Inlined from for portability. #ifndef CGROUP2_SUPER_MAGIC # define CGROUP2_SUPER_MAGIC 0x63677270 diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index f72d1a7fb1e..22e57d56c93 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -25,12 +25,12 @@ #ifndef CGROUP_SUBSYSTEM_LINUX_HPP #define CGROUP_SUBSYSTEM_LINUX_HPP -#include "memory/allocation.hpp" -#include "runtime/os.hpp" #include "logging/log.hpp" +#include "memory/allocation.hpp" +#include "osContainer_linux.hpp" +#include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -#include "osContainer_linux.hpp" // Shared cgroups code (used by cgroup version 1 and version 2) diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 72dda36504d..de027db812a 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -22,8 +22,8 @@ * */ -#include "os_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "os_linux.hpp" int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { assert(host_cpus > 0, "physical host cpus must be positive"); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index 19220af3177..aa63a7457cc 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -25,8 +25,8 @@ #ifndef CGROUP_UTIL_LINUX_HPP #define CGROUP_UTIL_LINUX_HPP -#include "utilities/globalDefinitions.hpp" #include "cgroupSubsystem_linux.hpp" +#include "utilities/globalDefinitions.hpp" class CgroupUtil: AllStatic { diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index f65da207062..64cb53eda28 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -22,17 +22,18 @@ * */ -#include -#include -#include -#include "cgroupV1Subsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "cgroupV1Subsystem_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" +#include "os_linux.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" -#include "os_linux.hpp" + +#include +#include +#include /* * Set directory to subsystem specific files based diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index a56ad455165..33bf2ed6e55 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -25,10 +25,10 @@ #ifndef CGROUP_V1_SUBSYSTEM_LINUX_HPP #define CGROUP_V1_SUBSYSTEM_LINUX_HPP -#include "runtime/os.hpp" -#include "memory/allocation.hpp" #include "cgroupSubsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "memory/allocation.hpp" +#include "runtime/os.hpp" // Cgroups version 1 specific implementation diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 6472fdfccc5..661f7e909b5 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -23,8 +23,8 @@ * */ -#include "cgroupV2Subsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "cgroupV2Subsystem_linux.hpp" // Constructor CgroupV2Controller::CgroupV2Controller(char* mount_path, diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index 2ba4c252659..899e7535fde 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -22,15 +22,16 @@ * */ -#include -#include -#include -#include "runtime/globals.hpp" -#include "runtime/os.hpp" +#include "cgroupSubsystem_linux.hpp" #include "logging/log.hpp" #include "os_linux.hpp" #include "osContainer_linux.hpp" -#include "cgroupSubsystem_linux.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" + +#include +#include +#include bool OSContainer::_is_initialized = false; diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index 3c270e8ea50..d9b024dbbb5 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -25,10 +25,10 @@ #ifndef OS_LINUX_OSCONTAINER_LINUX_HPP #define OS_LINUX_OSCONTAINER_LINUX_HPP +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" -#include "memory/allStatic.hpp" #define OSCONTAINER_ERROR (-2) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index ba026442f7f..d133813feb0 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -36,9 +36,9 @@ #include "memory/allocation.inline.hpp" #include "nmt/memTracker.hpp" #include "oops/oop.inline.hpp" -#include "osContainer_linux.hpp" #include "os_linux.inline.hpp" #include "os_posix.inline.hpp" +#include "osContainer_linux.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" #include "runtime/arguments.hpp" @@ -81,42 +81,39 @@ #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif -// put OS-includes here # include -# include -# include -# include -# include -# include -# include -# include -# include +# include # include # include +# include # include -# include -# include -# include -# include +# include +# include +# include +# include # include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include # include +# include # include # include +# include # include -# include -# include -# include -# include -# include # include -# include -# include -# include -# include -# include -# include -# include -# include +# include #ifdef __GLIBC__ # include #endif diff --git a/src/hotspot/os/linux/os_linux.inline.hpp b/src/hotspot/os/linux/os_linux.inline.hpp index f9d798404b5..4b5592d2f62 100644 --- a/src/hotspot/os/linux/os_linux.inline.hpp +++ b/src/hotspot/os/linux/os_linux.inline.hpp @@ -27,8 +27,8 @@ #include "os_linux.hpp" -#include "runtime/os.hpp" #include "os_posix.inline.hpp" +#include "runtime/os.hpp" inline bool os::zero_page_read_protected() { return true; diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 9151049dd1c..7caf8f98a00 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -31,21 +31,21 @@ #include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" -#include -#include -#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include /** /proc/[number]/stat diff --git a/src/hotspot/os/linux/waitBarrier_linux.cpp b/src/hotspot/os/linux/waitBarrier_linux.cpp index f1f5be05152..0d5722f0725 100644 --- a/src/hotspot/os/linux/waitBarrier_linux.cpp +++ b/src/hotspot/os/linux/waitBarrier_linux.cpp @@ -26,8 +26,9 @@ #include "runtime/os.hpp" #include "utilities/debug.hpp" #include "waitBarrier_linux.hpp" -#include + #include +#include // 32-bit RISC-V has no SYS_futex syscall. #ifdef RISCV32 diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 19aaeed69a2..119f32ffe2e 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -43,6 +43,7 @@ public class TestIncludesAreSorted { * can be checked). */ private static final String[] HOTSPOT_SOURCES_TO_CHECK = { + "os/linux", "share" }; From bea2b029a77e126171d17c3a44baec6d5cafed4a Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Mon, 8 Sep 2025 08:30:03 +0000 Subject: [PATCH 170/295] 8360219: [AIX] assert(locals_base >= l2) failed: bad placement Reviewed-by: dlong, mdoerr --- src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp index beadce33637..9c74e6f53e7 100644 --- a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp +++ b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp @@ -100,7 +100,7 @@ int AbstractInterpreter::size_activation(int max_stack, // It is also guaranteed to be walkable even though it is in a skeletal state // // is_top_frame == true: -// We're processing the *oldest* interpreter frame! +// We're processing the *youngest* interpreter frame on top of stack! // // pop_frame_extra_args: // If this is != 0 we are returning to a deoptimized frame by popping @@ -131,8 +131,9 @@ void AbstractInterpreter::layout_activation(Method* method, #ifdef ASSERT if (caller->is_interpreted_frame()) { assert(locals_base <= caller->interpreter_frame_expression_stack(), "bad placement"); - const int caller_abi_bytesize = (is_bottom_frame ? frame::top_ijava_frame_abi_size : frame::parent_ijava_frame_abi_size); - intptr_t* l2 = caller->sp() + method->max_locals() - 1 + (caller_abi_bytesize / Interpreter::stackElementSize); + // If the bottom frame's caller was thawed then it has frame::java_abi (aka parent_ijava_frame_abi). + // With an ordinary i2c call it would keep the larger frame::top_ijava_frame_abi + intptr_t* l2 = caller->sp() + method->max_locals() - 1 + (frame::parent_ijava_frame_abi_size / Interpreter::stackElementSize); assert(locals_base >= l2, "bad placement"); } #endif From 5e423e034f1f077ce9c17cfe9b0d838a4cf9365e Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Mon, 8 Sep 2025 09:37:36 +0000 Subject: [PATCH 171/295] 8367025: zIndexDistributor.hpp uses angle-bracket inclusion of globalDefinitions.hpp Reviewed-by: aboldtch, tschatzl, jwaters --- src/hotspot/share/gc/z/zIndexDistributor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/z/zIndexDistributor.hpp b/src/hotspot/share/gc/z/zIndexDistributor.hpp index d4b9edcb5b4..2b46ddafdb2 100644 --- a/src/hotspot/share/gc/z/zIndexDistributor.hpp +++ b/src/hotspot/share/gc/z/zIndexDistributor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ #ifndef SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP #define SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP -#include +#include "utilities/globalDefinitions.hpp" class ZIndexDistributor { private: From a272696813f2e5e896ac9de9985246aaeb9d476c Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 8 Sep 2025 10:28:18 +0000 Subject: [PATCH 172/295] 8365190: Remove LockingMode related code from share Reviewed-by: aboldtch, dholmes, ayang, coleenp, lmesnik, rcastanedalo --- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 42 +- src/hotspot/share/c1/c1_LIRGenerator.cpp | 2 +- src/hotspot/share/c1/c1_Runtime1.cpp | 3 - .../share/gc/g1/g1BarrierSet.inline.hpp | 4 +- .../share/gc/g1/g1BarrierSetRuntime.cpp | 2 +- .../share/gc/g1/g1HeapRegion.inline.hpp | 6 +- .../share/gc/g1/g1SATBMarkQueueSet.cpp | 2 +- .../share/gc/shared/cardTableBarrierSet.cpp | 2 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 6 - .../interpreter/zero/bytecodeInterpreter.cpp | 127 +--- src/hotspot/share/jvmci/jvmciRuntime.cpp | 4 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 5 - .../share/oops/instanceStackChunkKlass.cpp | 4 - src/hotspot/share/oops/markWord.cpp | 33 +- src/hotspot/share/oops/markWord.hpp | 20 +- src/hotspot/share/oops/oop.cpp | 22 +- src/hotspot/share/oops/oop.hpp | 4 +- .../share/oops/stackChunkOop.inline.hpp | 3 +- src/hotspot/share/opto/library_call.cpp | 16 +- src/hotspot/share/opto/phaseX.cpp | 1 + src/hotspot/share/prims/jvmtiEnv.cpp | 10 - src/hotspot/share/runtime/arguments.cpp | 18 - src/hotspot/share/runtime/basicLock.cpp | 25 +- src/hotspot/share/runtime/basicLock.hpp | 11 - .../share/runtime/basicLock.inline.hpp | 10 - src/hotspot/share/runtime/continuation.cpp | 4 - .../share/runtime/continuationFreezeThaw.cpp | 31 +- src/hotspot/share/runtime/deoptimization.cpp | 52 +- src/hotspot/share/runtime/globals.hpp | 4 - src/hotspot/share/runtime/javaCalls.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 52 +- src/hotspot/share/runtime/javaThread.hpp | 3 - .../share/runtime/lightweightSynchronizer.cpp | 34 +- src/hotspot/share/runtime/lockStack.cpp | 1 - src/hotspot/share/runtime/objectMonitor.cpp | 3 +- src/hotspot/share/runtime/objectMonitor.hpp | 13 +- .../share/runtime/objectMonitor.inline.hpp | 14 +- src/hotspot/share/runtime/sharedRuntime.cpp | 13 +- src/hotspot/share/runtime/synchronizer.cpp | 684 +----------------- src/hotspot/share/runtime/synchronizer.hpp | 30 +- .../share/runtime/synchronizer.inline.hpp | 18 +- src/hotspot/share/runtime/threads.cpp | 21 +- src/hotspot/share/runtime/threads.hpp | 5 +- src/hotspot/share/runtime/vmStructs.cpp | 9 - .../share/utilities/globalDefinitions.cpp | 2 - .../share/utilities/globalDefinitions.hpp | 11 - src/hotspot/share/utilities/vmError.cpp | 2 +- .../jvm/hotspot/runtime/ObjectMonitor.java | 6 +- test/hotspot/gtest/runtime/test_lockStack.cpp | 12 +- .../locking/TestRecursiveMonitorChurn.java | 3 - 50 files changed, 141 insertions(+), 1270 deletions(-) diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 029ccbded13..28c2364315e 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -331,26 +331,9 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { monitor = nullptr; if (method->is_synchronized()) { monitor = (BasicObjectLock*) istate->stack_base(); - oop lockee = monitor->obj(); - bool success = false; - if (LockingMode == LM_LEGACY) { - markWord disp = lockee->mark().set_unlocked(); - monitor->lock()->set_displaced_header(disp); - success = true; - if (lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) { - // Is it simple recursive case? - if (thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) { - monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); - if (HAS_PENDING_EXCEPTION) - goto unwind_and_return; - } + CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); + if (HAS_PENDING_EXCEPTION) + goto unwind_and_return; } // Get the signature handler @@ -481,24 +464,7 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { // Unlock if necessary if (monitor) { - bool success = false; - if (LockingMode == LM_LEGACY) { - BasicLock* lock = monitor->lock(); - oop rcvr = monitor->obj(); - monitor->set_obj(nullptr); - success = true; - markWord header = lock->displaced_header(); - if (header.to_pointer() != nullptr) { // Check for recursive lock - markWord old_header = markWord::encode(lock); - if (rcvr->cas_set_mark(header, old_header) != old_header) { - monitor->set_obj(rcvr); - success = false; - } - } - } - if (!success) { - InterpreterRuntime::monitorexit(monitor); - } + InterpreterRuntime::monitorexit(monitor); } unwind_and_return: diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index cbd84b3a11e..b30667dcac3 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -635,7 +635,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L // setup registers LIR_Opr hdr = lock; lock = new_hdr; - CodeStub* slow_path = new MonitorExitStub(lock, LockingMode != LM_MONITOR, monitor_no); + CodeStub* slow_path = new MonitorExitStub(lock, true, monitor_no); __ load_stack_address_monitor(monitor_no, lock); __ unlock_object(hdr, object, lock, scratch, slow_path); } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 4a1969788f3..fbf2bfb0f53 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -778,9 +778,6 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj, _monitorenter_slowcase_cnt++; } #endif - if (LockingMode == LM_MONITOR) { - lock->set_obj(obj); - } assert(obj == lock->obj(), "must match"); SharedRuntime::monitor_enter_helper(obj, lock->lock(), current); JRT_END diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp index 33c153e9e5d..9678da190af 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ inline void G1BarrierSet::enqueue_preloaded(oop pre_val) { // Nulls should have been already filtered. - assert(oopDesc::is_oop(pre_val, true), "Error"); + assert(oopDesc::is_oop(pre_val), "Error"); G1SATBMarkQueueSet& queue_set = G1BarrierSet::satb_mark_queue_set(); if (!queue_set.is_active()) return; diff --git a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp index ce0d53e4891..205829bba1a 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp @@ -47,7 +47,7 @@ void G1BarrierSetRuntime::write_ref_array_post_entry(HeapWord* dst, size_t lengt JRT_LEAF(void, G1BarrierSetRuntime::write_ref_field_pre_entry(oopDesc* orig, JavaThread* thread)) assert(thread == JavaThread::current(), "pre-condition"); assert(orig != nullptr, "should be optimized out"); - assert(oopDesc::is_oop(orig, true /* ignore mark word */), "Error"); + assert(oopDesc::is_oop(orig), "Error"); // store the original value that was in the field reference SATBMarkQueue& queue = G1ThreadLocalData::satb_mark_queue(thread); G1BarrierSet::satb_mark_queue_set().enqueue_known_active(queue, orig); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index c2e5c5df4b1..236e72aeb91 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +350,7 @@ inline HeapWord* G1HeapRegion::oops_on_memregion_iterate_in_unparsable(MemRegion assert(bitmap->is_marked(cur), "inv"); oop obj = cast_to_oop(cur); - assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur)); + assert(oopDesc::is_oop(obj), "Not an oop at " PTR_FORMAT, p2i(cur)); cur += obj->size(); bool is_precise; @@ -418,7 +418,7 @@ inline HeapWord* G1HeapRegion::oops_on_memregion_iterate(MemRegion mr, Closure* // All objects >= pb are parsable. So we can just take object sizes directly. while (true) { oop obj = cast_to_oop(cur); - assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur)); + assert(oopDesc::is_oop(obj), "Not an oop at " PTR_FORMAT, p2i(cur)); bool is_precise = false; diff --git a/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp b/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp index f0b29a5bbab..7d197c37158 100644 --- a/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp +++ b/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp @@ -89,7 +89,7 @@ static inline bool requires_marking(const void* entry, G1CollectedHeap* g1h) { return false; } - assert(oopDesc::is_oop(cast_to_oop(entry), true /* ignore mark word */), + assert(oopDesc::is_oop(cast_to_oop(entry)), "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry)); return true; diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp index 84bf3eac130..dfa00636dec 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp @@ -162,7 +162,7 @@ void CardTableBarrierSet::flush_deferred_card_mark_barrier(JavaThread* thread) { DEBUG_ONLY(oop old_obj = cast_to_oop(deferred.start());) assert(!_card_table->is_in_young(old_obj), "Else should have been filtered in on_slowpath_allocation_exit()"); - assert(oopDesc::is_oop(old_obj, true), "Not an oop"); + assert(oopDesc::is_oop(old_obj), "Not an oop"); assert(deferred.word_size() == old_obj->size(), "Mismatch: multiple objects?"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index cf9d808f7ce..4de6ccead51 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -312,11 +312,6 @@ void ShenandoahHeap::increase_object_age(oop obj, uint additional_age) { // For all these reasons, we take the conservative approach and not attempt // to increase the age when the header is displaced. markWord w = obj->mark(); - // The mark-word has been copied from the original object. It can not be - // inflating, because inflation can not be interrupted by a safepoint, - // and after a safepoint, a Java thread would first have to successfully - // evacuate the object before it could inflate the monitor. - assert(!w.is_being_inflated() || LockingMode == LM_LIGHTWEIGHT, "must not inflate monitor before evacuation of object succeeds"); // It is possible that we have copied the object after another thread has // already successfully completed evacuation. While harmless (we would never // publish our copy), don't even attempt to modify the age when that @@ -334,7 +329,6 @@ uint ShenandoahHeap::get_object_age(oop obj) { markWord w = obj->mark(); assert(!w.is_marked(), "must not be forwarded"); if (UseObjectMonitorTable) { - assert(LockingMode == LM_LIGHTWEIGHT, "Must use LW locking, too"); assert(w.age() <= markWord::max_age, "Impossible!"); return w.age(); } diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index bfed16f2769..e9adfce6372 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -624,26 +624,7 @@ void BytecodeInterpreter::run(interpreterState istate) { // The initial monitor is ours for the taking. BasicObjectLock* mon = &istate->monitor_base()[-1]; mon->set_obj(rcvr); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // Traditional fast locking. - markWord displaced = rcvr->mark().set_unlocked(); - mon->lock()->set_displaced_header(displaced); - success = true; - if (rcvr->cas_set_mark(markWord::from_pointer(mon), displaced) != displaced) { - // Is it simple recursive case? - if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - mon->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); - } - + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); } THREAD->set_do_not_unlock_if_synchronized(false); @@ -725,26 +706,7 @@ void BytecodeInterpreter::run(interpreterState istate) { BasicObjectLock* entry = (BasicObjectLock*) istate->stack_base(); assert(entry->obj() == nullptr, "Frame manager didn't allocate the monitor"); entry->set_obj(lockee); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // Traditional fast locking. - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - success = true; - if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); - } - + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); UPDATE_PC_AND_TOS(1, -1); goto run; } @@ -1657,26 +1619,7 @@ run: } if (entry != nullptr) { entry->set_obj(lockee); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // Traditional fast locking. - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - success = true; - if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); - } - + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); @@ -1694,25 +1637,7 @@ run: while (most_recent != limit ) { if ((most_recent)->obj() == lockee) { BasicLock* lock = most_recent->lock(); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // If it isn't recursive we either must swap old header or call the runtime - most_recent->set_obj(nullptr); - success = true; - markWord header = lock->displaced_header(); - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - most_recent->set_obj(lockee); - success = false; - } - } - } - if (!success) { - InterpreterRuntime::monitorexit(most_recent); - } + InterpreterRuntime::monitorexit(most_recent); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } most_recent++; @@ -3137,27 +3062,7 @@ run: while (end < base) { oop lockee = end->obj(); if (lockee != nullptr) { - BasicLock* lock = end->lock(); - - bool success = false; - if (LockingMode == LM_LEGACY) { - markWord header = lock->displaced_header(); - end->set_obj(nullptr); - - // If it isn't recursive we either must swap old header or call the runtime - success = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - end->set_obj(lockee); - success = false; - } - } - } - if (!success) { - InterpreterRuntime::monitorexit(end); - } + InterpreterRuntime::monitorexit(end); // One error is plenty if (illegal_state_oop() == nullptr && !suppress_error) { @@ -3204,32 +3109,12 @@ run: illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); } - } else if (LockingMode != LM_LEGACY) { + } else { InterpreterRuntime::monitorexit(base); if (THREAD->has_pending_exception()) { if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); } - } else { - BasicLock* lock = base->lock(); - markWord header = lock->displaced_header(); - base->set_obj(nullptr); - - // If it isn't recursive we either must swap old header or call the runtime - bool dec_monitor_count = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (rcvr->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - base->set_obj(rcvr); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(base); - if (THREAD->has_pending_exception()) { - if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); - THREAD->clear_pending_exception(); - } - } - } } } } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c0335e7c67e..33aa40acbc2 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -565,8 +565,8 @@ JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, bool a if (obj == nullptr) { tty->print("null"); - } else if (oopDesc::is_oop_or_null(obj, true) && (!as_string || !java_lang_String::is_instance(obj))) { - if (oopDesc::is_oop_or_null(obj, true)) { + } else if (oopDesc::is_oop_or_null(obj) && (!as_string || !java_lang_String::is_instance(obj))) { + if (oopDesc::is_oop_or_null(obj)) { char buf[O_BUFLEN]; tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); } else { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 737718096c5..47ebe5aa7a7 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -341,7 +341,6 @@ volatile_nonstatic_field(ObjectMonitor, _recursions, intptr_t) \ volatile_nonstatic_field(ObjectMonitor, _entry_list, ObjectWaiter*) \ volatile_nonstatic_field(ObjectMonitor, _succ, int64_t) \ - volatile_nonstatic_field(ObjectMonitor, _stack_locker, BasicLock*) \ \ volatile_nonstatic_field(oopDesc, _mark, markWord) \ volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ @@ -780,10 +779,6 @@ declare_constant(InstanceKlass::being_initialized) \ declare_constant(InstanceKlass::fully_initialized) \ \ - declare_constant(LockingMode::LM_MONITOR) \ - declare_constant(LockingMode::LM_LEGACY) \ - declare_constant(LockingMode::LM_LIGHTWEIGHT) \ - \ /*********************************/ \ /* InstanceKlass _misc_flags */ \ /*********************************/ \ diff --git a/src/hotspot/share/oops/instanceStackChunkKlass.cpp b/src/hotspot/share/oops/instanceStackChunkKlass.cpp index bf08cfd25ab..db60e74013f 100644 --- a/src/hotspot/share/oops/instanceStackChunkKlass.cpp +++ b/src/hotspot/share/oops/instanceStackChunkKlass.cpp @@ -164,10 +164,6 @@ void InstanceStackChunkKlass::oop_oop_iterate_stack_slow(stackChunkOop chunk, Oo template void InstanceStackChunkKlass::oop_oop_iterate_lockstack(stackChunkOop chunk, OopIterateClosure* closure, MemRegion mr) { - if (LockingMode != LM_LIGHTWEIGHT) { - return; - } - StackChunkOopIterateFilterClosure cl(closure, mr); if (chunk->has_bitmap()) { chunk->iterate_lockstack(&cl); diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index 2ba57cddc67..001666b0439 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -36,35 +36,18 @@ STATIC_ASSERT(markWord::klass_shift == markWord::hash_bits + markWord::hash_shif markWord markWord::displaced_mark_helper() const { assert(has_displaced_mark_helper(), "check"); - if (has_monitor()) { - // Has an inflated monitor. Must be checked before has_locker(). - ObjectMonitor* monitor = this->monitor(); - return monitor->header(); - } - if (has_locker()) { // has a stack lock - BasicLock* locker = this->locker(); - return locker->displaced_header(); - } - // This should never happen: - fatal("bad header=" INTPTR_FORMAT, value()); - return markWord(value()); + // Make sure we have an inflated monitor. + guarantee(has_monitor(), "bad header=" INTPTR_FORMAT, value()); + ObjectMonitor* monitor = this->monitor(); + return monitor->header(); } void markWord::set_displaced_mark_helper(markWord m) const { assert(has_displaced_mark_helper(), "check"); - if (has_monitor()) { - // Has an inflated monitor. Must be checked before has_locker(). - ObjectMonitor* monitor = this->monitor(); - monitor->set_header(m); - return; - } - if (has_locker()) { // has a stack lock - BasicLock* locker = this->locker(); - locker->set_displaced_header(m); - return; - } - // This should never happen: - fatal("bad header=" INTPTR_FORMAT, value()); + // Make sure we have an inflated monitor. + guarantee(has_monitor(), "bad header=" INTPTR_FORMAT, value()); + ObjectMonitor* monitor = this->monitor(); + monitor->set_header(m); } void markWord::print_on(outputStream* st, bool print_monitor_info) const { diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 9cb46f4697d..08234709c97 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,17 +198,8 @@ class markWord { markWord set_unlocked() const { return markWord(value() | unlocked_value); } - bool has_locker() const { - assert(LockingMode == LM_LEGACY, "should only be called with legacy stack locking"); - return (value() & lock_mask_in_place) == locked_value; - } - BasicLock* locker() const { - assert(has_locker(), "check"); - return (BasicLock*) value(); - } bool is_fast_locked() const { - assert(LockingMode == LM_LIGHTWEIGHT, "should only be called with new lightweight locking"); return (value() & lock_mask_in_place) == locked_value; } markWord set_fast_locked() const { @@ -227,11 +218,7 @@ class markWord { } bool has_displaced_mark_helper() const { intptr_t lockbits = value() & lock_mask_in_place; - if (LockingMode == LM_LIGHTWEIGHT) { - return !UseObjectMonitorTable && lockbits == monitor_value; - } - // monitor (0b10) | stack-locked (0b00)? - return (lockbits & unlocked_value) == 0; + return !UseObjectMonitorTable && lockbits == monitor_value; } markWord displaced_mark_helper() const; void set_displaced_mark_helper(markWord m) const; @@ -304,17 +291,14 @@ class markWord { inline void* decode_pointer() const { return (void*)clear_lock_bits().value(); } inline bool is_self_forwarded() const { - NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");) return mask_bits(value(), self_fwd_mask_in_place) != 0; } inline markWord set_self_forwarded() const { - NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");) return markWord(value() | self_fwd_mask_in_place); } inline markWord unset_self_forwarded() const { - NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");) return markWord(value() & ~self_fwd_mask_in_place); } diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 7f0068f7473..be6e16855bd 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -110,27 +110,13 @@ intptr_t oopDesc::slow_identity_hash() { } // used only for asserts and guarantees -bool oopDesc::is_oop(oop obj, bool ignore_mark_word) { - if (!Universe::heap()->is_oop(obj)) { - return false; - } - - // Header verification: the mark is typically non-zero. If we're - // at a safepoint, it must not be zero, except when using the new lightweight locking. - // Outside of a safepoint, the header could be changing (for example, - // another thread could be inflating a lock on this object). - if (ignore_mark_word) { - return true; - } - if (obj->mark().value() != 0) { - return true; - } - return LockingMode == LM_LIGHTWEIGHT || !SafepointSynchronize::is_at_safepoint(); +bool oopDesc::is_oop(oop obj) { + return Universe::heap()->is_oop(obj); } // used only for asserts and guarantees -bool oopDesc::is_oop_or_null(oop obj, bool ignore_mark_word) { - return obj == nullptr ? true : is_oop(obj, ignore_mark_word); +bool oopDesc::is_oop_or_null(oop obj) { + return obj == nullptr ? true : is_oop(obj); } VerifyOopClosure VerifyOopClosure::verify_oop; diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 3ec0ce5764a..a1c1a64b050 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -261,8 +261,8 @@ class oopDesc { inline bool is_unlocked() const; // asserts and guarantees - static bool is_oop(oop obj, bool ignore_mark_word = false); - static bool is_oop_or_null(oop obj, bool ignore_mark_word = false); + static bool is_oop(oop obj); + static bool is_oop_or_null(oop obj); // garbage collection inline bool is_gc_marked() const; diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index 384dbefc10b..9c91e934328 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +195,6 @@ void stackChunkOopDesc::do_barriers(const StackChunkFrameStream& f, template inline void stackChunkOopDesc::iterate_lockstack(StackChunkLockStackClosureType* closure) { - assert(LockingMode == LM_LIGHTWEIGHT, ""); int cnt = lockstack_size(); intptr_t* lockstart_addr = start_address(); for (int i = 0; i < cnt; i++) { diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index da04d6b01ac..433dacc0ee1 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4788,19 +4788,11 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { // Test the header to see if it is safe to read w.r.t. locking. Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); - if (LockingMode == LM_LIGHTWEIGHT) { - Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); - Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); - Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); + Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); + Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); + Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); - generate_slow_guard(test_monitor, slow_region); - } else { - Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); - Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); - Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); - - generate_slow_guard(test_not_unlocked, slow_region); - } + generate_slow_guard(test_monitor, slow_region); } // Get the hash value and check to see that it has been properly assigned. diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1df2cdb179e..a4248cb2b91 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1670,6 +1670,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found (linux x64 only?) with: // serviceability/sa/ClhsdbThreadContext.java // -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 + // Note: The -XX:LockingMode option is not available anymore. case Op_StrEquals: return false; diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index bc4013a7cab..30dd1f77d23 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1367,11 +1367,6 @@ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, job return err; } - if (LockingMode == LM_LEGACY && java_thread == nullptr) { - *owned_monitor_count_ptr = 0; - return JVMTI_ERROR_NONE; - } - // growable array of jvmti monitors info on the C-heap GrowableArray *owned_monitors_list = new (mtServiceability) GrowableArray(1, mtServiceability); @@ -1427,11 +1422,6 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count return err; } - if (LockingMode == LM_LEGACY && java_thread == nullptr) { - *monitor_info_count_ptr = 0; - return JVMTI_ERROR_NONE; - } - // growable array of jvmti monitors info on the C-heap GrowableArray *owned_monitors_list = new (mtServiceability) GrowableArray(1, mtServiceability); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 2ebc15d0e1a..21706eb7726 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1854,24 +1854,6 @@ bool Arguments::check_vm_args_consistency() { } #endif - if (UseObjectMonitorTable && LockingMode != LM_LIGHTWEIGHT) { - // ObjectMonitorTable requires lightweight locking. - FLAG_SET_CMDLINE(UseObjectMonitorTable, false); - warning("UseObjectMonitorTable requires LM_LIGHTWEIGHT"); - } - -#if !defined(X86) && !defined(AARCH64) && !defined(PPC64) && !defined(RISCV64) && !defined(S390) - if (LockingMode == LM_MONITOR) { - jio_fprintf(defaultStream::error_stream(), - "LockingMode == 0 (LM_MONITOR) is not fully implemented on this architecture\n"); - return false; - } -#endif - if (VerifyHeavyMonitors && LockingMode != LM_MONITOR) { - jio_fprintf(defaultStream::error_stream(), - "-XX:+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)\n"); - return false; - } return status; } diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 384fc493e0b..71082e24bb9 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -34,13 +34,6 @@ void BasicLock::print_on(outputStream* st, oop owner) const { if (mon != nullptr) { mon->print_on(st); } - } else if (LockingMode == LM_LEGACY) { - markWord mark_word = displaced_header(); - if (mark_word.value() != 0) { - // Print monitor info if there's an owning oop and it refers to this BasicLock. - bool print_monitor_info = (owner != nullptr) && (owner->mark() == markWord::from_pointer((void*)this)); - mark_word.print_on(st, print_monitor_info); - } } } @@ -73,23 +66,7 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { // small (given the support for inflated fast-path locking in the fast_lock, etc) // we'll leave that optimization for another time. - if (LockingMode == LM_LEGACY) { - if (displaced_header().is_neutral()) { - // The object is locked and the resulting ObjectMonitor* will also be - // locked so it can't be async deflated until ownership is dropped. - ObjectSynchronizer::inflate_helper(obj); - // WARNING: We cannot put a check here, because the inflation - // will not update the displaced header. Once BasicLock is inflated, - // no one should ever look at its content. - } else { - // Typically the displaced header will be 0 (recursive stack lock) or - // unused_mark. Naively we'd like to assert that the displaced mark - // value is either 0, neutral, or 3. But with the advent of the - // store-before-CAS avoidance in fast_lock/compiler_lock_object - // we can find any flavor mark in the displaced mark. - } - dest->set_displaced_header(displaced_header()); - } else if (UseObjectMonitorTable) { + if (UseObjectMonitorTable) { // Preserve the ObjectMonitor*, the cache is cleared when a box is reused // and only read while the lock is held, so no stale ObjectMonitor* is // encountered. diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index 50de8db6bc6..8ed38747c74 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -35,12 +35,6 @@ class BasicLock { friend class VMStructs; friend class JVMCIVMStructs; private: - // * For LM_MONITOR - // Unused. - // * For LM_LEGACY - // This is either the actual displaced header from a locked object, or - // a sentinel zero value indicating a recursive stack-lock. - // * For LM_LIGHTWEIGHT // Used as a cache of the ObjectMonitor* used when locking. Must either // be nullptr or the ObjectMonitor* used when locking. volatile uintptr_t _metadata; @@ -52,15 +46,10 @@ class BasicLock { public: BasicLock() : _metadata(0) {} - // LM_MONITOR void set_bad_metadata_deopt() { set_metadata(badDispHeaderDeopt); } - // LM_LEGACY - inline markWord displaced_header() const; - inline void set_displaced_header(markWord header); static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); } - // LM_LIGHTWEIGHT inline ObjectMonitor* object_monitor_cache() const; inline void clear_object_monitor_cache(); inline void set_object_monitor_cache(ObjectMonitor* mon); diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 773d8a1c848..2ea1fe2371c 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -29,16 +29,6 @@ #include "runtime/objectMonitor.inline.hpp" -inline markWord BasicLock::displaced_header() const { - assert(LockingMode == LM_LEGACY, "must be"); - return markWord(get_metadata()); -} - -inline void BasicLock::set_displaced_header(markWord header) { - assert(LockingMode == LM_LEGACY, "must be"); - Atomic::store(&_metadata, header.value()); -} - inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); #if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390)) diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 727dcf8fc26..8f1cbe39640 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -146,10 +146,6 @@ static void verify_preempt_preconditions(JavaThread* current, oop continuation) freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { verify_preempt_preconditions(current, continuation); - if (LockingMode == LM_LEGACY) { - return freeze_unsupported; - } - if (!is_vthread_safe_to_preempt(current, current->vthread())) { return freeze_pinned_native; } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 40a8987e139..64f9d2b9994 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -533,11 +533,7 @@ FreezeBase::FreezeBase(JavaThread* thread, ContinuationWrapper& cont, intptr_t* cont_size(), _cont.argsize(), p2i(_cont_stack_top), p2i(_cont_stack_bottom)); assert(cont_size() > 0, ""); - if (LockingMode != LM_LIGHTWEIGHT) { - _monitors_in_lockstack = 0; - } else { - _monitors_in_lockstack = _thread->lock_stack().monitor_count(); - } + _monitors_in_lockstack = _thread->lock_stack().monitor_count(); } void FreezeBase::init_rest() { // we want to postpone some initialization after chunk handling @@ -587,33 +583,12 @@ static void assert_frames_in_continuation_are_safe(JavaThread* thread) { #endif // ASSERT } -#ifdef ASSERT -static bool monitors_on_stack(JavaThread* thread) { - assert_frames_in_continuation_are_safe(thread); - ContinuationEntry* ce = thread->last_continuation(); - RegisterMap map(thread, - RegisterMap::UpdateMap::include, - RegisterMap::ProcessFrames::skip, - RegisterMap::WalkContinuation::skip); - map.set_include_argument_oops(false); - for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) { - if ((f.is_interpreted_frame() && ContinuationHelper::InterpretedFrame::is_owning_locks(f)) || - (f.is_compiled_frame() && ContinuationHelper::CompiledFrame::is_owning_locks(map.thread(), &map, f)) || - (f.is_native_frame() && ContinuationHelper::NativeFrame::is_owning_locks(map.thread(), f))) { - return true; - } - } - return false; -} -#endif // ASSERT - // Called _after_ the last possible safepoint during the freeze operation (chunk allocation) void FreezeBase::unwind_frames() { ContinuationEntry* entry = _cont.entry(); entry->flush_stack_processing(_thread); assert_frames_in_continuation_are_safe(_thread); JFR_ONLY(Jfr::check_and_process_sample_request(_thread);) - assert(LockingMode != LM_LEGACY || !monitors_on_stack(_thread), "unexpected monitors on stack"); set_anchor_to_entry(_thread, entry); } @@ -1762,8 +1737,8 @@ static inline freeze_result freeze_internal(JavaThread* current, intptr_t* const assert(entry->is_virtual_thread() == (entry->scope(current) == java_lang_VirtualThread::vthread_scope()), ""); - assert(LockingMode == LM_LEGACY || (current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), - "Held monitor count should only be used for LM_LEGACY: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); + assert((current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), + "Held monitor count should not be used for lightweight locking: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); if (entry->is_pinned() || current->held_monitor_count() > 0) { log_develop_debug(continuations)("PINNED due to critical section/hold monitor"); diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index da9a4e9cd9a..693815c6fc4 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1645,26 +1645,17 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArrayowner()); markWord mark = obj->mark(); if (exec_mode == Unpack_none) { - if (LockingMode == LM_LEGACY && mark.has_locker() && fr.sp() > (intptr_t*)mark.locker()) { - // With exec_mode == Unpack_none obj may be thread local and locked in - // a callee frame. Make the lock in the callee a recursive lock and restore the displaced header. - markWord dmw = mark.displaced_mark_helper(); - mark.locker()->set_displaced_header(markWord::encode((BasicLock*) nullptr)); - obj->set_mark(dmw); - } if (mark.has_monitor()) { // defer relocking if the deoptee thread is currently waiting for obj ObjectMonitor* waiting_monitor = deoptee_thread->current_waiting_monitor(); if (waiting_monitor != nullptr && waiting_monitor->object() == obj()) { assert(fr.is_deoptimized_frame(), "frame must be scheduled for deoptimization"); - if (LockingMode == LM_LEGACY) { - mon_info->lock()->set_displaced_header(markWord::unused_mark()); - } else if (UseObjectMonitorTable) { + if (UseObjectMonitorTable) { mon_info->lock()->clear_object_monitor_cache(); } #ifdef ASSERT else { - assert(LockingMode == LM_MONITOR || !UseObjectMonitorTable, "must be"); + assert(!UseObjectMonitorTable, "must be"); mon_info->lock()->set_bad_metadata_deopt(); } #endif @@ -1674,29 +1665,24 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraylock(); - if (LockingMode == LM_LIGHTWEIGHT) { - // We have lost information about the correct state of the lock stack. - // Entering may create an invalid lock stack. Inflate the lock if it - // was fast_locked to restore the valid lock stack. - if (UseObjectMonitorTable) { - // UseObjectMonitorTable expects the BasicLock cache to be either a - // valid ObjectMonitor* or nullptr. Right now it is garbage, set it - // to nullptr. - lock->clear_object_monitor_cache(); - } - ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); - if (deoptee_thread->lock_stack().contains(obj())) { - LightweightSynchronizer::inflate_fast_locked_object(obj(), ObjectSynchronizer::InflateCause::inflate_cause_vm_internal, - deoptee_thread, thread); - } - assert(mon_info->owner()->is_locked(), "object must be locked now"); - assert(obj->mark().has_monitor(), "must be"); - assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); - assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->has_owner(deoptee_thread), "must be"); - } else { - ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); - assert(mon_info->owner()->is_locked(), "object must be locked now"); + // We have lost information about the correct state of the lock stack. + // Entering may create an invalid lock stack. Inflate the lock if it + // was fast_locked to restore the valid lock stack. + if (UseObjectMonitorTable) { + // UseObjectMonitorTable expects the BasicLock cache to be either a + // valid ObjectMonitor* or nullptr. Right now it is garbage, set it + // to nullptr. + lock->clear_object_monitor_cache(); } + ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); + if (deoptee_thread->lock_stack().contains(obj())) { + LightweightSynchronizer::inflate_fast_locked_object(obj(), ObjectSynchronizer::InflateCause::inflate_cause_vm_internal, + deoptee_thread, thread); + } + assert(mon_info->owner()->is_locked(), "object must be locked now"); + assert(obj->mark().has_monitor(), "must be"); + assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); + assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->has_owner(deoptee_thread), "must be"); } } } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 9149e389e21..e76b7474891 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1048,10 +1048,6 @@ const int ObjectAlignmentInBytes = 8; product(bool, ErrorFileToStdout, false, \ "If true, error data is printed to stdout instead of a file") \ \ - develop(bool, VerifyHeavyMonitors, false, \ - "Checks that no stack locking happens when using " \ - "-XX:LockingMode=0 (LM_MONITOR)") \ - \ product(bool, PrintStringTableStatistics, false, \ "print statistics about the StringTable and SymbolTable") \ \ diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index f237886c128..ec3132220d9 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -553,7 +553,7 @@ class SignatureChekker : public SignatureIterator { "Bad JNI oop argument %d: " PTR_FORMAT, _pos, v); // Verify the pointee. oop vv = resolve_indirect_oop(v, _value_state[_pos]); - guarantee(oopDesc::is_oop_or_null(vv, true), + guarantee(oopDesc::is_oop_or_null(vv), "Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT, _pos, v, p2i(vv)); } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 89d742e0ea8..ba98f5928aa 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1063,11 +1063,6 @@ JavaThread* JavaThread::active() { } } -bool JavaThread::is_lock_owned(address adr) const { - assert(LockingMode != LM_LIGHTWEIGHT, "should not be called with new lightweight locking"); - return is_in_full_stack(adr); -} - oop JavaThread::exception_oop() const { return Atomic::load(&_exception_oop); } @@ -1437,9 +1432,8 @@ void JavaThread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) { entry = entry->parent(); } - if (LockingMode == LM_LIGHTWEIGHT) { - lock_stack().oops_do(f); - } + // Due to lightweight locking + lock_stack().oops_do(f); } void JavaThread::oops_do_frames(OopClosure* f, NMethodClosure* cf) { @@ -1999,22 +1993,9 @@ void JavaThread::trace_stack() { // this slow-path. void JavaThread::inc_held_monitor_count(intx i, bool jni) { #ifdef SUPPORT_MONITOR_COUNT - - if (LockingMode != LM_LEGACY) { - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); - return; - } - - assert(_held_monitor_count >= 0, "Must always be non-negative: %zd", _held_monitor_count); - _held_monitor_count += i; - if (jni) { - assert(_jni_monitor_count >= 0, "Must always be non-negative: %zd", _jni_monitor_count); - _jni_monitor_count += i; - } - assert(_held_monitor_count >= _jni_monitor_count, "Monitor count discrepancy detected - held count " - "%zd is less than JNI count %zd", _held_monitor_count, _jni_monitor_count); + // Nothing to do. Just do some sanity check. + assert(_held_monitor_count == 0, "counter should not be used"); + assert(_jni_monitor_count == 0, "counter should not be used"); #endif // SUPPORT_MONITOR_COUNT } @@ -2022,26 +2003,9 @@ void JavaThread::inc_held_monitor_count(intx i, bool jni) { // this slow-path. void JavaThread::dec_held_monitor_count(intx i, bool jni) { #ifdef SUPPORT_MONITOR_COUNT - - if (LockingMode != LM_LEGACY) { - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); - return; - } - - _held_monitor_count -= i; - assert(_held_monitor_count >= 0, "Must always be non-negative: %zd", _held_monitor_count); - if (jni) { - _jni_monitor_count -= i; - assert(_jni_monitor_count >= 0, "Must always be non-negative: %zd", _jni_monitor_count); - } - // When a thread is detaching with still owned JNI monitors, the logic that releases - // the monitors doesn't know to set the "jni" flag and so the counts can get out of sync. - // So we skip this assert if the thread is exiting. Once all monitors are unlocked the - // JNI count is directly set to zero. - assert(_held_monitor_count >= _jni_monitor_count || is_exiting(), "Monitor count discrepancy detected - held count " - "%zd is less than JNI count %zd", _held_monitor_count, _jni_monitor_count); + // Nothing to do. Just do some sanity check. + assert(_held_monitor_count == 0, "counter should not be used"); + assert(_jni_monitor_count == 0, "counter should not be used"); #endif // SUPPORT_MONITOR_COUNT } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index bf72fac5737..32003e1962e 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -755,9 +755,6 @@ public: return (_suspend_flags & _obj_deopt) != 0; } - // Stack-locking support (not for LM_LIGHTWEIGHT) - bool is_lock_owned(address adr) const; - // Accessors for vframe array top // The linked list of vframe arrays are sorted on sp. This means when we // unpack the head must contain the vframe array to unpack. diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp index 423ca990abd..6cec5c80982 100644 --- a/src/hotspot/share/runtime/lightweightSynchronizer.cpp +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -333,8 +333,6 @@ size_t ObjectMonitorTable::_table_size = 0; volatile bool ObjectMonitorTable::_resize = false; ObjectMonitor* LightweightSynchronizer::get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - ObjectMonitor* monitor = get_monitor_from_table(current, object); if (monitor != nullptr) { *inserted = false; @@ -628,7 +626,6 @@ bool LightweightSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stac } void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(!UseObjectMonitorTable || lock->object_monitor_cache() == nullptr, "must be cleared"); JavaThread* current = JavaThread::current(); VerifyThreadState vts(locking_thread, current); @@ -657,7 +654,6 @@ void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* } void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(current == JavaThread::current(), "must be"); if (obj->klass()->is_value_based()) { @@ -718,7 +714,6 @@ void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* cur } void LightweightSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(current == Thread::current(), "must be"); markWord mark = object->mark(); @@ -770,18 +765,14 @@ void LightweightSynchronizer::exit(oop object, BasicLock* lock, JavaThread* curr monitor->exit(current); } -// LightweightSynchronizer::inflate_locked_or_imse is used to to get an inflated -// ObjectMonitor* with LM_LIGHTWEIGHT. It is used from contexts which require -// an inflated ObjectMonitor* for a monitor, and expects to throw a -// java.lang.IllegalMonitorStateException if it is not held by the current -// thread. Such as notify/wait and jni_exit. LM_LIGHTWEIGHT keeps it invariant -// that it only inflates if it is already locked by the current thread or the -// current thread is in the process of entering. To maintain this invariant we -// need to throw a java.lang.IllegalMonitorStateException before inflating if -// the current thread is not the owner. -// LightweightSynchronizer::inflate_locked_or_imse facilitates this. +// LightweightSynchronizer::inflate_locked_or_imse is used to get an +// inflated ObjectMonitor* from contexts which require that, such as +// notify/wait and jni_exit. Lightweight locking keeps the invariant that it +// only inflates if it is already locked by the current thread or the current +// thread is in the process of entering. To maintain this invariant we need to +// throw a java.lang.IllegalMonitorStateException before inflating if the +// current thread is not the owner. ObjectMonitor* LightweightSynchronizer::inflate_locked_or_imse(oop obj, ObjectSynchronizer::InflateCause cause, TRAPS) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); JavaThread* current = THREAD; for (;;) { @@ -826,12 +817,11 @@ ObjectMonitor* LightweightSynchronizer::inflate_locked_or_imse(oop obj, ObjectSy ObjectMonitor* LightweightSynchronizer::inflate_into_object_header(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, Thread* current) { - // The JavaThread* locking_thread parameter is only used by LM_LIGHTWEIGHT and requires - // that the locking_thread == Thread::current() or is suspended throughout the call by - // some other mechanism. - // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non + // The JavaThread* locking parameter requires that the locking_thread == JavaThread::current, + // or is suspended throughout the call by some other mechanism. + // Even with lightweight locking the thread might be nullptr when called from a non // JavaThread. (As may still be the case from FastHashCode). However it is only - // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread + // important for the correctness of the lightweight locking algorithm that the thread // is set when called from ObjectSynchronizer::enter from the owning thread, // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. EventJavaMonitorInflate event; @@ -943,7 +933,6 @@ ObjectMonitor* LightweightSynchronizer::inflate_into_object_header(oop object, O } ObjectMonitor* LightweightSynchronizer::inflate_fast_locked_object(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); VerifyThreadState vts(locking_thread, current); assert(locking_thread->lock_stack().contains(object), "locking_thread must have object on its lock stack"); @@ -1000,7 +989,6 @@ ObjectMonitor* LightweightSynchronizer::inflate_fast_locked_object(oop object, O } ObjectMonitor* LightweightSynchronizer::inflate_and_enter(oop object, BasicLock* lock, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); VerifyThreadState vts(locking_thread, current); // Note: In some paths (deoptimization) the 'current' thread inflates and diff --git a/src/hotspot/share/runtime/lockStack.cpp b/src/hotspot/share/runtime/lockStack.cpp index cab54e420a9..a55c5a6451b 100644 --- a/src/hotspot/share/runtime/lockStack.cpp +++ b/src/hotspot/share/runtime/lockStack.cpp @@ -77,7 +77,6 @@ uint32_t LockStack::end_offset() { #ifndef PRODUCT void LockStack::verify(const char* msg) const { - assert(LockingMode == LM_LIGHTWEIGHT, "never use lock-stack when light weight locking is disabled"); assert((_top <= end_offset()), "lockstack overflow: _top %d end_offset %d", _top, end_offset()); assert((_top >= start_offset()), "lockstack underflow: _top %d start_offset %d", _top, start_offset()); if (SafepointSynchronize::is_at_safepoint() || (Thread::current()->is_Java_thread() && is_owning_thread())) { diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 9e3638ddadc..c1febe7a28c 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -296,8 +296,7 @@ ObjectMonitor::ObjectMonitor(oop object) : _contentions(0), _wait_set(nullptr), _waiters(0), - _wait_set_lock(0), - _stack_locker(nullptr) + _wait_set_lock(0) { } ObjectMonitor::~ObjectMonitor() { diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index c8daeb65b50..ab315ba0fc5 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -160,9 +160,9 @@ class ObjectMonitor : public CHeapObj { // Because of frequent access, the metadata field is at offset zero (0). // Enforced by the assert() in metadata_addr(). - // * LM_LIGHTWEIGHT with UseObjectMonitorTable: - // Contains the _object's hashCode. - // * LM_LEGACY, LM_MONITOR, LM_LIGHTWEIGHT without UseObjectMonitorTable: + // * Lightweight locking with UseObjectMonitorTable: + // Contains the _object's hashCode. + // * * Lightweight locking without UseObjectMonitorTable: // Contains the displaced object header word - mark volatile uintptr_t _metadata; // metadata WeakHandle _object; // backward object pointer @@ -204,9 +204,6 @@ class ObjectMonitor : public CHeapObj { volatile int _waiters; // number of waiting threads volatile int _wait_set_lock; // protects wait set queue - simple spinlock - // Used in LM_LEGACY mode to store BasicLock* in case of inflation by contending thread. - BasicLock* volatile _stack_locker; - public: static void Initialize(); @@ -318,10 +315,6 @@ class ObjectMonitor : public CHeapObj { set_owner_from(ANONYMOUS_OWNER, owner); } - // Get and set _stack_locker. - BasicLock* stack_locker() const; - void set_stack_locker(BasicLock* locker); - // Simply get _next_om field. ObjectMonitor* next_om() const; // Simply set _next_om field to new_value. diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index 7dabc50fca7..05ad06c9bf3 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -52,11 +52,7 @@ inline int64_t ObjectMonitor::owner_id_from(oop vthread) { inline bool ObjectMonitor::is_entered(JavaThread* current) const { if (has_anonymous_owner()) { - if (LockingMode == LM_LIGHTWEIGHT) { - return current->lock_stack().contains(object()); - } else { - return current->is_lock_owned((address)stack_locker()); - } + return current->lock_stack().contains(object()); } else { return has_owner(current); } @@ -116,14 +112,6 @@ inline int64_t ObjectMonitor::owner_raw() const { return Atomic::load(&_owner); } -inline BasicLock* ObjectMonitor::stack_locker() const { - return Atomic::load(&_stack_locker); -} - -inline void ObjectMonitor::set_stack_locker(BasicLock* locker) { - Atomic::store(&_stack_locker, locker); -} - // Returns true if owner field == DEFLATER_MARKER and false otherwise. inline bool ObjectMonitor::owner_is_DEFLATER_MARKER() const { return owner_raw() == DEFLATER_MARKER; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 4d3f1327d43..60161643315 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3348,18 +3348,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) kptr2 = fr.next_monitor_in_interpreter_frame(kptr2) ) { if (kptr2->obj() != nullptr) { // Avoid 'holes' in the monitor array BasicLock *lock = kptr2->lock(); - if (LockingMode == LM_LEGACY) { - // Inflate so the object's header no longer refers to the BasicLock. - if (lock->displaced_header().is_unlocked()) { - // The object is locked and the resulting ObjectMonitor* will also be - // locked so it can't be async deflated until ownership is dropped. - // See the big comment in basicLock.cpp: BasicLock::move_to(). - ObjectSynchronizer::inflate_helper(kptr2->obj()); - } - // Now the displaced header is free to move because the - // object's header no longer refers to it. - buf[i] = (intptr_t)lock->displaced_header().value(); - } else if (UseObjectMonitorTable) { + if (UseObjectMonitorTable) { buf[i] = (intptr_t)lock->object_monitor_cache(); } #ifdef ASSERT diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index f3e3072978b..ec4e91d8c6f 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -281,9 +281,7 @@ void ObjectSynchronizer::initialize() { // Start the timer for deflations, so it does not trigger immediately. _last_async_deflation_time_ns = os::javaTimeNanos(); - if (LockingMode == LM_LIGHTWEIGHT) { - LightweightSynchronizer::initialize(); - } + LightweightSynchronizer::initialize(); } MonitorList ObjectSynchronizer::_in_use_list; @@ -342,23 +340,15 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al if (obj == nullptr) return false; // slow-path for invalid obj const markWord mark = obj->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) { - // Degenerate notify - // fast-locked by caller so by definition the implied waitset is empty. - return true; - } - } else if (LockingMode == LM_LEGACY) { - if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) { - // Degenerate notify - // stack-locked by caller so by definition the implied waitset is empty. - return true; - } + if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) { + // Degenerate notify + // fast-locked by caller so by definition the implied waitset is empty. + return true; } if (mark.has_monitor()) { ObjectMonitor* const mon = read_monitor(current, obj, mark); - if (LockingMode == LM_LIGHTWEIGHT && mon == nullptr) { + if (mon == nullptr) { // Racing with inflation/deflation go slow path return false; } @@ -381,79 +371,6 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al return false; } -static bool useHeavyMonitors() { -#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) || defined(S390) - return LockingMode == LM_MONITOR; -#else - return false; -#endif -} - -// The LockNode emitted directly at the synchronization site would have -// been too big if it were to have included support for the cases of inflated -// recursive enter and exit, so they go here instead. -// Note that we can't safely call AsyncPrintJavaStack() from within -// quick_enter() as our thread state remains _in_Java. - -bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread* current) { - assert(current->thread_state() == _thread_in_Java, "invariant"); - - if (useHeavyMonitors()) { - return false; // Slow path - } - - assert(LockingMode == LM_LEGACY, "legacy mode below"); - - const markWord mark = obj->mark(); - - if (mark.has_monitor()) { - - ObjectMonitor* const m = read_monitor(mark); - // An async deflation or GC can race us before we manage to make - // the ObjectMonitor busy by setting the owner below. If we detect - // that race we just bail out to the slow-path here. - if (m->object_peek() == nullptr) { - return false; - } - - // Lock contention and Transactional Lock Elision (TLE) diagnostics - // and observability - // Case: light contention possibly amenable to TLE - // Case: TLE inimical operations such as nested/recursive synchronization - - if (m->has_owner(current)) { - m->increment_recursions(current); - current->inc_held_monitor_count(); - return true; - } - - // This Java Monitor is inflated so obj's header will never be - // displaced to this thread's BasicLock. Make the displaced header - // non-null so this BasicLock is not seen as recursive nor as - // being locked. We do this unconditionally so that this thread's - // BasicLock cannot be mis-interpreted by any stack walkers. For - // performance reasons, stack walkers generally first check for - // stack-locking in the object's header, the second check is for - // recursive stack-locking in the displaced header in the BasicLock, - // and last are the inflated Java Monitor (ObjectMonitor) checks. - lock->set_displaced_header(markWord::unused_mark()); - - if (!m->has_owner() && m->try_set_owner(current)) { - assert(m->recursions() == 0, "invariant"); - current->inc_held_monitor_count(); - return true; - } - } - - // Note that we could inflate in quick_enter. - // This is likely a useful optimization - // Critically, in quick_enter() we must not: - // -- block indefinitely, or - // -- reach a safepoint - - return false; // revert to slow-path -} - // Handle notifications when synchronizing on value based classes void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread* locking_thread) { assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); @@ -512,144 +429,7 @@ void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* lock // the locking_thread with respect to the current thread. Currently only used when // deoptimizing and re-locking locks. See Deoptimization::relock_objects assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); - - if (LockingMode == LM_LIGHTWEIGHT) { - return LightweightSynchronizer::enter_for(obj, lock, locking_thread); - } - - if (!enter_fast_impl(obj, lock, locking_thread)) { - // Inflated ObjectMonitor::enter_for is required - - // An async deflation can race after the inflate_for() call and before - // enter_for() can make the ObjectMonitor busy. enter_for() returns false - // if we have lost the race to async deflation and we simply try again. - while (true) { - ObjectMonitor* monitor = inflate_for(locking_thread, obj(), inflate_cause_monitor_enter); - if (monitor->enter_for(locking_thread)) { - return; - } - assert(monitor->is_being_async_deflated(), "must be"); - } - } -} - -void ObjectSynchronizer::enter_legacy(Handle obj, BasicLock* lock, JavaThread* current) { - if (!enter_fast_impl(obj, lock, current)) { - // Inflated ObjectMonitor::enter is required - - // An async deflation can race after the inflate() call and before - // enter() can make the ObjectMonitor busy. enter() returns false if - // we have lost the race to async deflation and we simply try again. - while (true) { - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_monitor_enter); - if (monitor->enter(current)) { - return; - } - } - } -} - -// The interpreter and compiler assembly code tries to lock using the fast path -// of this algorithm. Make sure to update that code if the following function is -// changed. The implementation is extremely sensitive to race condition. Be careful. -bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) { - assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); - - if (obj->klass()->is_value_based()) { - handle_sync_on_value_based_class(obj, locking_thread); - } - - locking_thread->inc_held_monitor_count(); - - if (!useHeavyMonitors()) { - if (LockingMode == LM_LEGACY) { - markWord mark = obj->mark(); - if (mark.is_unlocked()) { - // Anticipate successful CAS -- the ST of the displaced mark must - // be visible <= the ST performed by the CAS. - lock->set_displaced_header(mark); - if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) { - return true; - } - } else if (mark.has_locker() && - locking_thread->is_lock_owned((address) mark.locker())) { - assert(lock != mark.locker(), "must not re-lock the same lock"); - assert(lock != (BasicLock*) obj->mark().value(), "don't relock with same BasicLock"); - lock->set_displaced_header(markWord::from_pointer(nullptr)); - return true; - } - - // The object header will never be displaced to this lock, - // so it does not matter what the value is, except that it - // must be non-zero to avoid looking like a re-entrant lock, - // and must not look locked either. - lock->set_displaced_header(markWord::unused_mark()); - - // Failed to fast lock. - return false; - } - } else if (VerifyHeavyMonitors) { - guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); - } - - return false; -} - -void ObjectSynchronizer::exit_legacy(oop object, BasicLock* lock, JavaThread* current) { - assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); - - if (!useHeavyMonitors()) { - markWord mark = object->mark(); - if (LockingMode == LM_LEGACY) { - markWord dhw = lock->displaced_header(); - if (dhw.value() == 0) { - // If the displaced header is null, then this exit matches up with - // a recursive enter. No real work to do here except for diagnostics. -#ifndef PRODUCT - if (mark != markWord::INFLATING()) { - // Only do diagnostics if we are not racing an inflation. Simply - // exiting a recursive enter of a Java Monitor that is being - // inflated is safe; see the has_monitor() comment below. - assert(!mark.is_unlocked(), "invariant"); - assert(!mark.has_locker() || - current->is_lock_owned((address)mark.locker()), "invariant"); - if (mark.has_monitor()) { - // The BasicLock's displaced_header is marked as a recursive - // enter and we have an inflated Java Monitor (ObjectMonitor). - // This is a special case where the Java Monitor was inflated - // after this thread entered the stack-lock recursively. When a - // Java Monitor is inflated, we cannot safely walk the Java - // Monitor owner's stack and update the BasicLocks because a - // Java Monitor can be asynchronously inflated by a thread that - // does not own the Java Monitor. - ObjectMonitor* m = read_monitor(mark); - assert(m->object()->mark() == mark, "invariant"); - assert(m->is_entered(current), "invariant"); - } - } -#endif - return; - } - - if (mark == markWord::from_pointer(lock)) { - // If the object is stack-locked by the current thread, try to - // swing the displaced header from the BasicLock back to the mark. - assert(dhw.is_neutral(), "invariant"); - if (object->cas_set_mark(dhw, mark) == mark) { - return; - } - } - } - } else if (VerifyHeavyMonitors) { - guarantee((object->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); - } - - // We have to take the slow-path of possible inflation and then exit. - // The ObjectMonitor* can't be async deflated until ownership is - // dropped inside exit() and the ObjectMonitor* must be !is_busy(). - ObjectMonitor* monitor = inflate(current, object, inflate_cause_vm_internal); - assert(!monitor->has_anonymous_owner(), "must not be"); - monitor->exit(current); + return LightweightSynchronizer::enter_for(obj, lock, locking_thread); } // ----------------------------------------------------------------------------- @@ -670,17 +450,8 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { // enter() can make the ObjectMonitor busy. enter() returns false if // we have lost the race to async deflation and we simply try again. while (true) { - ObjectMonitor* monitor; - bool entered; - if (LockingMode == LM_LIGHTWEIGHT) { - BasicLock lock; - entered = LightweightSynchronizer::inflate_and_enter(obj(), &lock, inflate_cause_jni_enter, current, current) != nullptr; - } else { - monitor = inflate(current, obj(), inflate_cause_jni_enter); - entered = monitor->enter(current); - } - - if (entered) { + BasicLock lock; + if (LightweightSynchronizer::inflate_and_enter(obj(), &lock, inflate_cause_jni_enter, current, current) != nullptr) { current->inc_held_monitor_count(1, true); break; } @@ -693,13 +464,7 @@ void ObjectSynchronizer::jni_exit(oop obj, TRAPS) { JavaThread* current = THREAD; ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK); - } else { - // The ObjectMonitor* can't be async deflated until ownership is - // dropped inside exit() and the ObjectMonitor* must be !is_busy(). - monitor = inflate(current, obj, inflate_cause_jni_exit); - } + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK); // If this thread has locked the object, exit the monitor. We // intentionally do not use CHECK on check_owner because we must exit the // monitor even if an exception was already pending. @@ -740,14 +505,7 @@ int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { } ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK_0); - } else { - // The ObjectMonitor* can't be async deflated because the _waiters - // field is incremented before ownership is dropped and decremented - // after ownership is regained. - monitor = inflate(current, obj(), inflate_cause_wait); - } + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK_0); DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), current, millis); monitor->wait(millis, true, THREAD); // Not CHECK as we need following code @@ -766,11 +524,7 @@ void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { } ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK); - } else { - monitor = inflate(THREAD, obj(), inflate_cause_wait); - } + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK); monitor->wait(millis, false, THREAD); } @@ -779,26 +533,11 @@ void ObjectSynchronizer::notify(Handle obj, TRAPS) { JavaThread* current = THREAD; markWord mark = obj->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { - // Not inflated so there can't be any waiters to notify. - return; - } - } else if (LockingMode == LM_LEGACY) { - if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) { - // Not inflated so there can't be any waiters to notify. - return; - } - } - - ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); - } else { - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - monitor = inflate(current, obj(), inflate_cause_notify); + if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { + // Not inflated so there can't be any waiters to notify. + return; } + ObjectMonitor* monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); monitor->notify(CHECK); } @@ -807,26 +546,12 @@ void ObjectSynchronizer::notifyall(Handle obj, TRAPS) { JavaThread* current = THREAD; markWord mark = obj->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { - // Not inflated so there can't be any waiters to notify. - return; - } - } else if (LockingMode == LM_LEGACY) { - if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) { - // Not inflated so there can't be any waiters to notify. - return; - } + if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { + // Not inflated so there can't be any waiters to notify. + return; } - ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); - } else { - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - monitor = inflate(current, obj(), inflate_cause_notify); - } + ObjectMonitor* monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); monitor->notifyAll(CHECK); } @@ -846,67 +571,6 @@ struct SharedGlobals { static SharedGlobals GVars; -static markWord read_stable_mark(oop obj) { - markWord mark = obj->mark_acquire(); - if (!mark.is_being_inflated() || LockingMode == LM_LIGHTWEIGHT) { - // New lightweight locking does not use the markWord::INFLATING() protocol. - return mark; // normal fast-path return - } - - int its = 0; - for (;;) { - markWord mark = obj->mark_acquire(); - if (!mark.is_being_inflated()) { - return mark; // normal fast-path return - } - - // The object is being inflated by some other thread. - // The caller of read_stable_mark() must wait for inflation to complete. - // Avoid live-lock. - - ++its; - if (its > 10000 || !os::is_MP()) { - if (its & 1) { - os::naked_yield(); - } else { - // Note that the following code attenuates the livelock problem but is not - // a complete remedy. A more complete solution would require that the inflating - // thread hold the associated inflation lock. The following code simply restricts - // the number of spinners to at most one. We'll have N-2 threads blocked - // on the inflationlock, 1 thread holding the inflation lock and using - // a yield/park strategy, and 1 thread in the midst of inflation. - // A more refined approach would be to change the encoding of INFLATING - // to allow encapsulation of a native thread pointer. Threads waiting for - // inflation to complete would use CAS to push themselves onto a singly linked - // list rooted at the markword. Once enqueued, they'd loop, checking a per-thread flag - // and calling park(). When inflation was complete the thread that accomplished inflation - // would detach the list and set the markword to inflated with a single CAS and - // then for each thread on the list, set the flag and unpark() the thread. - - // Index into the lock array based on the current object address. - static_assert(is_power_of_2(inflation_lock_count()), "must be"); - size_t ix = (cast_from_oop(obj) >> 5) & (inflation_lock_count() - 1); - int YieldThenBlock = 0; - assert(ix < inflation_lock_count(), "invariant"); - inflation_lock(ix)->lock(); - while (obj->mark_acquire() == markWord::INFLATING()) { - // Beware: naked_yield() is advisory and has almost no effect on some platforms - // so we periodically call current->_ParkEvent->park(1). - // We use a mixed spin/yield/block mechanism. - if ((YieldThenBlock++) >= 16) { - Thread::current()->_ParkEvent->park(1); - } else { - os::naked_yield(); - } - } - inflation_lock(ix)->unlock(); - } - } else { - SpinPause(); // SMP-polite spinning - } - } -} - // hashCode() generation : // // Possibilities: @@ -965,7 +629,7 @@ static intptr_t get_next_hash(Thread* current, oop obj) { } static intptr_t install_hash_code(Thread* current, oop obj) { - assert(UseObjectMonitorTable && LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(UseObjectMonitorTable, "must be"); markWord mark = obj->mark_acquire(); for (;;) { @@ -996,12 +660,8 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { ObjectMonitor* monitor = nullptr; markWord temp, test; intptr_t hash; - markWord mark = read_stable_mark(obj); - if (VerifyHeavyMonitors) { - assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)"); - guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); - } - if (mark.is_unlocked() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) { + markWord mark = obj->mark_acquire(); + if (mark.is_unlocked() || mark.is_fast_locked()) { hash = mark.hash(); if (hash != 0) { // if it has a hash, just return it return hash; @@ -1013,10 +673,9 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { if (test == mark) { // if the hash was installed, return it return hash; } - if (LockingMode == LM_LIGHTWEIGHT) { - // CAS failed, retry - continue; - } + // CAS failed, retry + continue; + // Failed to install the hash. It could be that another thread // installed the hash just before our attempt or inflation has // occurred or... so we fall thru to inflate the monitor for @@ -1048,34 +707,14 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { } // Fall thru so we only have one place that installs the hash in // the ObjectMonitor. - } else if (LockingMode == LM_LEGACY && mark.has_locker() - && current->is_Java_thread() - && JavaThread::cast(current)->is_lock_owned((address)mark.locker())) { - // This is a stack-lock owned by the calling thread so fetch the - // displaced markWord from the BasicLock on the stack. - temp = mark.displaced_mark_helper(); - assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value()); - hash = temp.hash(); - if (hash != 0) { // if it has a hash, just return it - return hash; - } - // WARNING: - // The displaced header in the BasicLock on a thread's stack - // is strictly immutable. It CANNOT be changed in ANY cases. - // So we have to inflate the stack-lock into an ObjectMonitor - // even if the current thread owns the lock. The BasicLock on - // a thread's stack can be asynchronously read by other threads - // during an inflate() call so any change to that stack memory - // may not propagate to other threads correctly. } - // Inflate the monitor to set the hash. - - // There's no need to inflate if the mark has already got a monitor. // NOTE: an async deflation can race after we get the monitor and // before we can update the ObjectMonitor's header with the hash // value below. - monitor = mark.has_monitor() ? mark.monitor() : inflate(current, obj, inflate_cause_hash_code); + assert(mark.has_monitor(), "must be"); + monitor = mark.monitor(); + // Load ObjectMonitor's header/dmw field and see if it has a hash. mark = monitor->header(); assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); @@ -1115,19 +754,14 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, assert(current == JavaThread::current(), "Can only be called on current thread"); oop obj = h_obj(); - markWord mark = read_stable_mark(obj); + markWord mark = obj->mark_acquire(); - if (LockingMode == LM_LEGACY && mark.has_locker()) { - // stack-locked case, header points into owner's stack - return current->is_lock_owned((address)mark.locker()); - } - - if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) { + if (mark.is_fast_locked()) { // fast-locking case, see if lock is in current's lock stack return current->lock_stack().contains(h_obj()); } - while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + while (mark.has_monitor()) { ObjectMonitor* monitor = read_monitor(current, obj, mark); if (monitor != nullptr) { return monitor->is_entered(current) != 0; @@ -1141,13 +775,6 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, } } - if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { - // Inflated monitor so header points to ObjectMonitor (tagged pointer). - // The first stage of async deflation does not affect any field - // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = read_monitor(mark); - return monitor->is_entered(current) != 0; - } // Unlocked case, header in place assert(mark.is_unlocked(), "sanity check"); return false; @@ -1155,21 +782,15 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_obj) { oop obj = h_obj(); - markWord mark = read_stable_mark(obj); + markWord mark = obj->mark_acquire(); - if (LockingMode == LM_LEGACY && mark.has_locker()) { - // stack-locked so header points into owner's stack. - // owning_thread_from_monitor_owner() may also return null here: - return Threads::owning_thread_from_stacklock(t_list, (address) mark.locker()); - } - - if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) { + if (mark.is_fast_locked()) { // fast-locked so get owner from the object. // owning_thread_from_object() may also return null here: return Threads::owning_thread_from_object(t_list, h_obj()); } - while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + while (mark.has_monitor()) { ObjectMonitor* monitor = read_monitor(Thread::current(), obj, mark); if (monitor != nullptr) { return Threads::owning_thread_from_monitor(t_list, monitor); @@ -1183,16 +804,6 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob } } - if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { - // Inflated monitor so header points to ObjectMonitor (tagged pointer). - // The first stage of async deflation does not affect any field - // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = read_monitor(mark); - assert(monitor != nullptr, "monitor should be non-null"); - // owning_thread_from_monitor() may also return null here: - return Threads::owning_thread_from_monitor(t_list, monitor); - } - // Unlocked case, header in place // Cannot have assertion since this object may have been // locked by another thread when reaching here. @@ -1415,230 +1026,6 @@ jlong ObjectSynchronizer::time_since_last_async_deflation_ms() { return (os::javaTimeNanos() - last_async_deflation_time_ns()) / (NANOUNITS / MILLIUNITS); } -static void post_monitor_inflate_event(EventJavaMonitorInflate* event, - const oop obj, - ObjectSynchronizer::InflateCause cause) { - assert(event != nullptr, "invariant"); - const Klass* monitor_klass = obj->klass(); - if (ObjectMonitor::is_jfr_excluded(monitor_klass)) { - return; - } - event->set_monitorClass(monitor_klass); - event->set_address((uintptr_t)(void*)obj); - event->set_cause((u1)cause); - event->commit(); -} - -// Fast path code shared by multiple functions -void ObjectSynchronizer::inflate_helper(oop obj) { - assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); - markWord mark = obj->mark_acquire(); - if (mark.has_monitor()) { - ObjectMonitor* monitor = read_monitor(mark); - markWord dmw = monitor->header(); - assert(dmw.is_neutral(), "sanity check: header=" INTPTR_FORMAT, dmw.value()); - return; - } - (void)inflate(Thread::current(), obj, inflate_cause_vm_internal); -} - -ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) { - assert(current == Thread::current(), "must be"); - assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); - return inflate_impl(current->is_Java_thread() ? JavaThread::cast(current) : nullptr, obj, cause); -} - -ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) { - assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be"); - assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for"); - return inflate_impl(thread, obj, cause); -} - -ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* locking_thread, oop object, const InflateCause cause) { - // The JavaThread* locking_thread requires that the locking_thread == Thread::current() or - // is suspended throughout the call by some other mechanism. - // The thread might be nullptr when called from a non JavaThread. (As may still be - // the case from FastHashCode). However it is only important for correctness that the - // thread is set when called from ObjectSynchronizer::enter from the owning thread, - // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. - assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl"); - EventJavaMonitorInflate event; - - for (;;) { - const markWord mark = object->mark_acquire(); - - // The mark can be in one of the following states: - // * inflated - If the ObjectMonitor owner is anonymous and the - // locking_thread owns the object lock, then we - // make the locking_thread the ObjectMonitor owner. - // * stack-locked - Coerce it to inflated from stack-locked. - // * INFLATING - Busy wait for conversion from stack-locked to - // inflated. - // * unlocked - Aggressively inflate the object. - - // CASE: inflated - if (mark.has_monitor()) { - ObjectMonitor* inf = mark.monitor(); - markWord dmw = inf->header(); - assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - if (inf->has_anonymous_owner() && locking_thread != nullptr) { - assert(LockingMode == LM_LEGACY, "invariant"); - if (locking_thread->is_lock_owned((address)inf->stack_locker())) { - inf->set_stack_locker(nullptr); - inf->set_owner_from_anonymous(locking_thread); - } - } - return inf; - } - - // CASE: inflation in progress - inflating over a stack-lock. - // Some other thread is converting from stack-locked to inflated. - // Only that thread can complete inflation -- other threads must wait. - // The INFLATING value is transient. - // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. - // We could always eliminate polling by parking the thread on some auxiliary list. - if (mark == markWord::INFLATING()) { - read_stable_mark(object); - continue; - } - - // CASE: stack-locked - // Could be stack-locked either by current or by some other thread. - // - // Note that we allocate the ObjectMonitor speculatively, _before_ attempting - // to install INFLATING into the mark word. We originally installed INFLATING, - // allocated the ObjectMonitor, and then finally STed the address of the - // ObjectMonitor into the mark. This was correct, but artificially lengthened - // the interval in which INFLATING appeared in the mark, thus increasing - // the odds of inflation contention. If we lose the race to set INFLATING, - // then we just delete the ObjectMonitor and loop around again. - // - LogStreamHandle(Trace, monitorinflation) lsh; - if (LockingMode == LM_LEGACY && mark.has_locker()) { - ObjectMonitor* m = new ObjectMonitor(object); - // Optimistically prepare the ObjectMonitor - anticipate successful CAS - // We do this before the CAS in order to minimize the length of time - // in which INFLATING appears in the mark. - - markWord cmp = object->cas_set_mark(markWord::INFLATING(), mark); - if (cmp != mark) { - delete m; - continue; // Interference -- just retry - } - - // We've successfully installed INFLATING (0) into the mark-word. - // This is the only case where 0 will appear in a mark-word. - // Only the singular thread that successfully swings the mark-word - // to 0 can perform (or more precisely, complete) inflation. - // - // Why do we CAS a 0 into the mark-word instead of just CASing the - // mark-word from the stack-locked value directly to the new inflated state? - // Consider what happens when a thread unlocks a stack-locked object. - // It attempts to use CAS to swing the displaced header value from the - // on-stack BasicLock back into the object header. Recall also that the - // header value (hash code, etc) can reside in (a) the object header, or - // (b) a displaced header associated with the stack-lock, or (c) a displaced - // header in an ObjectMonitor. The inflate() routine must copy the header - // value from the BasicLock on the owner's stack to the ObjectMonitor, all - // the while preserving the hashCode stability invariants. If the owner - // decides to release the lock while the value is 0, the unlock will fail - // and control will eventually pass from slow_exit() to inflate. The owner - // will then spin, waiting for the 0 value to disappear. Put another way, - // the 0 causes the owner to stall if the owner happens to try to - // drop the lock (restoring the header from the BasicLock to the object) - // while inflation is in-progress. This protocol avoids races that might - // would otherwise permit hashCode values to change or "flicker" for an object. - // Critically, while object->mark is 0 mark.displaced_mark_helper() is stable. - // 0 serves as a "BUSY" inflate-in-progress indicator. - - - // fetch the displaced mark from the owner's stack. - // The owner can't die or unwind past the lock while our INFLATING - // object is in the mark. Furthermore the owner can't complete - // an unlock on the object, either. - markWord dmw = mark.displaced_mark_helper(); - // Catch if the object's header is not neutral (not locked and - // not marked is what we care about here). - assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - - // Setup monitor fields to proper values -- prepare the monitor - m->set_header(dmw); - - // Note that a thread can inflate an object - // that it has stack-locked -- as might happen in wait() -- directly - // with CAS. That is, we can avoid the xchg-nullptr .... ST idiom. - if (locking_thread != nullptr && locking_thread->is_lock_owned((address)mark.locker())) { - m->set_owner(locking_thread); - } else { - // Use ANONYMOUS_OWNER to indicate that the owner is the BasicLock on the stack, - // and set the stack locker field in the monitor. - m->set_stack_locker(mark.locker()); - m->set_anonymous_owner(); - } - // TODO-FIXME: assert BasicLock->dhw != 0. - - // Must preserve store ordering. The monitor state must - // be stable at the time of publishing the monitor address. - guarantee(object->mark() == markWord::INFLATING(), "invariant"); - // Release semantics so that above set_object() is seen first. - object->release_set_mark(markWord::encode(m)); - - // Once ObjectMonitor is configured and the object is associated - // with the ObjectMonitor, it is safe to allow async deflation: - _in_use_list.add(m); - - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", type='%s'", p2i(object), - object->mark().value(), object->klass()->external_name()); - } - if (event.should_commit()) { - post_monitor_inflate_event(&event, object, cause); - } - return m; - } - - // CASE: unlocked - // TODO-FIXME: for entry we currently inflate and then try to CAS _owner. - // If we know we're inflating for entry it's better to inflate by swinging a - // pre-locked ObjectMonitor pointer into the object header. A successful - // CAS inflates the object *and* confers ownership to the inflating thread. - // In the current implementation we use a 2-step mechanism where we CAS() - // to inflate and then CAS() again to try to swing _owner from null to current. - // An inflateTry() method that we could call from enter() would be useful. - - assert(mark.is_unlocked(), "invariant: header=" INTPTR_FORMAT, mark.value()); - ObjectMonitor* m = new ObjectMonitor(object); - // prepare m for installation - set monitor to initial state - m->set_header(mark); - - if (object->cas_set_mark(markWord::encode(m), mark) != mark) { - delete m; - m = nullptr; - continue; - // interference - the markword changed - just retry. - // The state-transitions are one-way, so there's no chance of - // live-lock -- "Inflated" is an absorbing state. - } - - // Once the ObjectMonitor is configured and object is associated - // with the ObjectMonitor, it is safe to allow async deflation: - _in_use_list.add(m); - - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - lsh.print_cr("inflate(unlocked): object=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", type='%s'", p2i(object), - object->mark().value(), object->klass()->external_name()); - } - if (event.should_commit()) { - post_monitor_inflate_event(&event, object, cause); - } - return m; - } -} - // Walk the in-use list and deflate (at most MonitorDeflationMax) idle // ObjectMonitors. Returns the number of deflated ObjectMonitors. // @@ -1914,7 +1301,6 @@ const char* ObjectSynchronizer::inflate_cause_name(const InflateCause cause) { case inflate_cause_monitor_enter: return "Monitor Enter"; case inflate_cause_wait: return "Monitor Wait"; case inflate_cause_notify: return "Monitor Notify"; - case inflate_cause_hash_code: return "Monitor Hash Code"; case inflate_cause_jni_enter: return "JNI Monitor Enter"; case inflate_cause_jni_exit: return "JNI Monitor Exit"; default: diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index e35c3651f5b..419cf2bf5bb 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,16 +73,15 @@ class ObjectSynchronizer : AllStatic { friend class ObjectMonitorDeflationLogging; friend class WhiteBox; - public: +public: typedef enum { inflate_cause_vm_internal = 0, inflate_cause_monitor_enter = 1, inflate_cause_wait = 2, inflate_cause_notify = 3, - inflate_cause_hash_code = 4, - inflate_cause_jni_enter = 5, - inflate_cause_jni_exit = 6, - inflate_cause_nof = 7 // Number of causes + inflate_cause_jni_enter = 4, + inflate_cause_jni_exit = 5, + inflate_cause_nof = 6 // Number of causes } InflateCause; typedef enum { @@ -104,15 +103,7 @@ class ObjectSynchronizer : AllStatic { // locked on is either already locked by the locking_thread or cannot // escape the locking_thread. static void enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread); -private: - // Shared implementation for enter and enter_for. Performs all but - // inflated monitor enter. - static bool enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread); - static bool quick_enter_legacy(oop obj, BasicLock* Lock, JavaThread* current); - static void enter_legacy(Handle obj, BasicLock* Lock, JavaThread* current); - static void exit_legacy(oop obj, BasicLock* lock, JavaThread* current); -public: // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. static void jni_enter(Handle obj, JavaThread* current); @@ -131,18 +122,7 @@ public: // 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. - static ObjectMonitor* inflate_for(JavaThread* thread, oop obj, const InflateCause cause); - -private: - // Shared implementation between the different LockingMode. - static ObjectMonitor* inflate_impl(JavaThread* locking_thread, oop obj, const InflateCause cause); - public: - // This version is only for internal use - static void inflate_helper(oop obj); static const char* inflate_cause_name(const InflateCause cause); inline static ObjectMonitor* read_monitor(markWord mark); diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp index ac9116088f7..a44fe817276 100644 --- a/src/hotspot/share/runtime/synchronizer.inline.hpp +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * 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,11 +45,7 @@ inline ObjectMonitor* ObjectSynchronizer::read_monitor(Thread* current, oop obj, inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { assert(current == Thread::current(), "must be"); - if (LockingMode == LM_LIGHTWEIGHT) { LightweightSynchronizer::enter(obj, lock, current); - } else { - enter_legacy(obj, lock, current); - } } inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { @@ -61,21 +57,13 @@ inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread return false; } - if (LockingMode == LM_LIGHTWEIGHT) { - return LightweightSynchronizer::quick_enter(obj, lock, current); - } else { - return quick_enter_legacy(obj, lock, current); - } + return LightweightSynchronizer::quick_enter(obj, lock, current); } inline void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { current->dec_held_monitor_count(); - if (LockingMode == LM_LIGHTWEIGHT) { - LightweightSynchronizer::exit(object, lock, current); - } else { - exit_legacy(object, lock, current); - } + LightweightSynchronizer::exit(object, lock, current); } #endif // SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 3cf1058b6f7..65eea9d5fb2 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1294,21 +1294,7 @@ GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, } #endif // INCLUDE_JVMTI -JavaThread *Threads::owning_thread_from_stacklock(ThreadsList * t_list, address basicLock) { - assert(LockingMode == LM_LEGACY, "Not with new lightweight locking"); - - JavaThread* the_owner = nullptr; - for (JavaThread* q : *t_list) { - if (q->is_lock_owned(basicLock)) { - the_owner = q; - break; - } - } - return the_owner; -} - JavaThread* Threads::owning_thread_from_object(ThreadsList * t_list, oop obj) { - assert(LockingMode == LM_LIGHTWEIGHT, "Only with new lightweight locking"); for (JavaThread* q : *t_list) { // Need to start processing before accessing oops in the thread. StackWatermark* watermark = StackWatermarkSet::get(q, StackWatermarkKind::gc); @@ -1325,12 +1311,7 @@ JavaThread* Threads::owning_thread_from_object(ThreadsList * t_list, oop obj) { JavaThread* Threads::owning_thread_from_monitor(ThreadsList* t_list, ObjectMonitor* monitor) { if (monitor->has_anonymous_owner()) { - if (LockingMode == LM_LIGHTWEIGHT) { - return owning_thread_from_object(t_list, monitor->object()); - } else { - assert(LockingMode == LM_LEGACY, "invariant"); - return owning_thread_from_stacklock(t_list, (address)monitor->stack_locker()); - } + return owning_thread_from_object(t_list, monitor->object()); } else { JavaThread* the_owner = nullptr; for (JavaThread* q : *t_list) { diff --git a/src/hotspot/share/runtime/threads.hpp b/src/hotspot/share/runtime/threads.hpp index 979b1dffe26..c6428c874f6 100644 --- a/src/hotspot/share/runtime/threads.hpp +++ b/src/hotspot/share/runtime/threads.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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. * @@ -134,9 +134,6 @@ public: static GrowableArray* get_pending_threads(ThreadsList * t_list, int count, address monitor); - // Get owning Java thread from the basicLock address. - static JavaThread *owning_thread_from_stacklock(ThreadsList * t_list, address basicLock); - static JavaThread* owning_thread_from_object(ThreadsList* t_list, oop obj); static JavaThread* owning_thread_from_monitor(ThreadsList* t_list, ObjectMonitor* owner); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 1fba55cde99..bc026887b84 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -673,7 +673,6 @@ volatile_nonstatic_field(ObjectMonitor, _metadata, uintptr_t) \ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _owner, int64_t) \ - volatile_nonstatic_field(ObjectMonitor, _stack_locker, BasicLock*) \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ nonstatic_field(ObjectMonitor, _contentions, int) \ @@ -1640,14 +1639,6 @@ declare_constant(T_NARROWKLASS_size) \ declare_constant(T_VOID_size) \ \ - /**********************************************/ \ - /* LockingMode enum (globalDefinitions.hpp) */ \ - /**********************************************/ \ - \ - declare_constant(LM_MONITOR) \ - declare_constant(LM_LEGACY) \ - declare_constant(LM_LIGHTWEIGHT) \ - \ /*********************************************/ \ /* MethodCompilation (globalDefinitions.hpp) */ \ /*********************************************/ \ diff --git a/src/hotspot/share/utilities/globalDefinitions.cpp b/src/hotspot/share/utilities/globalDefinitions.cpp index 84a0730212f..8a111a12607 100644 --- a/src/hotspot/share/utilities/globalDefinitions.cpp +++ b/src/hotspot/share/utilities/globalDefinitions.cpp @@ -56,8 +56,6 @@ int LogMinObjAlignmentInBytes = -1; // Oop encoding heap max uint64_t OopEncodingHeapMax = 0; -const int LockingMode = LM_LIGHTWEIGHT; - // Something to help porters sleep at night #ifdef ASSERT diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 64ccae539a3..8217451a5c6 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1004,17 +1004,6 @@ enum JavaThreadState { _thread_max_state = 12 // maximum thread state+1 - used for statistics allocation }; -enum LockingMode { - // Use only heavy monitors for locking - LM_MONITOR = 0, - // Legacy stack-locking, with monitors as 2nd tier - LM_LEGACY = 1, - // New lightweight locking, with monitors as 2nd tier - LM_LIGHTWEIGHT = 2 -}; - -extern const int LockingMode; - //---------------------------------------------------------------------------------------------------- // Special constants for debugging diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index a4d44a96878..81e357f1c4f 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1078,7 +1078,7 @@ void VMError::report(outputStream* st, bool _verbose) { print_stack_location(st, _context, continuation); st->cr(); - STEP_IF("printing lock stack", _verbose && _thread != nullptr && _thread->is_Java_thread() && LockingMode == LM_LIGHTWEIGHT); + STEP_IF("printing lock stack", _verbose && _thread != nullptr && _thread->is_Java_thread()); st->print_cr("Lock stack of current Java thread (top to bottom):"); JavaThread::cast(_thread)->lock_stack().print_on(st); st->cr(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java index 25c5344506c..1bdbf8ce8a2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +51,6 @@ public class ObjectMonitor extends VMObject { objectFieldOffset = f.getOffset(); f = type.getField("_owner"); ownerFieldOffset = f.getOffset(); - f = type.getField("_stack_locker"); - stackLockerFieldOffset = f.getOffset(); f = type.getField("_next_om"); nextOMFieldOffset = f.getOffset(); contentionsField = new CIntField(type.getCIntegerField("_contentions"), 0); @@ -89,7 +87,6 @@ public class ObjectMonitor extends VMObject { } public Address owner() { return addr.getAddressAt(ownerFieldOffset); } - public Address stackLocker() { return addr.getAddressAt(stackLockerFieldOffset); } // FIXME // void set_owner(void* owner); @@ -120,7 +117,6 @@ public class ObjectMonitor extends VMObject { private static long metadataFieldOffset; private static long objectFieldOffset; private static long ownerFieldOffset; - private static long stackLockerFieldOffset; private static long nextOMFieldOffset; private static CIntField contentionsField; private static CIntField waitersField; diff --git a/test/hotspot/gtest/runtime/test_lockStack.cpp b/test/hotspot/gtest/runtime/test_lockStack.cpp index 3163898e17d..6755541adb0 100644 --- a/test/hotspot/gtest/runtime/test_lockStack.cpp +++ b/test/hotspot/gtest/runtime/test_lockStack.cpp @@ -63,7 +63,7 @@ public: } while (false) TEST_VM_F(LockStackTest, is_recursive) { - if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) { + if (!VM_Version::supports_recursive_lightweight_locking()) { return; } @@ -130,7 +130,7 @@ TEST_VM_F(LockStackTest, is_recursive) { } TEST_VM_F(LockStackTest, try_recursive_enter) { - if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) { + if (!VM_Version::supports_recursive_lightweight_locking()) { return; } @@ -197,10 +197,6 @@ TEST_VM_F(LockStackTest, try_recursive_enter) { } TEST_VM_F(LockStackTest, contains) { - if (LockingMode != LM_LIGHTWEIGHT) { - return; - } - const bool test_recursive = VM_Version::supports_recursive_lightweight_locking(); JavaThread* THREAD = JavaThread::current(); @@ -263,10 +259,6 @@ TEST_VM_F(LockStackTest, contains) { } TEST_VM_F(LockStackTest, remove) { - if (LockingMode != LM_LIGHTWEIGHT) { - return; - } - const bool test_recursive = VM_Version::supports_recursive_lightweight_locking(); JavaThread* THREAD = JavaThread::current(); diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java index e92e947ecfa..505d5cc7df7 100644 --- a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -53,9 +53,6 @@ public class TestRecursiveMonitorChurn { public static volatile Monitor monitor; public static void main(String[] args) { - if (WB.getBooleanVMFlag("VerifyHeavyMonitors")) { - throw new SkippedException("VerifyHeavyMonitors 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++) { From 03c54d4288dfd70190c3f306a44a8424f268f787 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 12:26:58 +0000 Subject: [PATCH 173/295] 8365689: Elements.getFileObjectOf fails with a NullPointerException when an erroneous Element is passed in Reviewed-by: darcy, vromero --- .../sun/tools/javac/model/JavacElements.java | 3 +- .../model/element/TestFileObjectOf.java | 159 +++++++++++++++++- 2 files changed, 159 insertions(+), 3 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index 73219ca38ae..c9bb6cf4182 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -800,6 +800,7 @@ public class JavacElements implements Elements { yield msym.module_info.classfile; } case TYP -> ((ClassSymbol) sym).classfile; + case ERR -> null; default -> sym.enclClass().classfile; }; } diff --git a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java index ad7c701fa5e..4f9703bc428 100644 --- a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java +++ b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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 8224922 + * @bug 8224922 8365689 * @summary Verify the behavior of the Elements.getFileObjectOf * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -33,6 +33,8 @@ * @run main TestFileObjectOf */ +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; import java.nio.file.Path; @@ -49,6 +51,7 @@ import javax.lang.model.util.Elements; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; import toolbox.JarTask; import toolbox.JavacTask; @@ -592,4 +595,156 @@ public class TestFileObjectOf extends TestRunner { } + @Test //JDK-8365689 + public void testUndefined(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + module m { + requires undefined1; //as module + exports undefined2; //as package + exports test; + } + """, + """ + package test; + public class TestClass { + void t() { + undefined3.call(); + this.undefined4(); + } + } + """); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + //from source, implicit: + { + List log; + + log = new JavacTask(tb) + .options("-XDshould-stop.at=FLOW", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UndefinedPrintFiles.class.getName(), + "-sourcepath", src.toString()) + .outdir(classes) + .classes("java.lang.Object") + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "undefined1: " + "", + "undefined2: " + "", + "undefined3: " + "", + "undefined4: " + "" + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + tb.cleanDirectory(classes); + + //from source, explicit: + { + List log; + + log = new JavacTask(tb) + .options("-XDshould-stop.at=FLOW", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UndefinedPrintFiles.class.getName()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "undefined1: " + "", + "undefined2: " + "", + "undefined3: " + "", + "undefined4: " + "" + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("fromClass") + public static final class UndefinedPrintFiles extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) + return false; + + Elements elements = processingEnv.getElementUtils(); + Trees trees = Trees.instance(processingEnv); + + Queue q = new ArrayDeque<>(); + q.add(elements.getModuleElement("m")); + + while (!q.isEmpty()) { + Element currentElement = q.remove(); + + switch (currentElement.getKind()) { + case MODULE -> { + ElementFilter.exportsIn(((ModuleElement) currentElement).getDirectives()) + .stream() + .map(ed -> ed.getPackage()) + .forEach(q::add); + } + case PACKAGE -> { + currentElement.getEnclosedElements() + .stream() + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) + .forEach(q::add); + continue; + } + default -> {} + } + + TreePath tp = trees.getPath(currentElement); + + new TreePathScanner<>() { + @Override + public Object visitIdentifier(IdentifierTree node, Object p) { + if (node.getName().toString().startsWith("undefined")) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + } + return super.visitIdentifier(node, p); + } + + @Override + public Object visitMemberSelect(MemberSelectTree node, Object p) { + if (node.getIdentifier().toString().startsWith("undefined")) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + } + return super.visitMemberSelect(node, p); + } + }.scan(tp, null); + } + + return false; + } + + void handleDeclaration(Element el) { + Elements elements = processingEnv.getElementUtils(); + JavaFileObject fileObjects = elements.getFileObjectOf(el); + System.out.println(el.getSimpleName() + ": " + (fileObjects != null ? fileObjects.toUri().toString() : "")); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + } } From bcff857ba09028cc43e856726b5c839cc6b1b0d9 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Mon, 8 Sep 2025 13:30:45 +0000 Subject: [PATCH 174/295] 8361381: GlyphLayout behavior differs on JDK 11+ compared to JDK 8 Reviewed-by: prr, serb --- .../sun/font/ExtendedTextSourceLabel.java | 10 +- .../GlyphVector/GetGlyphCharIndexTest.java | 19 ++- .../LineBreakMeasurer/KhmerLineBreakTest.java | 115 ++++++++++++++++++ 3 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java index 433d1d5413f..784035f4fe2 100644 --- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java @@ -577,6 +577,7 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La * not all do, and it cannot be relied upon. * - each glyph maps to a single character, when multiple glyphs exist for a character they all map to it, but * no two characters map to the same glyph +* This was only true for the old, ICU layout engine which inserted 0xffff glyphs for ligaturized characters! * - multiple glyphs mapping to the same character need not be in sequence (thai, tamil have split characters) * - glyphs may be arbitrarily reordered (Indic reorders glyphs) * - all glyphs share the same bidi level @@ -712,8 +713,6 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La while (gx != gxlimit) { // start of new cluster - int clusterExtraGlyphs = 0; - minIndex = indices[gx]; maxIndex = minIndex; @@ -730,14 +729,11 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La while (gx != gxlimit && ((glyphinfo[gp + advx] == 0) || - (indices[gx] <= maxIndex) || - (maxIndex - minIndex > clusterExtraGlyphs))) { + (indices[gx] <= maxIndex))) { - ++clusterExtraGlyphs; // have an extra glyph in this cluster if (DEBUG) { System.err.println("gp=" +gp +" adv=" + glyphinfo[gp + advx] + - " gx="+ gx+ " i[gx]="+indices[gx] + - " clusterExtraGlyphs="+clusterExtraGlyphs); + " gx="+ gx+ " i[gx]="+indices[gx]); } // adjust advance only if new glyph has non-zero advance diff --git a/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java b/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java index 6ec6a257ae8..939643c7a45 100644 --- a/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java +++ b/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java @@ -23,7 +23,7 @@ /* @test * @summary Test getGlyphCharIndex() results from layout - * @bug 8152680 + * @bug 8152680 8361381 */ import java.awt.Font; @@ -40,5 +40,22 @@ public class GetGlyphCharIndexTest { if (idx0 != 0) { throw new RuntimeException("Expected 0, got " + idx0); } + + // This is the encoding-independent Khmer string "បានស្នើសុំនៅតែត្រូវបានបដិសេធ" + // We can't check for more details like e.g. correct line breaking because it is font and platform dependent, + // but we can at least chack that the created GlyphVector has monotonically increasing character indices. + // This is guaranteed by HarfBuzz's HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS cluster level which is used + // in the OpenJDK layout implementation. + String khmer = "\u1794\u17b6\u1793\u179f\u17d2\u1793\u17be\u179f\u17bb\u17c6\u1793\u17c5" + + "\u178f\u17c2\u178f\u17d2\u179a\u17bc\u179c\u1794\u17b6\u1793\u1794\u178a\u17b7\u179f\u17c1\u1792"; + font = new Font(Font.DIALOG, Font.PLAIN, 12); + gv = font.layoutGlyphVector(frc, khmer.toCharArray(), 0, khmer.length(), 0); + int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + for (int i = 0; i < (indices.length - 1); i++) { + if (indices[i] > indices[i + 1]) { + throw new RuntimeException("Glyph character indices are supposed to be monotonically growing, but character index at position " + + i + " is bigger then the one at position " + (i + 1) + ", i.e. " + indices[i] + " > " + indices[i + 1] + "."); + } + } } } diff --git a/test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java b/test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java new file mode 100644 index 00000000000..855ad1b320b --- /dev/null +++ b/test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java @@ -0,0 +1,115 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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 8361381 + * @summary GlyphLayout behavior differs on JDK 11+ compared to JDK 8 + */ + +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.text.BreakIterator; +import java.util.Locale; + +public class KhmerLineBreakTest { + static String khmer = "បានស្នើសុំនៅតែត្រូវបានបដិសេធ"; + /* + + This is part of the output we get from `ExtendedTextSourceLabel::createCharinfo()` + when running with `-Dsun.java2d.debugfonts=true`. It's a listing of the 28 code points + of the `khmer` string defined above and displays their x-position during rendering as + well as their advance. Code points with zero advance belong to the glyph cluster which + is started by the first preceding code point with a non-zero advance. There should be no + breaks at characters with zero advance, because this would break a glyph cluster. + + 0 ch: 1794 x: 0.0 xa: 68.115234 + 1 ch: 17b6 x: 68.115234 xa: 0.0 + 2 ch: 1793 x: 68.115234 xa: 45.410156 + 3 ch: 179f x: 113.52539 xa: 90.82031 + 4 ch: 17d2 x: 204.3457 xa: 0.0 + 5 ch: 1793 x: 204.3457 xa: 0.0 + 6 ch: 17be x: 204.3457 xa: 0.0 + 7 ch: 179f x: 204.3457 xa: 68.115234 + 8 ch: 17bb x: 272.46094 xa: 0.0 + 9 ch: 17c6 x: 272.46094 xa: 0.0 + 10 ch: 1793 x: 272.46094 xa: 90.82031 + 11 ch: 17c5 x: 363.28125 xa: 0.0 + 12 ch: 178f x: 363.28125 xa: 68.115234 + 13 ch: 17c2 x: 431.39648 xa: 0.0 + 14 ch: 178f x: 431.39648 xa: 68.115234 + 15 ch: 17d2 x: 499.51172 xa: 0.0 + 16 ch: 179a x: 499.51172 xa: 0.0 + 17 ch: 17bc x: 499.51172 xa: 0.0 + 18 ch: 179c x: 499.51172 xa: 22.705078 + 19 ch: 1794 x: 522.2168 xa: 68.115234 + 20 ch: 17b6 x: 590.33203 xa: 0.0 + 21 ch: 1793 x: 590.33203 xa: 45.410156 + 22 ch: 1794 x: 635.7422 xa: 45.410156 + 23 ch: 178a x: 681.15234 xa: 45.410156 + 24 ch: 17b7 x: 726.5625 xa: 0.0 + 25 ch: 179f x: 726.5625 xa: 90.82031 + 26 ch: 17c1 x: 817.3828 xa: 0.0 + 27 ch: 1792 x: 817.3828 xa: 45.410156 + + */ + static boolean[] possibleBreak = new boolean[] + { true, false, true, true, false, false, false, true, false, false, + true, false, true, false, true, false, false, false, true, true, + false, true, true, true, false, true, false, true, true /* */ }; + static Locale locale = new Locale.Builder().setLanguage("km").setRegion("KH").build(); + static BreakIterator breakIterator = BreakIterator.getLineInstance(locale); + static FontRenderContext frc = new FontRenderContext(null, true, true); + + public static void main(String[] args) { + Font[] allFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (int i=0; i < allFonts.length; i++) { + if (allFonts[i].canDisplayUpTo(khmer) == -1) { + Font font = allFonts[i].deriveFont(Font.PLAIN, 60f); + System.out.println("Trying font: " + font.getFontName()); + AttributedString attrStr = new AttributedString(khmer); + attrStr.addAttribute(TextAttribute.FONT, font); + AttributedCharacterIterator it = attrStr.getIterator(); + for (int width = 200; width < 400; width += 10) { + LineBreakMeasurer measurer = new LineBreakMeasurer(it, breakIterator, frc); + System.out.print(width + " : "); + while (measurer.getPosition() < it.getEndIndex()) { + int nextOffset = measurer.nextOffset(width); + System.out.print(nextOffset + " "); + if (!possibleBreak[nextOffset]) { + System.out.println(); + throw new RuntimeException("Invalid break at offset " + nextOffset + " (width = " + width + " font = " + font.getFontName() + ")"); + } + measurer.setPosition(nextOffset); + } + System.out.println(); + } + System.out.println("OK"); + } + } + } +} From 166ef5e7b1c6d6a9f0f1f29fedb7f65b94f53119 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Mon, 8 Sep 2025 14:37:25 +0000 Subject: [PATCH 175/295] 8366159: SkippedException is treated as a pass for pkcs11/KeyStore, pkcs11/SecretKeyFactory and pkcs11/SecureRandom Reviewed-by: weijun --- .../pkcs11/KeyStore/CertChainRemoval.java | 11 ++-- .../security/pkcs11/KeyStore/ClientAuth.java | 5 +- .../pkcs11/SecretKeyFactory/TestGeneral.java | 51 ++++++++++++------- .../security/pkcs11/SecureRandom/Basic.java | 7 +-- .../SecureRandom/TestDeserialization.java | 12 ++--- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java b/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java index 0158da0da36..31efbccaeab 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,15 +28,17 @@ * @run testng/othervm CertChainRemoval */ import jdk.test.lib.SecurityTools; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; import java.nio.file.Path; -import java.util.*; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.Provider; import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.Enumeration; import jtreg.SkippedException; import org.testng.SkipException; @@ -125,8 +127,7 @@ public class CertChainRemoval extends PKCS11Test { p11ks.load(null, PKCS11KS.passwd); printKeyStore("Initial PKCS11 KeyStore: ", p11ks); } catch (Exception e) { - System.out.println("Skip test, due to " + e); - return; + throw new SkippedException("Skip test, due to " + e, e); } // get the necessary keys from the temp keystore diff --git a/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java b/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java index 1af1258d173..5d50015880d 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +260,7 @@ public class ClientAuth extends PKCS11Test { try { javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding", p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } this.provider = p; diff --git a/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java b/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java index bca594c66bd..e59d0b4a1ca 100644 --- a/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java +++ b/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ * @run main/othervm TestGeneral */ +import jtreg.SkippedException; + import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -57,8 +61,11 @@ public class TestGeneral extends PKCS11Test { try { skf = SecretKeyFactory.getInstance(algorithm, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Not supported, skipping: " + e); - return; + throw new SkippedException("[algorithm: " + algorithm + + ", key: " + key.getAlgorithm() + "]" + + ", provider: " + p.getName() + "]" + + ", expectedTestResult: " + expected + "]" + + "Not supported, skipping: " + e); } try { SecretKey key2 = skf.translateKey(key); @@ -99,21 +106,31 @@ public class TestGeneral extends PKCS11Test { SecretKey bf_128Key = new SecretKeySpec(rawBytes, 0, 16, "Blowfish"); SecretKey cc20Key = new SecretKeySpec(rawBytes, 0, 32, "ChaCha20"); - // fixed key length - test("AES", aes_128Key, p, TestResult.PASS); - test("AES", aes_256Key, p, TestResult.PASS); - test("AES", cc20Key, p, TestResult.FAIL); + List skippedList = new ArrayList<>(); + try { + // fixed key length + test("AES", aes_128Key, p, TestResult.PASS); + test("AES", aes_256Key, p, TestResult.PASS); + test("AES", cc20Key, p, TestResult.FAIL); - test("ChaCha20", aes_128Key, p, TestResult.FAIL); - test("ChaCha20", aes_256Key, p, TestResult.FAIL); - test("ChaCha20", cc20Key, p, TestResult.PASS); + test("ChaCha20", aes_128Key, p, TestResult.FAIL); + test("ChaCha20", aes_256Key, p, TestResult.FAIL); + test("ChaCha20", cc20Key, p, TestResult.PASS); - // variable key length - // Different PKCS11 impls may have different ranges - // of supported key sizes for variable-key-length - // algorithms. - test("Blowfish", aes_128Key, p, TestResult.FAIL); - test("Blowfish", cc20Key, p, TestResult.FAIL); - test("Blowfish", bf_128Key, p, TestResult.PASS); + // variable key length + // Different PKCS11 impls may have different ranges + // of supported key sizes for variable-key-length + // algorithms. + test("Blowfish", aes_128Key, p, TestResult.FAIL); + test("Blowfish", cc20Key, p, TestResult.FAIL); + test("Blowfish", bf_128Key, p, TestResult.PASS); + } catch (SkippedException skippedException){ + skippedException.printStackTrace(); + skippedList.add(skippedException.getMessage()); + } + + if (!skippedList.isEmpty()) { + throw new SkippedException("One or more tests skipped " + skippedList); + } } } diff --git a/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java b/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java index 091b906171c..1b3aed50d7c 100644 --- a/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java +++ b/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @run main/othervm Basic */ +import jtreg.SkippedException; + import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; @@ -44,9 +46,8 @@ public class Basic extends PKCS11Test { try { random = SecureRandom.getInstance("PKCS11"); } catch (NoSuchAlgorithmException e) { - System.out.println("Provider " + p + " does not support SecureRandom, skipping"); e.printStackTrace(); - return; + throw new SkippedException("Provider " + p + " does not support SecureRandom, skipping", e); } byte[] b = new byte[32]; random.nextBytes(b); diff --git a/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java b/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java index f54ae95f36d..b8d37e2a00e 100644 --- a/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java +++ b/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @modules jdk.crypto.cryptoki */ +import jtreg.SkippedException; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -43,18 +45,16 @@ public class TestDeserialization extends PKCS11Test { public void main(Provider p) throws Exception { // Skip this test for providers not found by java.security.Security if (Security.getProvider(p.getName()) != p) { - System.out.println("Skip test for provider " + p.getName()); - return; + throw new SkippedException("Skip test for provider " + p.getName()); } SecureRandom r; try { r = SecureRandom.getInstance("PKCS11", p); System.out.println("SecureRandom instance " + r); } catch (NoSuchAlgorithmException e) { - System.out.println("Provider " + p + - " does not support SecureRandom, skipping"); e.printStackTrace(); - return; + throw new SkippedException("Provider " + p + + " does not support SecureRandom, skipping"); } r.setSeed(System.currentTimeMillis()); byte[] buf = new byte[16]; From 6765a9d775b5bd3d1b36090038060762f976d174 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 8 Sep 2025 15:50:09 +0000 Subject: [PATCH 176/295] 8366908: Use a different class for testing JDK-8351654 Reviewed-by: liach, lmesnik --- test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java b/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java index 214751863ea..33cb881e537 100644 --- a/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java +++ b/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java @@ -39,7 +39,6 @@ */ import java.lang.invoke.MethodHandles; -import java.time.Duration; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassTransform; import java.lang.classfile.MethodTransform; @@ -61,7 +60,7 @@ import java.io.FileNotFoundException; public class TestVerify { - private static final String CLASS_TO_BREAK = "java.time.Duration"; + private static final String CLASS_TO_BREAK = "java.util.Date"; private static final String INTERNAL_CLASS_TO_BREAK = CLASS_TO_BREAK.replace('.', '/'); private static final boolean DEBUG = false; @@ -91,7 +90,7 @@ public class TestVerify { } builder.with(element); }); - var classTransform = ClassTransform.transformingMethods(mm -> mm.methodName().stringValue().equals("getSeconds"), methodTransform); + var classTransform = ClassTransform.transformingMethods(mm -> mm.methodName().equalsString("parse"), methodTransform); byte[] bytes; try { @@ -164,7 +163,7 @@ public class TestVerify { } else { // Load the class instrumented with CFLH for the VerifyError. inst.addTransformer(new BadTransformer()); - System.out.println("1 hour is " + Duration.ofHours(1).getSeconds() + " seconds"); + Class cls = Class.forName(CLASS_TO_BREAK); } throw new RuntimeException("Failed: Did not throw VerifyError"); } catch (VerifyError e) { From ab12fbfda2c364bb16ddf03b923989639f437f6a Mon Sep 17 00:00:00 2001 From: Fabio Romano Date: Mon, 8 Sep 2025 16:10:22 +0000 Subject: [PATCH 177/295] 8077587: BigInteger Roots Reviewed-by: rgiulietti --- .../share/classes/java/math/BigInteger.java | 79 +++++++ .../classes/java/math/MutableBigInteger.java | 200 +++++++++++++++++- .../java/math/BigInteger/BigIntegerTest.java | 157 +++++++++++++- 3 files changed, 433 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 51d935f10c1..21f8598266f 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -2742,6 +2742,85 @@ public class BigInteger extends Number implements Comparable { return new BigInteger[] { sqrtRem[0].toBigInteger(), sqrtRem[1].toBigInteger() }; } + /** + * Returns the integer {@code n}th root of this BigInteger. The integer + * {@code n}th root {@code r} of the corresponding mathematical integer {@code x} + * is defined as follows: + *

          + *
        • if {@code x} ≥ 0, then {@code r} ≥ 0 is the largest integer such that + * {@code r}{@code n} ≤ {@code x}; + *
        • if {@code x} < 0, then {@code r} ≤ 0 is the smallest integer such that + * {@code r}{@code n} ≥ {@code x}. + *
        + * If the root is defined, it is equal to the value of + * {@code x.signum()}⋅ ⌊{@code |nthRoot(x, n)|}⌋, + * where {@code nthRoot(x, n)} denotes the real {@code n}th root of {@code x} + * treated as a real. + * Otherwise, the method throws an {@code ArithmeticException}. + * + *

        Note that the magnitude of the integer {@code n}th root will be less than + * the magnitude of the real {@code n}th root if the latter is not representable + * as an integral value. + * + * @param n the root degree + * @return the integer {@code n}th root of {@code this} + * @throws ArithmeticException if {@code n <= 0}. + * @throws ArithmeticException if {@code n} is even and {@code this} is negative. + * @see #sqrt() + * @since 26 + * @apiNote Note that calling {@code nthRoot(2)} is equivalent to calling {@code sqrt()}. + */ + public BigInteger nthRoot(int n) { + if (n == 1) + return this; + + if (n == 2) + return sqrt(); + + checkRootDegree(n); + return new MutableBigInteger(this.mag).nthRootRem(n)[0].toBigInteger(signum); + } + + /** + * Returns an array of two BigIntegers containing the integer {@code n}th root + * {@code r} of {@code this} and its remainder {@code this - r}{@code n}, + * respectively. + * + * @param n the root degree + * @return an array of two BigIntegers with the integer {@code n}th root at + * offset 0 and the remainder at offset 1 + * @throws ArithmeticException if {@code n <= 0}. + * @throws ArithmeticException if {@code n} is even and {@code this} is negative. + * @see #sqrt() + * @see #sqrtAndRemainder() + * @see #nthRoot(int) + * @since 26 + * @apiNote Note that calling {@code nthRootAndRemainder(2)} is equivalent to calling + * {@code sqrtAndRemainder()}. + */ + public BigInteger[] nthRootAndRemainder(int n) { + if (n == 1) + return new BigInteger[] { this, ZERO }; + + if (n == 2) + return sqrtAndRemainder(); + + checkRootDegree(n); + MutableBigInteger[] rootRem = new MutableBigInteger(this.mag).nthRootRem(n); + return new BigInteger[] { + rootRem[0].toBigInteger(signum), + rootRem[1].toBigInteger(signum) + }; + } + + private void checkRootDegree(int n) { + if (n <= 0) + throw new ArithmeticException("Non-positive root degree"); + + if ((n & 1) == 0 && this.signum < 0) + throw new ArithmeticException("Negative radicand with even root degree"); + } + /** * Returns a BigInteger whose value is the greatest common divisor of * {@code abs(this)} and {@code abs(val)}. Returns 0 if diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index 6ff435ba1ed..dd1da29ddd2 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1892,6 +1892,204 @@ class MutableBigInteger { return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE); } + /** + * Calculate the integer {@code n}th root {@code floor(nthRoot(this, n))} and the remainder, + * where {@code nthRoot(., n)} denotes the mathematical {@code n}th root. + * The contents of {@code this} are not changed. The value of {@code this} + * is assumed to be non-negative and the root degree {@code n >= 3}. + * Assumes {@code bitLength() <= Integer.MAX_VALUE}. + * + * @implNote The implementation is based on the material in Richard P. Brent + * and Paul Zimmermann, + * Modern Computer Arithmetic, p. 27-28. + * + * @param n the root degree + * @return the integer {@code n}th root of {@code this} and the remainder + */ + MutableBigInteger[] nthRootRem(int n) { + // Special cases. + if (this.isZero() || this.isOne()) + return new MutableBigInteger[] { this, new MutableBigInteger() }; + + final int bitLength = (int) this.bitLength(); + // if this < 2^n, result is unity + if (bitLength <= n) { + MutableBigInteger rem = new MutableBigInteger(this); + rem.subtract(ONE); + return new MutableBigInteger[] { new MutableBigInteger(1), rem }; + } + + MutableBigInteger s; + if (bitLength <= Long.SIZE) { + // Initial estimate is the root of the unsigned long value. + final long x = this.toLong(); + long sLong = (long) nthRootApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L; + /* The integer-valued recurrence formula in the algorithm of Brent&Zimmermann + * simply discards the fraction part of the real-valued Newton recurrence + * on the function f discussed in the referenced work. + * Indeed, for real x and integer n > 0, the equality ⌊x/n⌋ == ⌊⌊x⌋/n⌋ holds, + * from which the claim follows. + * As a consequence, an initial underestimate (not discussed in BZ) + * will immediately lead to a (weak) overestimate during the 1st iteration, + * thus meeting BZ requirements for termination and correctness. + */ + if (BigInteger.bitLengthForLong(sLong) * (n - 1) <= Long.SIZE) { + // Do the 1st iteration outside the loop to ensure an overestimate + long sToN1 = BigInteger.unsignedLongPow(sLong, n - 1); + sLong = ((n - 1) * sLong + Long.divideUnsigned(x, sToN1)) / n; + + if (BigInteger.bitLengthForLong(sLong) * (n - 1) <= Long.SIZE) { + // Refine the estimate. + long u = sLong; + do { + sLong = u; + sToN1 = BigInteger.unsignedLongPow(sLong, n - 1); + u = ((n - 1) * sLong + Long.divideUnsigned(x, sToN1)) / n; + } while (u < sLong); // Terminate when non-decreasing. + + return new MutableBigInteger[] { + new MutableBigInteger(sLong), new MutableBigInteger(x - sToN1 * sLong) + }; + } + } + // s^(n - 1) could overflow long range, use MutableBigInteger loop instead + s = new MutableBigInteger(sLong); + } else { + final int rootLen = (bitLength - 1) / n + 1; // ⌈bitLength / n⌉ + int rootSh; + double rad = 0.0, approx = 0.0; + if (n < Double.PRECISION) { + // Set up the initial estimate of the iteration. + /* Since the following equality holds: + * nthRoot(x, n) == nthRoot(x/2^sh, n) * 2^(sh/n), + * + * to get an upper bound of the root of x, it suffices to find an integer sh + * and a real s such that s >= nthRoot(x/2^sh, n) and sh % n == 0. + * The upper bound will be s * 2^(sh/n), indeed: + * s * 2^(sh/n) >= nthRoot(x/2^sh, n) * 2^(sh/n) == nthRoot(x, n). + * To achieve this, we right shift the input of sh bits into finite double range, + * rounding up the result. + * + * The value of the shift sh is chosen in order to have the smallest number of + * trailing zeros in the double value of s after the significand (minimizing + * non-significant bits), to avoid losing bits in the significand. + */ + // Determine a right shift that is a multiple of n into finite double range. + rootSh = (bitLength - Double.PRECISION) / n; // rootSh < rootLen + /* Let x = this, P = Double.PRECISION, ME = Double.MAX_EXPONENT, + * bl = bitLength, sh = rootSh * n, ex = (bl - P) % n + * + * We have bl-sh = bl-((bl-P)-ex) = P + ex + * Since ex < n < P, we get P + ex ≤ ME, and so bl-sh ≤ ME. + * + * Recalling x < 2^bl: + * x >> sh < 2^(bl-sh) ≤ 2^ME < Double.MAX_VALUE + * Thus, rad ≤ 2^ME is in the range of finite doubles. + * + * Noting that ex ≥ 0, we get bl-sh = P + ex ≥ P + * which shows that x >> sh has at least P bits of precision, + * since bl-sh is its bit length. + */ + // Shift the value into finite double range + rad = this.toBigInteger().shiftRight(rootSh * n).doubleValue(); + + // Use the root of the shifted value as an estimate. + // rad ≤ 2^ME, so Math.nextUp(rad) < Double.MAX_VALUE + rad = Math.nextUp(rad); + approx = nthRootApprox(rad, n); + } else { // fp arithmetic gives too few correct bits + // Set the root shift to the root's bit length minus 1 + // The initial estimate will be 2^rootLen == 2 << (rootLen - 1) + rootSh = rootLen - 1; + } + + if (rootSh == 0) { + // approx has at most ⌈Double.PRECISION / n⌉ + 1 ≤ 19 integer bits + s = new MutableBigInteger((int) approx + 1); + } else { + // Allocate ⌈intLen / n⌉ ints to store the final root + s = new MutableBigInteger(new int[(intLen - 1) / n + 1]); + + if (n >= Double.PRECISION) { // fp arithmetic gives too few correct bits + // Set the initial estimate to 2 << (rootLen - 1) + s.value[0] = 2; + s.intLen = 1; + } else { + // Discard wrong integer bits from the initial estimate + // The reduced radicand rad has Math.getExponent(rad)+1 integer bits, but only + // the first Double.PRECISION leftmost bits are correct + // We scale the corresponding wrong bits of approx in the fraction part. + int wrongBits = ((Math.getExponent(rad) + 1) - Double.PRECISION) / n; + // Since rad <= 2^(bitLength - sh), then + // wrongBits <= ((bitLength - sh + 1) - Double.PRECISION) / n, + // so wrongBits is less than ⌈(bitLength - sh) / n⌉, + // the bit length of the exact shifted root, + // hence wrongBits + rootSh < ⌈(bitLength - sh) / n⌉ + rootSh == rootLen + rootSh += wrongBits; + approx = Math.scalb(approx, -wrongBits); + + // now approx has at most ⌈Double.PRECISION / n⌉ + 1 ≤ 19 integer bits + s.value[0] = (int) approx + 1; + s.intLen = 1; + } + + /* The Newton's recurrence roughly doubles the correct bits at each iteration. + * Instead of shifting the approximate root into the original range right now, + * we only double its bit length and then refine it with Newton's recurrence, + * using a suitable shifted radicand, in order to avoid computing and + * carrying trash bits in the approximate root. + * The shifted radicand is determined by the same reasoning used to get the + * initial estimate. + */ + // Refine the estimate to avoid computing non-significant bits + // rootSh is always less than rootLen, so correctBits >= 1 + for (int correctBits = rootLen - rootSh; correctBits < rootSh; correctBits <<= 1) { + s.leftShift(correctBits); + rootSh -= correctBits; + // Remove useless bits from the radicand + MutableBigInteger x = new MutableBigInteger(this); + x.rightShift(rootSh * n); + + newtonRecurrenceNthRoot(x, s, n, s.toBigInteger().pow(n - 1)); + s.add(ONE); // round up to ensure s is an upper bound of the root + } + + // Shift the approximate root back into the original range. + s.leftShift(rootSh); // Here rootSh > 0 always + } + } + + // Do the 1st iteration outside the loop to ensure an overestimate + newtonRecurrenceNthRoot(this, s, n, s.toBigInteger().pow(n - 1)); + // Refine the estimate. + do { + BigInteger sBig = s.toBigInteger(); + BigInteger sToN1 = sBig.pow(n - 1); + MutableBigInteger rem = new MutableBigInteger(sToN1.multiply(sBig).mag); + if (rem.subtract(this) <= 0) + return new MutableBigInteger[] { s, rem }; + + newtonRecurrenceNthRoot(this, s, n, sToN1); + } while (true); + } + + private static double nthRootApprox(double x, int n) { + return Math.nextUp(n == 3 ? Math.cbrt(x) : Math.pow(x, Math.nextUp(1.0 / n))); + } + + /** + * Computes {@code ((n-1)*s + x/sToN1)/n} and places the result in {@code s}. + */ + private static void newtonRecurrenceNthRoot( + MutableBigInteger x, MutableBigInteger s, int n, BigInteger sToN1) { + MutableBigInteger dividend = new MutableBigInteger(); + s.mul(n - 1, dividend); + MutableBigInteger xDivSToN1 = new MutableBigInteger(); + x.divide(new MutableBigInteger(sToN1.mag), xDivSToN1, false); + dividend.add(xDivSToN1); + dividend.divideOneWord(n, s); + } + /** * Calculate the integer square root {@code floor(sqrt(this))} and the remainder * if needed, where {@code sqrt(.)} denotes the mathematical square root. diff --git a/test/jdk/java/math/BigInteger/BigIntegerTest.java b/test/jdk/java/math/BigInteger/BigIntegerTest.java index 7da3fdac618..9018db6bb3c 100644 --- a/test/jdk/java/math/BigInteger/BigIntegerTest.java +++ b/test/jdk/java/math/BigInteger/BigIntegerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @library /test/lib * @build jdk.test.lib.RandomFactory * @run main BigIntegerTest - * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027 8229845 + * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027 8229845 8077587 * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed) * @run main/timeout=400 BigIntegerTest * @author madbot @@ -231,6 +231,9 @@ public class BigIntegerTest { if (!y.equals(z)) failCount1++; + + failCount1 += checkResult(x.signum() < 0 && power % 2 == 0 ? x.negate() : x, + y.nthRoot(power), "BigInteger.pow() inconsistent with BigInteger.nthRoot()"); } report("pow for " + order + " bits", failCount1); } @@ -412,6 +415,154 @@ public class BigIntegerTest { BigInteger.valueOf(x)).collect(Collectors.summingInt(g))); } + private static void nthRootSmall() { + int failCount = 0; + + // A non-positive degree should cause an exception. + int n = 0; + BigInteger x = BigInteger.ONE; + BigInteger s; + try { + s = x.nthRoot(n); + // If nthRoot() does not throw an exception that is a failure. + failCount++; + printErr("nthRoot() of non-positive degree did not throw an exception"); + } catch (ArithmeticException expected) { + // Not a failure + } + + // A negative value with even degree should cause an exception. + n = 4; + x = BigInteger.valueOf(-1); + try { + s = x.nthRoot(n); + // If nthRoot() does not throw an exception that is a failure. + failCount++; + printErr("nthRoot() of negative number and even degree did not throw an exception"); + } catch (ArithmeticException expected) { + // Not a failure + } + + // A negative value with odd degree should return -nthRoot(-x, n) + n = 3; + x = BigInteger.valueOf(-8); + failCount += checkResult(x.negate().nthRoot(n).negate(), x.nthRoot(n), + "nthRoot(" + x + ", " + n + ") != -nthRoot(" + x.negate() + ", " + n + ")"); + + // A zero value should return BigInteger.ZERO. + failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.nthRoot(n), + "nthRoot(0, " + n + ") != 0"); + + // A one degree should return x. + x = BigInteger.TWO; + failCount += checkResult(x, x.nthRoot(1), "nthRoot(" + x + ", 1) != " + x); + + n = 8; + // 1 <= value < 2^n should return BigInteger.ONE. + int end = 1 << n; + for (int i = 1; i < end; i++) { + failCount += checkResult(BigInteger.ONE, + BigInteger.valueOf(i).nthRoot(n), "nthRoot(" + i + ", " + n + ") != 1"); + } + + report("nthRootSmall", failCount); + } + + public static void nthRoot() { + nthRootSmall(); + + ToIntFunction f = (x) -> { + int n = random.nextInt(x.bitLength()) + 2; + int failCount = 0; + + // nth root of x^n -> x + BigInteger xN = x.pow(n); + failCount += checkResult(x, xN.nthRoot(n), "nthRoot() x^n -> x"); + + // nth root of x^n + 1 -> x + BigInteger xNup = xN.add(BigInteger.ONE); + failCount += checkResult(x, xNup.nthRoot(n), "nthRoot() x^n + 1 -> x"); + + // nth root of (x + 1)^n - 1 -> x + BigInteger up = + x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE); + failCount += checkResult(x, up.nthRoot(n), "nthRoot() (x + 1)^n - 1 -> x"); + + // nthRoot(x, n)^n <= x + BigInteger r = x.nthRoot(n); + if (r.pow(n).compareTo(x) > 0) { + failCount++; + printErr("nthRoot(x, n)^n > x for x = " + x + ", n = " + n); + } + + // (nthRoot(x, n) + 1)^n > x + if (r.add(BigInteger.ONE).pow(n).compareTo(x) <= 0) { + failCount++; + printErr("(nthRoot(x, n) + 1)^n <= x for x = " + x + ", n = " + n); + } + + return failCount; + }; + + Stream.Builder sb = Stream.builder(); + int maxExponent = 256; + for (int i = 1; i <= maxExponent; i++) { + BigInteger p2 = BigInteger.ONE.shiftLeft(i); + sb.add(p2.subtract(BigInteger.ONE)); + sb.add(p2); + sb.add(p2.add(BigInteger.ONE)); + } + sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger()); + sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE)); + report("nthRoot for 2^N, 2^N - 1 and 2^N + 1, 1 <= N <= " + maxExponent, + sb.build().collect(Collectors.summingInt(f))); + + IntStream ints = random.ints(SIZE, 2, Integer.MAX_VALUE); + report("nthRoot for int", ints.mapToObj(x -> + BigInteger.valueOf(x)).collect(Collectors.summingInt(f))); + + LongStream longs = random.longs(SIZE, Integer.MAX_VALUE + 1L, Long.MAX_VALUE); + report("nthRoot for long", longs.mapToObj(x -> + BigInteger.valueOf(x)).collect(Collectors.summingInt(f))); + + DoubleStream doubles = random.doubles(SIZE, 0x1p63, Math.scalb(1.0, maxExponent)); + report("nthRoot for double", doubles.mapToObj(x -> + BigDecimal.valueOf(x).toBigInteger()).collect(Collectors.summingInt(f))); + } + + public static void nthRootAndRemainder() { + ToIntFunction g = (x) -> { + int failCount = 0; + int n = random.nextInt(x.bitLength()) + 2; + BigInteger xN = x.pow(n); + + // nth root of x^n -> x + BigInteger[] actual = xN.nthRootAndRemainder(n); + failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + failCount += checkResult(BigInteger.ZERO, actual[1], "nthRootAndRemainder()[1]"); + + // nth root of x^n + 1 -> x + BigInteger xNup = xN.add(BigInteger.ONE); + actual = xNup.nthRootAndRemainder(n); + failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + failCount += checkResult(BigInteger.ONE, actual[1], "nthRootAndRemainder()[1]"); + + // nth root of (x + 1)^n - 1 -> x + BigInteger up = + x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE); + actual = up.nthRootAndRemainder(n); + failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + BigInteger r = up.subtract(xN); + failCount += checkResult(r, actual[1], "nthRootAndRemainder()[1]"); + + return failCount; + }; + + IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE); + report("nthRootAndRemainder", bits.mapToObj(x -> + BigInteger.valueOf(x)).collect(Collectors.summingInt(g))); + } + public static void arithmetic(int order) { int failCount = 0; @@ -1294,6 +1445,8 @@ public class BigIntegerTest { squareRoot(); squareRootAndRemainder(); + nthRoot(); + nthRootAndRemainder(); bitCount(); bitLength(); From 48831c65b5535fef706b64a4eb23ba28b1567ead Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 8 Sep 2025 16:23:26 +0000 Subject: [PATCH 178/295] 8367021: Regression in LocaleDataTest refactoring Reviewed-by: jlu, joehw --- test/jdk/sun/text/resources/LocaleDataTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 009ba718de5..40182034854 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -41,7 +41,7 @@ * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 * 8251317 8274658 8283277 8283805 8265315 8287868 8295564 8284840 8296715 - * 8301206 8303472 8317979 8306116 8174269 8333582 8357075 8357882 + * 8301206 8303472 8317979 8306116 8174269 8333582 8357075 8357882 8367021 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata @@ -204,7 +204,7 @@ public class LocaleDataTest in = new BufferedReader(new InputStreamReader(new FileInputStream(localeData), StandardCharsets.UTF_8)); } - out = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8)); + out = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8), true); // perform the actual test int errorCount = doTest(in, out, writeNewFile); From 323b02016e7458a0be39d52c9b0a5c61d579347e Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 8 Sep 2025 16:46:30 +0000 Subject: [PATCH 179/295] 8367034: [REDO] Protect ExecuteWithLog from running with redirection without a subshell Reviewed-by: erikj --- make/RunTests.gmk | 34 ++++++++++++++-------------- make/StaticLibs.gmk | 2 +- make/common/MakeBase.gmk | 26 +++++++++++++-------- make/common/ProcessMarkdown.gmk | 2 +- make/hotspot/gensrc/GensrcDtrace.gmk | 5 ++-- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 10f0a2f87ed..7b05a0ba12f 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -509,7 +509,7 @@ define SetupRunGtestTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ $$(CD) $$($1_TEST_SUPPORT_DIR) && \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ -jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \ @@ -520,7 +520,7 @@ define SetupRunGtestTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt @@ -644,7 +644,7 @@ define SetupRunMicroTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \ $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ @@ -655,7 +655,7 @@ define SetupRunMicroTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt @@ -758,34 +758,34 @@ define SetupAOTBody ifeq ($$($1_TRAINING), onestep) $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ - -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ + -Xlog:class+load$$(COMMA)aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) else $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ - -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ + -Xlog:class+load$$(COMMA)aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ - $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ + $$($1_VM_OPTIONS) -Xlog:aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - )) + ) endif @@ -1085,9 +1085,9 @@ define SetupRunJtregTestBody $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1204,12 +1204,12 @@ define SetupRunSpecialTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \ $$($1_TEST_COMMAND_LINE) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) # We can not parse the various "special" tests. parse-test-$1: run-test-$1 diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk index 3cf2a4dd136..80d6b4538c8 100644 --- a/make/StaticLibs.gmk +++ b/make/StaticLibs.gmk @@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true) INFO := Generating export list for $(notdir $(lib)), \ DEPS := $(lib), \ OUTPUT_FILE := $(lib).exp, \ - COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \ + COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \ )) \ $(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \ ) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index d1bb0396943..97ef88932cb 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -284,6 +284,12 @@ else LogCmdlines = endif +# Check if the command line contains redirection, that is <, > or >>, +# and if so, return a value that is interpreted as true in a make $(if) +# construct. +is_redirect = \ + $(if $(filter < > >>, $1), true) + ################################################################################ # ExecuteWithLog will run a command and log the output appropriately. This is # meant to be used by commands that do "real" work, like a compilation. @@ -291,21 +297,23 @@ endif # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # -# NOTE: If the command redirects stdout, the caller needs to wrap it in a -# subshell (by adding parentheses around it), otherwise the redirect to the -# subshell tee process will create a race condition where the target file may -# not be fully written when the make recipe is done. -# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ - $(call LogCmdlines, Executing: [$(strip $2)]) \ + $(call LogCmdlines, Executing: \ + [$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN))]) \ $(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ + ( $(RM) $(strip $1).log && \ + $(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN)) \ + > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ - $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ - $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ + $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ + $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ exit $(DOLLAR)exitcode ) ) ################################################################################ diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index 1b4a5b76ea1..c60b49ae85f 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -109,7 +109,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) + $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index e71c3cb961d..7a80bf47285 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -47,8 +47,9 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - ($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) - $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $@, \ + $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: # hotspot_jni.d hotspot.d hs_private.d From 55af9d83800930966776224bc4c7ff4ab1af9817 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 8 Sep 2025 16:48:14 +0000 Subject: [PATCH 180/295] 8366837: Clean up gensrc by spp.Spp Reviewed-by: erikj --- make/common/Utils.gmk | 36 ++ .../modules/GensrcStreamPreProcessing.gmk | 228 ++++++++ make/modules/java.base/Gensrc.gmk | 4 +- .../modules/java.base/gensrc/GensrcBuffer.gmk | 535 +++++++----------- .../java.base/gensrc/GensrcCharsetCoder.gmk | 141 ++--- .../gensrc/GensrcScopedMemoryAccess.gmk | 185 ++---- .../java.base/gensrc/GensrcVarHandles.gmk | 339 ++++------- .../nio/charset/Charset-X-Coder.java.template | 18 +- test/make/TestMakeBase.gmk | 57 ++ 9 files changed, 752 insertions(+), 791 deletions(-) create mode 100644 make/common/modules/GensrcStreamPreProcessing.gmk diff --git a/make/common/Utils.gmk b/make/common/Utils.gmk index 03009ec3ca4..c0ebabca3f7 100644 --- a/make/common/Utils.gmk +++ b/make/common/Utils.gmk @@ -55,6 +55,42 @@ uppercase = \ $(uppercase_result) \ ) +lowercase_table := A,a B,b C,c D,d E,e F,f G,g H,h I,i J,j K,k L,l M,m N,n O,o \ + P,p Q,q R,r S,s T,t U,u V,v W,w X,x Y,y Z,z + +lowercase_internal = \ + $(if $(strip $1), $$(subst $(firstword $1), $(call lowercase_internal, \ + $(wordlist 2, $(words $1), $1), $2)), $2) + +# Convert a string to lower case. Works only on a-z. +# $1 - The string to convert +lowercase = \ + $(strip \ + $(eval lowercase_result := $(call lowercase_internal, $(lowercase_table), $1)) \ + $(lowercase_result) \ + ) + +lowercase_letters := a b c d e f g h i j k l m n o p q r s t u v w x y z +uppercase_letters := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + +titlecase_internal = \ + $(strip $(or \ + $(strip $(foreach l, $(lowercase_letters) $(uppercase_letters), \ + $(if $(filter $l%, $1), \ + $(call uppercase, $l)$(call lowercase, $(patsubst $l%,%,$1))))), \ + $1)) + +# Convert a string to Title Case. Works only on a-z. +# $1 - The string to convert +titlecase = \ + $(strip $(foreach w, $1, $(call titlecase_internal, $w))) + +# Returns the first character of a string. Works only on a-z. +# $1 - The string to extract the first character from +firstchar = \ + $(strip $(foreach l, $(lowercase_letters) $(uppercase_letters), \ + $(if $(filter $l%, $(firstword $1)), $l))) + ################################################################################ # Creates a sequence of increasing numbers (inclusive). # Param 1 - starting number diff --git a/make/common/modules/GensrcStreamPreProcessing.gmk b/make/common/modules/GensrcStreamPreProcessing.gmk new file mode 100644 index 00000000000..a48e3c98d4b --- /dev/null +++ b/make/common/modules/GensrcStreamPreProcessing.gmk @@ -0,0 +1,228 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +include MakeIncludeStart.gmk +ifeq ($(INCLUDE), true) + +################################################################################ +# This file defines macros that sets up rules for running the spp.Spp build tool +################################################################################ + +include Execute.gmk +include $(TOPDIR)/make/ToolsJdk.gmk + +NON_BYTE_NUMBER_TYPES := char short int long float double +NUMBER_TYPES := byte $(NON_BYTE_NUMBER_TYPES) +PRIMITIVE_TYPES := boolean $(NUMBER_TYPES) + +################################################################################ +# The Conv function converts a type given as first argument (as a normal Java +# native type name), into one of several corresponding strings, depending on +# the aspect given in the second argument +# +# The implementation dispatches the call to one of several Conv_ macros. +# +# arg $1: the type to convert +# arg $2: the aspect to convert for +# arg $3: byte order (only needed for certain aspects) +# +Conv = \ + $(strip $(call Conv_$(strip $2),$(strip $1),$(strip $3))) + +################################################################################ +# Conv_ implementations + +# Return a single letter representing the type (lowercase first letter) +Conv_x = \ + $(call firstchar, $1) + +# Return capitalized type name +Conv_Type = \ + $(call titlecase, $1) + +# Return the full descriptive name of the type, e.g. int -> integer +Conv_fulltype = \ + $(if $(filter char, $1), \ + character, \ + $(if $(filter int, $1), \ + integer, \ + $1 \ + ) \ + ) + +# Return the capitalized full descriptive name of the type, e.g. int -> Integer +Conv_Fulltype = \ + $(call titlecase, $(call Conv_fulltype, $1)) + +# Return log2 bits per value (0-3) +Conv_LBPV = \ + $(if $(filter byte, $1), \ + 0, \ + $(if $(filter char short, $1), \ + 1, \ + $(if $(filter int float, $1), \ + 2, \ + $(if $(filter long double, $1), \ + 3)))) + +# Return float or int category +Conv_category = \ + $(if $(filter float double, $1), \ + floatingPointType, \ + integralType \ + ) + +# Return stream information for char +Conv_streams = \ + $(if $(filter char, $1), streamableType) + +# Return stream type information for char +Conv_streamtype = \ + $(if $(filter char, $1), int) + +# Return capitalized stream type information for char +Conv_Streamtype = \ + $(if $(filter char, $1), Int) + +# Return article to use for type in English text +Conv_a = \ + $(if $(filter int, $1), an, a) + +# Return capitalized article to use for type in English text +Conv_A = \ + $(if $(filter int, $1), An, A) + +# Return integer type with same size as the type +Conv_memtype = \ + $(if $(filter float, $1), int, $(if $(filter double, $1), long, $1)) + +# Return capitalized integer type with same size as the type +Conv_Memtype = \ + $(call titlecase, $(call Conv, $1, memtype)) + +# Return capitalized full descriptive name for integer type with same size as the type +Conv_FullMemtype = \ + $(call Conv, $(call Conv, $1, memtype), Fulltype) + +# Return Type or Memtype depending on byte order +# arg $2: BYTE_ORDER +Conv_Swaptype = \ + $(if $(filter U, $2), \ + $(call Conv, $1, Type), \ + $(call Conv, $1, Memtype)) + +# Return fromBits method name for floating types, depending on byte order +# arg $2: BYTE_ORDER +Conv_fromBits = \ + $(if $(filter float double, $1), \ + $(if $(filter U, $2), , \ + $(call Conv, $1, Type).$(call Conv, $1, memtype)BitsTo$(call Conv, $1, Type))) + +# Return toBits method name for floating types, depending on byte order +# arg $2: BYTE_ORDER +Conv_toBits = \ + $(if $(filter float double, $1), \ + $(if $(filter U, $2), , \ + $(call Conv, $1, Type).$1ToRaw$(call Conv, $(call Conv, $1, memtype), Type)Bits)) + +# Return swap method name, depending on byte order +# arg $2: BYTE_ORDER +Conv_swap = \ + $(if $(filter S, $2), Bits.swap) + +# Return word describing the number of bytes required by type +Conv_nbytes = \ + $(if $(filter 0, $(call Conv, $1, LBPV)), one, \ + $(if $(filter 1, $(call Conv, $1, LBPV)), two, \ + $(if $(filter 2, $(call Conv, $1, LBPV)), four, \ + $(if $(filter 3, $(call Conv, $1, LBPV)), eight)))) + +# Return word describing the number of bytes required by type, minus one +Conv_nbytesButOne = \ + $(if $(filter 0, $(call Conv, $1, LBPV)), zero, \ + $(if $(filter 1, $(call Conv, $1, LBPV)), one, \ + $(if $(filter 2, $(call Conv, $1, LBPV)), three, \ + $(if $(filter 3, $(call Conv, $1, LBPV)), seven)))) + +################################################################################ +# Setup make rules that runs the spp.Spp build tool on an input file. +# +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. +# +# Remaining parameters are named arguments. These include: +# BEGIN_END Set to true to exclude everything outside #begin/#end (default: false) +# SUBST_EMPTY_LINES Set to false to not generate empty lines for removed lines (default: true) +# SOURCE_FILE The input file to process (required) +# OUTPUT_FILE The output file (required) +# INFO Override default message to print (optional) +# KEYS One or more keys to control the generation (optional) +# REPLACEMENTS one or more text replacement patterns, using the syntax: +# VAR=VALUE [VAR=VALUE] ... +# +SetupStreamPreProcessing = $(NamedParamsMacroTemplate) +define SetupStreamPreProcessingBody + # Verify arguments + ifeq ($$($1_SOURCE_FILE), ) + $$(error Must specify SOURCE_FILE (in $1)) + endif + ifeq ($$($1_OUTPUT_FILE), ) + $$(error Must specify OUTPUT_FILE (in $1)) + endif + + $1_COMMAND_LINE := + ifeq ($$($1_BEGIN_END), true) + $1_COMMAND_LINE += -be + endif + + ifeq ($$($1_SUBST_EMPTY_LINES), false) + $1_COMMAND_LINE += -nel + endif + + $1_COMMAND_LINE += $$(foreach k, $$($1_KEYS), -K$$k) + $1_COMMAND_LINE += $$(subst $$$$(SPACE), ,$$(foreach d, $$($1_REPLACEMENTS), -D$$d)) + + $1_COMMAND_LINE += -i$$($1_SOURCE_FILE) -o$$($1_OUTPUT_FILE).tmp + + ifeq ($$($1_INFO), ) + $1_INFO := Preprocessing $$(notdir $$($1_SOURCE_FILE)) for $(MODULE) + endif + + $$(eval $$(call SetupExecute, RUN_SPP_$1, \ + INFO := $$($1_INFO), \ + DEPS := $$($1_SOURCE_FILE) $$(BUILD_TOOLS_JDK), \ + OUTPUT_FILE := $$($1_OUTPUT_FILE), \ + COMMAND := $$(TOOL_SPP) $$($1_COMMAND_LINE), \ + PRE_COMMAND := $$(RM) $$($1_OUTPUT_FILE).tmp $$($1_OUTPUT_FILE), \ + POST_COMMAND := $$(MV) $$($1_OUTPUT_FILE).tmp $$($1_OUTPUT_FILE), \ +)) + + $1 += $$(RUN_SPP_$1) +endef + +################################################################################ + +endif # include guard +include MakeIncludeEnd.gmk diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index e4a019ed584..2750a6c8791 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -26,6 +26,8 @@ ################################################################################ include GensrcCommon.gmk +include GensrcProperties.gmk +include GensrcStreamPreProcessing.gmk include gensrc/GensrcBuffer.gmk include gensrc/GensrcCharacterData.gmk @@ -71,8 +73,6 @@ TARGETS += $(CLDR_GEN_DONE) ################################################################################ -include GensrcProperties.gmk - $(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \ SRC_DIRS := $(MODULE_SRC)/share/classes/sun/launcher/resources, \ CLASS := ListResourceBundle, \ diff --git a/make/modules/java.base/gensrc/GensrcBuffer.gmk b/make/modules/java.base/gensrc/GensrcBuffer.gmk index dd91c8c870a..edefd60b6d4 100644 --- a/make/modules/java.base/gensrc/GensrcBuffer.gmk +++ b/make/modules/java.base/gensrc/GensrcBuffer.gmk @@ -28,363 +28,222 @@ ifeq ($(INCLUDE), true) ################################################################################ -GENSRC_BUFFER := +BUFFER_INPUT_DIR := $(MODULE_SRC)/share/classes/java/nio +BUFFER_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio -GENSRC_BUFFER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio +################################################################################ +# Helper method to setup generation of bin snippets. +# Will add the generated snippet file name to $1_BIN_SNIPPET_FILES. +# +# arg $1: $1 as passed into SetupGenBuffer +# arg $2: type for this bin snippet +define SetupGenBufferBinSnippets + $1_$2_TMP := $$(BUFFER_OUTPUT_DIR)/$1.java.bin-snippet.$2 -GENSRC_BUFFER_SRC := $(MODULE_SRC)/share/classes/java/nio - -### - -$(GENSRC_BUFFER_DST)/_the.buffer.dir: - $(call LogInfo, Generating buffer classes) - $(call MakeDir, $(@D)) - $(TOUCH) $@ - -define fixRw - $1_RW := $2 - $1_rwkey := rw - ifeq (R, $2) - $1_rwkey := ro - endif -endef - -define typesAndBits - # param 1 target - # param 2 type - # param 3 BO - $1_a := a - $1_A := A - - $1_type := $2 - - ifeq ($2, byte) - $1_x := b - $1_Type := Byte - $1_fulltype := byte - $1_Fulltype := Byte - $1_category := integralType - $1_LBPV := 0 - endif - - ifeq ($2, char) - $1_x := c - $1_Type := Char - $1_fulltype := character - $1_Fulltype := Character - $1_category := integralType - $1_streams := streamableType - $1_streamtype := int - $1_Streamtype := Int - $1_LBPV := 1 - endif - - ifeq ($2, short) - $1_x := s - $1_Type := Short - $1_fulltype := short - $1_Fulltype := Short - $1_category := integralType - $1_LBPV := 1 - endif - - ifeq ($2, int) - $1_a := an - $1_A := An - $1_x := i - $1_Type := Int - $1_fulltype := integer - $1_Fulltype := Integer - $1_category := integralType - $1_LBPV := 2 - endif - - ifeq ($2, long) - $1_x := l - $1_Type := Long - $1_fulltype := long - $1_Fulltype := Long - $1_category := integralType - $1_LBPV := 3 - endif - - ifeq ($2, float) - $1_x := f - $1_Type := Float - $1_fulltype := float - $1_Fulltype := Float - $1_category := floatingPointType - $1_LBPV := 2 - endif - - ifeq ($2, double) - $1_x := d - $1_Type := Double - $1_fulltype := double - $1_Fulltype := Double - $1_category := floatingPointType - $1_LBPV := 3 - endif - - $1_Swaptype := $$($1_Type) - $1_memtype := $2 - $1_Memtype := $$($1_Type) - - ifeq ($2, float) - $1_memtype := int - $1_Memtype := Int - ifneq ($3, U) - $1_Swaptype := Int - $1_fromBits := Float.intBitsToFloat - $1_toBits := Float.floatToRawIntBits - endif - endif - - ifeq ($2, double) - $1_memtype := long - $1_Memtype := Long - ifneq ($3, U) - $1_Swaptype := Long - $1_fromBits := Double.longBitsToDouble - $1_toBits := Double.doubleToRawLongBits - endif - endif - - ifeq ($3, S) - $1_swap := Bits.swap - endif -endef - -define genBinOps - # param 1 target - # param 2 type - # param 3 BO - # param 4 RW - # param 5 nbytes - # param 6 nbytesButOne - $(call typesAndBits,$1,$2,$3) - $(call fixRw,$1,$4) - $1_nbytes := $5 - $1_nbytesButOne := $6 - $1_CMD := $(TOOL_SPP) \ - -Dtype=$$($1_type) \ - -DType=$$($1_Type) \ - -Dfulltype=$$($1_fulltype) \ - -Dmemtype=$$($1_memtype) \ - -DMemtype=$$($1_Memtype) \ - -DfromBits=$$($1_fromBits) \ - -DtoBits=$$($1_toBits) \ - -DLG_BYTES_PER_VALUE=$$($1_LBPV) \ - -DBYTES_PER_VALUE="(1 << $$($1_LBPV))" \ - -Dnbytes=$$($1_nbytes) \ - -DnbytesButOne=$$($1_nbytesButOne) \ - -DRW=$$($1_RW) \ - -K$$($1_rwkey) \ - -Da=$$($1_a) \ - -be -endef - -define SetupGenBuffer - # param 1 is for output file - # param 2 is template dependency - # param 3-9 are named args. - # type := - # BIN := - # RW := Mutability (R)ead-only (W)ritable - # BO := (U)nswapped/(S)wapped/(L)ittle/(B)ig - # - $(if $3,$1_$(strip $3)) - $(if $4,$1_$(strip $4)) - $(if $5,$1_$(strip $5)) - $(if $6,$1_$(strip $6)) - $(if $7,$1_$(strip $7)) - $(if $8,$1_$(strip $8)) - $(if $9,$1_$(strip $9)) - $(if $(10),$1_$(strip $(10))) - $(if $(11),$1_$(strip $(11))) - $(if $(12),$1_$(strip $(12))) - $(if $(13),$1_$(strip $(13))) - $(if $(14),$1_$(strip $(14))) - $(foreach i,3 4 5 6 7 8 9 10 11 12 13 14 15,$(if $($i),$1_$(strip $($i)))$(NEWLINE)) - $(call LogSetupMacroEntry,SetupGenBuffer($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15)) - $(if $(16),$(error Internal makefile error: Too many arguments to SetupGenBuffer, please update GensrcBuffer.gmk)) - - $(call fixRw,$1,$$($1_RW)) - $(call typesAndBits,$1,$$($1_type),$$($1_BO)) - - $1_DST := $(GENSRC_BUFFER_DST)/$1.java - $1_SRC := $(GENSRC_BUFFER_SRC)/$(strip $2).java.template - $1_SRC_BIN := $(GENSRC_BUFFER_SRC)/$(strip $2)-bin.java.template - - $1_DEP := $$($1_SRC) - ifneq ($$($1_BIN), 1) - $1_DEP := $$($1_SRC) - $1_OUT := $$($1_DST) + $1_$2_LBPV := $$(call Conv, $2, LBPV) + ifeq ($$($1_READ_ONLY), true) + $1_$2_RW_KEYS := ro + $1_$2_RW_REPLACEMENT := R else - $1_DEP += $$($1_SRC) $$($1_SRC_BIN) - $1_OUT := $(GENSRC_BUFFER_DST)/$1.binop.0.java + $1_$2_RW_KEYS := rw + $1_$2_RW_REPLACEMENT := endif - ifeq ($$($1_BIN), 1) - $(call genBinOps,$1_char,char,$$($1_BO),$$($1_RW),two,one) - $(call genBinOps,$1_short,short,$$($1_BO),$$($1_RW),two,one) - $(call genBinOps,$1_int,int,$$($1_BO),$$($1_RW),four,three) - $(call genBinOps,$1_long,long,$$($1_BO),$$($1_RW),eight,seven) - $(call genBinOps,$1_float,float,$$($1_BO),$$($1_RW),four,three) - $(call genBinOps,$1_double,double,$$($1_BO),$$($1_RW),eight,seven) - endif - - $$($1_DST): $$($1_DEP) $(GENSRC_BUFFER_DST)/_the.buffer.dir - $(RM) $$($1_OUT).tmp - $(TOOL_SPP) -i$$($1_SRC) -o$$($1_OUT).tmp \ - -K$$($1_type) \ - -K$$($1_category) \ - -K$$($1_streams) \ - -Dtype=$$($1_type) \ - -DType=$$($1_Type) \ - -Dfulltype=$$($1_fulltype) \ - -DFulltype=$$($1_Fulltype) \ - -Dstreamtype=$$($1_streamtype) \ - -DStreamtype=$$($1_Streamtype) \ - -Dx=$$($1_x) \ - -Dmemtype=$$($1_memtype) \ - -DMemtype=$$($1_Memtype) \ - -DSwaptype=$$($1_Swaptype) \ - -DfromBits=$$($1_fromBits) \ - -DtoBits=$$($1_toBits) \ - -DLG_BYTES_PER_VALUE=$$($1_LBPV) \ - -DBYTES_PER_VALUE="(1 << $$($1_LBPV))" \ - -DBO=$$($1_BO) \ - -Dswap=$$($1_swap) \ - -DRW=$$($1_RW) \ - -K$$($1_rwkey) \ - -Da=$$($1_a) \ - -DA=$$($1_A) \ - -Kbo$$($1_BO) - $(MV) $$($1_OUT).tmp $$($1_OUT) - # Do the extra bin thing - ifeq ($$($1_BIN), 1) - $(SED) -e '/#BIN/,$$$$d' < $$($1_OUT) > $$($1_DST).tmp - $(RM) $$($1_OUT) - $$($1_char_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_short_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_int_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_long_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_float_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_double_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $(ECHO) "}" >> $$($1_DST).tmp - mv $$($1_DST).tmp $$($1_DST) - endif - - GENSRC_BUFFER += $$($1_DST) + $$(eval $$(call SetupStreamPreProcessing, GEN_BUFFER_BIN_$1_$2, \ + SOURCE_FILE := $$(BUFFER_INPUT_DIR)/$$($1_TEMPLATE)-bin.java.template, \ + OUTPUT_FILE := $$($1_$2_TMP), \ + INFO := Generating buffer class bin snippets for $1 ($2), \ + BEGIN_END := true, \ + KEYS := \ + $$($1_$2_RW_KEYS), \ + REPLACEMENTS := \ + type=$2 \ + RW=$$($1_$2_RW_REPLACEMENT) \ + LG_BYTES_PER_VALUE=$$($1_$2_LBPV) \ + BYTES_PER_VALUE="(1$$$$(SPACE)<<$$$$(SPACE)$$($1_$2_LBPV))" \ + a=$$(call Conv, $2, a) \ + fulltype=$$(call Conv, $2, fulltype) \ + memtype=$$(call Conv, $2, memtype) \ + Memtype=$$(call Conv, $2, Memtype) \ + nbytes=$$(call Conv, $2, nbytes) \ + nbytesButOne=$$(call Conv, $2, nbytesButOne) \ + Type=$$(call Conv, $2, Type) \ + fromBits=$$(call Conv, $2, fromBits, $$($1_BYTE_ORDER)) \ + toBits=$$(call Conv, $2, toBits, $$($1_BYTE_ORDER)), \ + )) + TARGETS += $$(GEN_BUFFER_$1_$2) + $1_BIN_SNIPPET_FILES += $$($1_$2_TMP) endef -### - -X_BUF := X-Buffer - -$(eval $(call SetupGenBuffer,ByteBuffer, $(X_BUF), type := byte, BIN := 1)) -$(eval $(call SetupGenBuffer,CharBuffer, $(X_BUF), type := char)) -$(eval $(call SetupGenBuffer,ShortBuffer, $(X_BUF), type := short)) -$(eval $(call SetupGenBuffer,IntBuffer, $(X_BUF), type := int)) -$(eval $(call SetupGenBuffer,LongBuffer, $(X_BUF), type := long)) -$(eval $(call SetupGenBuffer,FloatBuffer, $(X_BUF), type := float)) -$(eval $(call SetupGenBuffer,DoubleBuffer,$(X_BUF), type := double)) - -# Buffers whose contents are heap-allocated +################################################################################ +# Setup make rules that creates a generated buffer class java source file, +# according to specifications provided. # -HEAP_X_BUF := Heap-X-Buffer - -$(eval $(call SetupGenBuffer,HeapByteBuffer, $(HEAP_X_BUF), type := byte)) -$(eval $(call SetupGenBuffer,HeapByteBufferR, $(HEAP_X_BUF), type := byte, RW := R)) -$(eval $(call SetupGenBuffer,HeapCharBuffer, $(HEAP_X_BUF), type := char)) -$(eval $(call SetupGenBuffer,HeapCharBufferR, $(HEAP_X_BUF), type := char, RW := R)) -$(eval $(call SetupGenBuffer,HeapShortBuffer, $(HEAP_X_BUF), type := short)) -$(eval $(call SetupGenBuffer,HeapShortBufferR, $(HEAP_X_BUF), type := short, RW := R)) -$(eval $(call SetupGenBuffer,HeapIntBuffer, $(HEAP_X_BUF), type := int)) -$(eval $(call SetupGenBuffer,HeapIntBufferR, $(HEAP_X_BUF), type := int, RW := R)) -$(eval $(call SetupGenBuffer,HeapLongBuffer, $(HEAP_X_BUF), type := long)) -$(eval $(call SetupGenBuffer,HeapLongBufferR, $(HEAP_X_BUF), type := long, RW := R)) -$(eval $(call SetupGenBuffer,HeapFloatBuffer, $(HEAP_X_BUF), type := float)) -$(eval $(call SetupGenBuffer,HeapFloatBufferR, $(HEAP_X_BUF), type := float, RW := R)) -$(eval $(call SetupGenBuffer,HeapDoubleBuffer, $(HEAP_X_BUF), type := double)) -$(eval $(call SetupGenBuffer,HeapDoubleBufferR,$(HEAP_X_BUF), type := double, RW := R)) - -# Direct byte buffer +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. The output +# file name is also based on this. # -DIRECT_X_BUF := Direct-X-Buffer - -$(eval $(call SetupGenBuffer,DirectByteBuffer, $(DIRECT_X_BUF), type := byte, BIN := 1)) -$(eval $(call SetupGenBuffer,DirectByteBufferR,$(DIRECT_X_BUF), type := byte, BIN := 1, RW := R)) - -# Unswapped views of direct byte buffers +# Remaining parameters are named arguments. These include: +# TYPE The native type +# TEMPLATE The base file name of the template to use +# BYTE_ORDER (U)nswapped/(S)wapped/(L)ittle/(B)ig +# READ_ONLY Set to true to generate read-only buffers (default: false) +# GENERATE_BIN Set to true to generate bin snippets (default: false) # -$(eval $(call SetupGenBuffer,DirectCharBufferU, $(DIRECT_X_BUF), type := char, BO := U)) -$(eval $(call SetupGenBuffer,DirectCharBufferRU, $(DIRECT_X_BUF), type := char, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectShortBufferU, $(DIRECT_X_BUF), type := short, BO := U)) -$(eval $(call SetupGenBuffer,DirectShortBufferRU, $(DIRECT_X_BUF), type := short, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectIntBufferU, $(DIRECT_X_BUF), type := int, BO := U)) -$(eval $(call SetupGenBuffer,DirectIntBufferRU, $(DIRECT_X_BUF), type := int, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectLongBufferU, $(DIRECT_X_BUF), type := long, BO := U)) -$(eval $(call SetupGenBuffer,DirectLongBufferRU, $(DIRECT_X_BUF), type := long, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectFloatBufferU, $(DIRECT_X_BUF), type := float, BO := U)) -$(eval $(call SetupGenBuffer,DirectFloatBufferRU, $(DIRECT_X_BUF), type := float, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferU, $(DIRECT_X_BUF), type := double, BO := U)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferRU,$(DIRECT_X_BUF), type := double, RW := R, BO := U)) +SetupGenBuffer = $(NamedParamsMacroTemplate) +define SetupGenBufferBody + $1_OUTPUT := $$(BUFFER_OUTPUT_DIR)/$1.java + ifeq ($$($1_GENERATE_BIN), true) + # After generating the buffer class, we need to do further post processing, + # so output to a temporary file + $1_REAL_OUTPUT := $$($1_OUTPUT) + $1_OUTPUT := $$($1_OUTPUT).bin-snippet.tmp + endif -# Swapped views of direct byte buffers + $1_LBPV := $$(call Conv, $$($1_TYPE), LBPV) + ifeq ($$($1_READ_ONLY), true) + $1_RW_KEYS := ro + $1_RW_REPLACEMENT := R + else + $1_RW_KEYS := rw + $1_RW_REPLACEMENT := + endif + + $$(eval $$(call SetupStreamPreProcessing, GEN_BUFFER_$1, \ + SOURCE_FILE := $$(BUFFER_INPUT_DIR)/$$($1_TEMPLATE).java.template, \ + OUTPUT_FILE := $$($1_OUTPUT), \ + INFO := Generating buffer class $1.java, \ + KEYS := \ + $$($1_TYPE) \ + $$($1_RW_KEYS) \ + bo$$($1_BYTE_ORDER) \ + $$(call Conv, $$($1_TYPE), category) \ + $$(call Conv, $$($1_TYPE), streams), \ + REPLACEMENTS := \ + type=$$($1_TYPE) \ + BO=$$($1_BYTE_ORDER) \ + RW=$$($1_RW_REPLACEMENT) \ + LG_BYTES_PER_VALUE=$$($1_LBPV) \ + BYTES_PER_VALUE="(1$$$$(SPACE)<<$$$$(SPACE)$$($1_$2_LBPV))" \ + a=$$(call Conv, $$($1_TYPE), a) \ + A=$$(call Conv, $$($1_TYPE), A) \ + fulltype=$$(call Conv, $$($1_TYPE), fulltype) \ + Fulltype=$$(call Conv, $$($1_TYPE), Fulltype) \ + memtype=$$(call Conv, $$($1_TYPE), memtype) \ + Memtype=$$(call Conv, $$($1_TYPE), Memtype) \ + streamtype=$$(call Conv, $$($1_TYPE), streamtype) \ + Streamtype=$$(call Conv, $$($1_TYPE), Streamtype) \ + Type=$$(call Conv, $$($1_TYPE), Type) \ + x=$$(call Conv, $$($1_TYPE), x) \ + fromBits=$$(call Conv, $$($1_TYPE), fromBits, $$($1_BYTE_ORDER)) \ + toBits=$$(call Conv, $$($1_TYPE), toBits, $$($1_BYTE_ORDER)) \ + swap=$$(call Conv, $$($1_TYPE), swap, $$($1_BYTE_ORDER)) \ + Swaptype=$$(call Conv, $$($1_TYPE), Swaptype, $$($1_BYTE_ORDER)), \ + )) + TARGETS += $$(GEN_BUFFER_$1) + $1 += $$(GEN_BUFFER_$1) + + ifeq ($$($1_GENERATE_BIN), true) + # Setup generation of snippet files, one for each non-byte type. This will + # populate $1_BIN_SNIPPET_FILES. + $1_BIN_SNIPPET_FILES := + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBufferBinSnippets,$1,$$t)) \ + ) + + # Inject these snippets in the file generated by GEN_BUFFER_$1 + $$($1_REAL_OUTPUT): $$($1_OUTPUT) $$($1_BIN_SNIPPET_FILES) + $$(call LogInfo, Concatenating buffer class bin snippets for $1) + # Delete everything from the line containing #BIN and below + $$(SED) -e '/#BIN/,$$$$d' < $$($1_OUTPUT) > $$($1_REAL_OUTPUT).tmp + $$(CAT) $$($1_BIN_SNIPPET_FILES) >> $$($1_REAL_OUTPUT).tmp + $$(ECHO) "}" >> $$($1_REAL_OUTPUT).tmp + $$(MV) $$($1_REAL_OUTPUT).tmp $$($1_REAL_OUTPUT) + + TARGETS += $$($1_REAL_OUTPUT) + $1 += $$($1_REAL_OUTPUT) + endif +endef + +################################################################################ +# Helper method to setup generation of all buffer classes, for a given +# modifiability state (read-only or not) # -$(eval $(call SetupGenBuffer,DirectCharBufferS, $(DIRECT_X_BUF), type := char, BO := S)) -$(eval $(call SetupGenBuffer,DirectCharBufferRS, $(DIRECT_X_BUF), type := char, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectShortBufferS, $(DIRECT_X_BUF), type := short, BO := S)) -$(eval $(call SetupGenBuffer,DirectShortBufferRS, $(DIRECT_X_BUF), type := short, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectIntBufferS, $(DIRECT_X_BUF), type := int, BO := S)) -$(eval $(call SetupGenBuffer,DirectIntBufferRS, $(DIRECT_X_BUF), type := int, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectLongBufferS, $(DIRECT_X_BUF), type := long, BO := S)) -$(eval $(call SetupGenBuffer,DirectLongBufferRS, $(DIRECT_X_BUF), type := long, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectFloatBufferS, $(DIRECT_X_BUF), type := float, BO := S)) -$(eval $(call SetupGenBuffer,DirectFloatBufferRS, $(DIRECT_X_BUF), type := float, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferS, $(DIRECT_X_BUF), type := double, BO := S)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferRS,$(DIRECT_X_BUF), type := double, RW := R, BO := S)) +# arg $1: READ_ONLY argument, true or false +# arg $2: Modifiability marker for class name (R or empty) +define SetupGenerateBuffersWithRO + ifeq ($1, false) + # The basic buffer classes are not generated in READ_ONLY versions + $$(eval $$(call SetupGenBuffer, ByteBuffer, \ + TYPE := byte, \ + TEMPLATE := X-Buffer, \ + GENERATE_BIN := true, \ + )) + TARGETS += $$(ByteBuffer) -# Big-endian views of byte buffers -# -BYTE_X_BUF := ByteBufferAs-X-Buffer + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, $$(call titlecase, $$t)Buffer, \ + TYPE := $$t, \ + TEMPLATE := X-Buffer, \ + )) \ + $$(eval TARGETS += $$($$(call titlecase, $$t)Buffer)) \ + ) + endif -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferB, $(BYTE_X_BUF), type := char, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRB, $(BYTE_X_BUF), type := char, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferB, $(BYTE_X_BUF), type := short, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRB, $(BYTE_X_BUF), type := short, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferB, $(BYTE_X_BUF), type := int, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRB, $(BYTE_X_BUF), type := int, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferB, $(BYTE_X_BUF), type := long, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRB, $(BYTE_X_BUF), type := long, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferB, $(BYTE_X_BUF), type := float, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRB, $(BYTE_X_BUF), type := float, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferB, $(BYTE_X_BUF), type := double, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRB,$(BYTE_X_BUF), type := double, RW := R, BO := B)) + # Buffers whose contents are heap-allocated, one for every type + $$(foreach t, $$(NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, Heap$$(call titlecase, $$t)Buffer$2, \ + TYPE := $$t, \ + TEMPLATE := Heap-X-Buffer, \ + READ_ONLY := $1, \ + )) \ + $$(eval TARGETS += $$(Heap$$(call titlecase, $$t)Buffer$2)) \ + ) -# Little-endian views of byte buffers -# -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferL, $(BYTE_X_BUF), type := char, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRL, $(BYTE_X_BUF), type := char, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferL, $(BYTE_X_BUF), type := short, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRL, $(BYTE_X_BUF), type := short, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferL, $(BYTE_X_BUF), type := int, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRL, $(BYTE_X_BUF), type := int, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferL, $(BYTE_X_BUF), type := long, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRL, $(BYTE_X_BUF), type := long, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferL, $(BYTE_X_BUF), type := float, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRL, $(BYTE_X_BUF), type := float, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferL, $(BYTE_X_BUF), type := double, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRL,$(BYTE_X_BUF), type := double, RW := R, BO := L)) + # Treat byte special for DirectByteBuffer classes + $$(eval $$(call SetupGenBuffer, DirectByteBuffer$2, \ + TEMPLATE := Direct-X-Buffer, \ + TYPE := byte, \ + GENERATE_BIN := true, \ + READ_ONLY := $1, \ + )) + TARGETS += $$(DirectByteBuffer$2) -### + # Generate Swapped and Unswapped views of the direct byte buffers, each for + # every non-byte type + $$(foreach b, U S, \ + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, Direct$$(call titlecase, $$t)Buffer$2$$b, \ + TYPE := $$t, \ + TEMPLATE := Direct-X-Buffer, \ + BYTE_ORDER := $$b, \ + READ_ONLY := $1, \ + )) \ + $$(eval TARGETS += $$(Direct$$(call titlecase, $$t)Buffer$2$$b)) \ + ) \ + ) -$(GENSRC_BUFFER): $(BUILD_TOOLS_JDK) + # Generate Big and Little endian views of the direct byte buffers, each for + # every non-byte type + $$(foreach b, B L, \ + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, ByteBufferAs$$(call titlecase, $$t)Buffer$2$$b, \ + TYPE := $$t, \ + TEMPLATE := ByteBufferAs-X-Buffer, \ + BYTE_ORDER := $$b, \ + READ_ONLY := $1, \ + )) \ + $$(eval TARGETS += $$(ByteBufferAs$$(call titlecase, $$t)Buffer$2$$b)) \ + ) \ + ) +endef -TARGETS += $(GENSRC_BUFFER) +################################################################################ +# Generate buffers in both read-write and read-only variants for all buffers + +$(eval $(call SetupGenerateBuffersWithRO,false,)) +$(eval $(call SetupGenerateBuffersWithRO,true,R)) ################################################################################ diff --git a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk index 3e654d0b7a8..8cc5b92cb2b 100644 --- a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk +++ b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk @@ -28,91 +28,74 @@ ifeq ($(INCLUDE), true) ################################################################################ -GENSRC_CHARSETCODER := - -GENSRC_CHARSETCODER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset - -GENSRC_CHARSETCODER_SRC := $(MODULE_SRC)/share/classes/java/nio - -GENSRC_CHARSETCODER_TEMPLATE := $(GENSRC_CHARSETCODER_SRC)/charset/Charset-X-Coder.java.template +CHARSETCODER_INPUT := $(MODULE_SRC)/share/classes/java/nio/charset/Charset-X-Coder.java.template +CHARSETCODER_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset ################################################################################ -$(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java: $(GENSRC_CHARSETCODER_TEMPLATE) - $(call MakeTargetDir) - $(RM) $@.tmp - $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_decoder, \ - $(TOOL_SPP) -i$< -o$@.tmp \ - -Kdecoder \ - -DA='A' \ - -Da='a' \ - -DCode='Decode' \ - -Dcode='decode' \ - -DitypesPhrase='bytes in a specific charset' \ - -DotypesPhrase='sixteen-bit Unicode characters' \ - -Ditype='byte' \ - -Dotype='character' \ - -DItype='Byte' \ - -DOtype='Char' \ - -Dcoder='decoder' \ - -DCoder='Decoder' \ - -Dcoding='decoding' \ - -DOtherCoder='Encoder' \ - -DreplTypeName='string' \ - -DdefaultRepl='"\\uFFFD"' \ - -DdefaultReplName='"\\uFFFD"<\/code>' \ - -DreplType='String' \ - -DreplFQType='java.lang.String' \ - -DreplLength='length()' \ - -DItypesPerOtype='CharsPerByte' \ - -DnotLegal='not legal for this charset' \ - -Dotypes-per-itype='chars-per-byte' \ - -DoutSequence='Unicode character') - $(MV) $@.tmp $@ +$(eval $(call SetupStreamPreProcessing, GEN_CHARSETDECODER, \ + SOURCE_FILE := $(CHARSETCODER_INPUT), \ + OUTPUT_FILE := $(CHARSETCODER_OUTPUT_DIR)/CharsetDecoder.java, \ + INFO := Generating CharsetDecoder.java, \ + KEYS := decoder, \ + REPLACEMENTS := \ + A='A' \ + a='a' \ + Code='Decode' \ + code='decode' \ + itypesPhrase='bytes$$(SPACE)in$$(SPACE)a$$(SPACE)specific$$(SPACE)charset' \ + otypesPhrase='sixteen-bit$$(SPACE)Unicode$$(SPACE)characters' \ + itype='byte' \ + otype='character' \ + Itype='Byte' \ + Otype='Char' \ + coder='decoder' \ + Coder='Decoder' \ + coding='decoding' \ + OtherCoder='Encoder' \ + replTypeName='string' \ + replType='String' \ + replFQType='java.lang.String' \ + replLength='length()' \ + ItypesPerOtype='CharsPerByte' \ + notLegal='not$$(SPACE)legal$$(SPACE)for$$(SPACE)this$$(SPACE)charset' \ + otypes-per-itype='chars-per-byte' \ + outSequence='Unicode$$(SPACE)character', \ +)) -GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java +TARGETS += $(GEN_CHARSETDECODER) -################################################################################ +$(eval $(call SetupStreamPreProcessing, GEN_CHARSETENCODER, \ + SOURCE_FILE := $(CHARSETCODER_INPUT), \ + OUTPUT_FILE := $(CHARSETCODER_OUTPUT_DIR)/CharsetEncoder.java, \ + INFO := Generating CharsetEncoder.java, \ + KEYS := encoder, \ + REPLACEMENTS := \ + A='An' \ + a='an' \ + Code='Encode' \ + code='encode' \ + itypesPhrase='sixteen-bit$$(SPACE)Unicode$$(SPACE)characters' \ + otypesPhrase='bytes$$(SPACE)in$$(SPACE)a$$(SPACE)specific$$(SPACE)charset' \ + itype='character' \ + otype='byte' \ + Itype='Char' \ + Otype='Byte' \ + coder='encoder' \ + Coder='Encoder' \ + coding='encoding' \ + OtherCoder='Decoder' \ + replTypeName='byte$$(SPACE)array' \ + replType='byte[]' \ + replFQType='byte[]' \ + replLength='length' \ + ItypesPerOtype='BytesPerChar' \ + notLegal='not$$(SPACE)a$$(SPACE)legal$$(SPACE)sixteen-bit$$(SPACE)Unicode$$(SPACE)sequence' \ + otypes-per-itype='bytes-per-char' \ + outSequence='byte$$(SPACE)sequence$$(SPACE)in$$(SPACE)the$$(SPACE)given$$(SPACE)charset', \ +)) -$(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java: $(GENSRC_CHARSETCODER_TEMPLATE) - $(call MakeTargetDir) - $(RM) $@.tmp - $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_encoder, \ - $(TOOL_SPP) -i$< -o$@.tmp \ - -Kencoder \ - -DA='An' \ - -Da='an' \ - -DCode='Encode' \ - -Dcode='encode' \ - -DitypesPhrase='sixteen-bit Unicode characters' \ - -DotypesPhrase='bytes in a specific charset' \ - -Ditype='character' \ - -Dotype='byte' \ - -DItype='Char' \ - -DOtype='Byte' \ - -Dcoder='encoder' \ - -DCoder='Encoder' \ - -Dcoding='encoding' \ - -DOtherCoder='Decoder' \ - -DreplTypeName='byte array' \ - -DdefaultRepl='new byte[] { (byte)'"'"\\?"'"' }' \ - -DdefaultReplName='{<\/code>\ (byte)'"'"\\?"'"'<\/code>\ }<\/code>' \ - -DreplType='byte[]' \ - -DreplFQType='byte[]' \ - -DreplLength='length' \ - -DItypesPerOtype='BytesPerChar' \ - -DnotLegal='not a legal sixteen-bit Unicode sequence' \ - -Dotypes-per-itype='bytes-per-char' \ - -DoutSequence='byte sequence in the given charset') - $(MV) $@.tmp $@ - -GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java - -################################################################################ - -$(GENSRC_CHARSETCODER): $(BUILD_TOOLS_JDK) - -TARGETS += $(GENSRC_CHARSETCODER) +TARGETS += $(GEN_CHARSETENCODER) ################################################################################ diff --git a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk index ea51e4fd4ee..5444de78c00 100644 --- a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk +++ b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk @@ -28,144 +28,77 @@ ifeq ($(INCLUDE), true) ################################################################################ -SCOPED_MEMORY_ACCESS_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc -SCOPED_MEMORY_ACCESS_SRC_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc -SCOPED_MEMORY_ACCESS_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess.java.template -SCOPED_MEMORY_ACCESS_BIN_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess-bin.java.template -SCOPED_MEMORY_ACCESS_DEST := $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)/ScopedMemoryAccess.java +SCOPED_INPUT_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc +SCOPED_INPUT := $(SCOPED_INPUT_DIR)/X-ScopedMemoryAccess.java.template +SCOPED_OUTPUT := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc/ScopedMemoryAccess.java ################################################################################ -# Setup a rule for generating the ScopedMemoryAccess java class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized -define GenerateScopedOp +# Helper method to setup generation of scoped snippets. +# Will add the generated snippet file name to SCOPED_SNIPPET_FILES. +# +# arg $1: type for this snippet +define SetupGenScopedSnippets + $1_SCOPED_SNIPPET_FILE := $$(SCOPED_OUTPUT).snippet.$1 - $1_Type := $2 - - ifeq ($$($1_Type), Boolean) - $1_type := boolean - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS + $1_KEYS := $1 CAS + ifneq ($$(filter byte, $1),) + $1_KEYS += byte + endif + ifneq ($$(filter float double, $1),) + $1_KEYS += floatingPoint + endif + ifneq ($$(filter char short int long, $1),) + $1_KEYS += Unaligned + endif + ifneq ($$(filter boolean byte char short, $1),) + $1_KEYS += ShorterThanInt + endif + ifeq ($$(filter boolean, $1),) + $1_KEYS += AtomicAdd + endif + ifeq ($$(filter float double, $1),) + $1_KEYS += Bitwise endif - ifeq ($$($1_Type), Byte) - $1_type := byte - $1_BoxType := $$($1_Type) + $$(eval $$(call SetupStreamPreProcessing, GEN_SCOPED_SNIPPET_$1, \ + SOURCE_FILE := $$(SCOPED_INPUT_DIR)/X-ScopedMemoryAccess-bin.java.template, \ + OUTPUT_FILE := $$($1_SCOPED_SNIPPET_FILE), \ + INFO := Generating snippets for ScopedMemoryAccess ($1), \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$1 \ + Type=$$(call Conv, $1, Type), \ + )) + TARGETS += $$(GEN_SCOPED_SNIPPET_$1) - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -Kbyte - endif - - ifeq ($$($1_Type), Short) - $1_type := short - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Char) - $1_type := char - $1_BoxType := Character - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Int) - $1_type := int - $1_BoxType := Integer - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Long) - $1_type := long - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Float) - $1_type := float - $1_BoxType := $$($1_Type) - - $1_rawType := int - $1_RawType := Int - $1_RawBoxType := Integer - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifeq ($$($1_Type), Double) - $1_type := double - $1_BoxType := $$($1_Type) - - $1_rawType := long - $1_RawType := Long - $1_RawBoxType := Long - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), ) - $1_ARGS += -KAtomicAdd - endif - - ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), ) - $1_ARGS += -KBitwise - endif - - ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char), ) - $1_ARGS += -KShorterThanInt - endif + SCOPED_SNIPPET_FILES += $$($1_SCOPED_SNIPPET_FILE) endef ################################################################################ -# Setup a rule for generating the ScopedMemoryAccess java class +# Setup generation of snippet files, one for each primitive type. This will +# populate SCOPED_SNIPPET_FILES. -SCOPE_MEMORY_ACCESS_TYPES := Boolean Byte Short Char Int Long Float Double -$(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ - $(eval $(call GenerateScopedOp,BIN_$t,$t))) +# SCOPED_TYPES is identical to PRIMITIVE_TYPES, but with a slightly different +# order. Keep the original SCOPED_TYPES order for now to not change the +# generated file. +SCOPED_TYPES := boolean byte short char int long float double -$(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE) $(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) - $(call MakeDir, $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)) - $(CAT) $(SCOPED_MEMORY_ACCESS_TEMPLATE) > $(SCOPED_MEMORY_ACCESS_DEST) - $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ - $(TOOL_SPP) -nel -K$(BIN_$t_type) -Dtype=$(BIN_$t_type) -DType=$(BIN_$t_Type) $(BIN_$t_ARGS) \ - -i$(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) -o$(SCOPED_MEMORY_ACCESS_DEST) ;) - $(ECHO) "}" >> $(SCOPED_MEMORY_ACCESS_DEST) +SCOPED_SNIPPET_FILES := +$(foreach t, $(SCOPED_TYPES), \ + $(eval $(call SetupGenScopedSnippets,$t)) \ +) -TARGETS += $(SCOPED_MEMORY_ACCESS_DEST) +# Setup a rule for generating the ScopedMemoryAccess java class by incorporating +# those snippets +$(SCOPED_OUTPUT): $(SCOPED_INPUT) $(SCOPED_SNIPPET_FILES) + $(call LogInfo, Concatenating snippets for ScopedMemoryAccess.java) + $(CAT) $(SCOPED_INPUT) > $(SCOPED_OUTPUT).tmp + $(CAT) $(SCOPED_SNIPPET_FILES) >> $(SCOPED_OUTPUT).tmp + $(ECHO) "}" >> $(SCOPED_OUTPUT).tmp + $(MV) $(SCOPED_OUTPUT).tmp $(SCOPED_OUTPUT) + +TARGETS += $(SCOPED_OUTPUT) ################################################################################ diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index ec1aec5c764..e536990c2b1 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -28,277 +28,132 @@ ifeq ($(INCLUDE), true) ################################################################################ -GENSRC_VARHANDLES := - -VARHANDLES_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke -VARHANDLES_SRC_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke +VARHANDLES_INPUT_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke +VARHANDLES_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke ################################################################################ # Setup a rule for generating a VarHandle java class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized +# +# arg $1: type for this varhandle define GenerateVarHandle + VARHANDLE_$1_type := $$(strip $$(if $$(filter reference, $1), Object, $1)) + VARHANDLE_$1_Type := $$(call Conv, $1, Type) - $1_Type := $2 - - $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandle$$($1_Type)s.java - - $1_ARGS += -KCAS - - ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), ) - $1_ARGS += -KAtomicAdd + $1_KEYS := $$(VARHANDLE_$1_type) CAS + ifneq ($$(filter byte short char, $1),) + $1_KEYS += ShorterThanInt + endif + ifeq ($$(filter boolean reference, $1),) + $1_KEYS += AtomicAdd + endif + ifeq ($$(filter float double reference, $1),) + $1_KEYS += Bitwise endif - ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), ) - $1_ARGS += -KBitwise - endif - - ifneq ($$(findstring $$($1_Type), Byte Short Char), ) - $1_ARGS += -KShorterThanInt - endif - - $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandle.java.template $(BUILD_TOOLS_JDK) - ifeq ($$($1_Type), Reference) - $$(eval $1_type := Object) - else - $$(eval $1_type := $$$$(shell $(TR) '[:upper:]' '[:lower:]' <<< $$$$($1_Type))) - endif - $$(call MakeDir, $$(@D)) - $(RM) $$@ - $(TOOL_SPP) -nel -K$$($1_type) -Dtype=$$($1_type) -DType=$$($1_Type) \ - $$($1_ARGS) -i$$< -o$$@ - - GENSRC_VARHANDLES += $$($1_FILENAME) + $$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_$1, \ + SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandle.java.template, \ + OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandle$$(VARHANDLE_$1_Type)s.java, \ + INFO := Generating VarHandle class for $1, \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$$(VARHANDLE_$1_type) \ + Type=$$(VARHANDLE_$1_Type), \ + )) + TARGETS += $$(GEN_VARHANDLE_$1) endef -################################################################################ - ################################################################################ # Setup a rule for generating a VarHandleByteArray java class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized +# +# arg $1: type for this varhandle define GenerateVarHandleByteArray + VARHANDLE_BYTEARRAY_$1_Type := $$(call Conv, $1, Type) - $1_Type := $2 - - $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleByteArrayAs$$($1_Type)s.java - - ifeq ($$($1_Type), Short) - $1_type := short - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) + $1_KEYS := $1 + ifneq ($$(filter int long float double, $1),) + $1_KEYS += CAS + endif + ifneq ($$(filter float double, $1),) + $1_KEYS += floatingPoint + endif + ifneq ($$(filter int long, $1),) + $1_KEYS += AtomicAdd Bitwise endif - ifeq ($$($1_Type), Char) - $1_type := char - $1_BoxType := Character - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - endif - - ifeq ($$($1_Type), Int) - $1_type := int - $1_BoxType := Integer - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Long) - $1_type := long - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Float) - $1_type := float - $1_BoxType := $$($1_Type) - - $1_rawType := int - $1_RawType := Int - $1_RawBoxType := Integer - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifeq ($$($1_Type), Double) - $1_type := double - $1_BoxType := $$($1_Type) - - $1_rawType := long - $1_RawType := Long - $1_RawBoxType := Long - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleByteArrayView.java.template $(BUILD_TOOLS_JDK) - $$(call MakeDir, $$(@D)) - $(RM) $$@ - $(TOOL_SPP) -nel -K$$($1_type) \ - -Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \ - -DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \ - $$($1_ARGS) -i$$< -o$$@ - - GENSRC_VARHANDLES += $$($1_FILENAME) + $$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_BYTEARRAY_$1, \ + SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandleByteArrayView.java.template, \ + OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandleByteArrayAs$$(VARHANDLE_BYTEARRAY_$1_Type)s.java, \ + INFO := Generating VarHandleByteArray class for $1, \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$1 \ + Type=$$(VARHANDLE_BYTEARRAY_$1_Type) \ + BoxType=$$(call Conv, $1, Fulltype) \ + rawType=$$(call Conv, $1, memtype) \ + RawType=$$(call Conv, $1, Memtype) \ + RawBoxType=$$(call Conv, $1, FullMemtype), \ + )) + TARGETS += $$(GEN_VARHANDLE_BYTEARRAY_$1) endef ################################################################################ - -################################################################################ -# Setup a rule for generating a memory segment var handle view class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized +# Setup a rule for generating a VarHandleMemorySegment java class +# +# arg $1: type for this varhandle define GenerateVarHandleMemorySegment + VARHANDLE_SEGMENT_$1_Type := $$(call Conv, $1, Type) - $1_Type := $2 - $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleSegmentAs$$($1_Type)s.java - - ifeq ($$($1_Type), Boolean) - $1_type := boolean - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -Kbyte - $1_ARGS += -KShorterThanInt + $1_KEYS := $1 + ifneq ($$(filter int long float double, $1),) + $1_KEYS += CAS + endif + ifneq ($$(filter boolean byte, $1),) + $1_KEYS += byte + endif + ifneq ($$(filter float double, $1),) + $1_KEYS += floatingPoint + endif + ifneq ($$(filter boolean byte short char, $1),) + $1_KEYS += ShorterThanInt + endif + ifneq ($$(filter int long, $1),) + $1_KEYS += AtomicAdd Bitwise endif - ifeq ($$($1_Type), Byte) - $1_type := byte - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -Kbyte - $1_ARGS += -KShorterThanInt - endif - - ifeq ($$($1_Type), Short) - $1_type := short - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KShorterThanInt - endif - - ifeq ($$($1_Type), Char) - $1_type := char - $1_BoxType := Character - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KShorterThanInt - endif - - ifeq ($$($1_Type), Int) - $1_type := int - $1_BoxType := Integer - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Long) - $1_type := long - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Float) - $1_type := float - $1_BoxType := $$($1_Type) - - $1_rawType := int - $1_RawType := Int - $1_RawBoxType := Integer - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifeq ($$($1_Type), Double) - $1_type := double - $1_BoxType := $$($1_Type) - - $1_rawType := long - $1_RawType := Long - $1_RawBoxType := Long - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleSegmentView.java.template $(BUILD_TOOLS_JDK) - $$(call MakeDir, $$(@D)) - $(RM) $$@ - $(TOOL_SPP) -nel -K$$($1_type) \ - -Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \ - -DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \ - $$($1_ARGS) -i$$< -o$$@ - - GENSRC_VARHANDLES += $$($1_FILENAME) + $$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_SEGMENT_$1, \ + SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandleSegmentView.java.template, \ + OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandleSegmentAs$$(VARHANDLE_SEGMENT_$1_Type)s.java, \ + INFO := Generating VarHandleSegment class for $1, \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$1 \ + Type=$$(VARHANDLE_SEGMENT_$1_Type) \ + BoxType=$$(call Conv, $1, Fulltype) \ + rawType=$$(call Conv, $1, memtype) \ + RawType=$$(call Conv, $1, Memtype) \ + RawBoxType=$$(call Conv, $1, FullMemtype), \ + )) + TARGETS += $$(GEN_VARHANDLE_SEGMENT_$1) endef ################################################################################ +# Generate all VarHandle related classes -# List the types to generate source for, with capitalized first letter -VARHANDLES_TYPES := Boolean Byte Short Char Int Long Float Double Reference -$(foreach t, $(VARHANDLES_TYPES), \ - $(eval $(call GenerateVarHandle,VAR_HANDLE_$t,$t))) +$(foreach t, $(PRIMITIVE_TYPES) reference, \ + $(eval $(call GenerateVarHandle,$t)) \ +) -# List the types to generate source for, with capitalized first letter -VARHANDLES_BYTE_ARRAY_TYPES := Short Char Int Long Float Double -$(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \ - $(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t))) +$(foreach t, $(NON_BYTE_NUMBER_TYPES), \ + $(eval $(call GenerateVarHandleByteArray,$t)) \ +) -# List the types to generate source for, with capitalized first letter -VARHANDLES_MEMORY_SEGMENT_TYPES := Boolean Byte Short Char Int Long Float Double -$(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \ - $(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t))) - -TARGETS += $(GENSRC_VARHANDLES) +$(foreach t, $(PRIMITIVE_TYPES), \ + $(eval $(call GenerateVarHandleMemorySegment,$t)) \ +) ################################################################################ diff --git a/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template b/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template index ca610d476f2..8f0fcc08952 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template +++ b/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template @@ -97,10 +97,10 @@ import jdk.internal.util.ArraysSupport; * #if[encoder] * is initially set to the $coder$'s default replacement, which often - * (but not always) has the initial value $defaultReplName$; + * (but not always) has the initial value { (byte)'?' }; #end[encoder] #if[decoder] - * has the initial value $defaultReplName$; + * has the initial value "\uFFFD"; #end[decoder] * * its value may be changed via the {@link #replaceWith($replFQType$) @@ -212,7 +212,12 @@ public abstract class Charset$Coder$ { /** * Initializes a new $coder$. The new $coder$ will have the given * $otypes-per-itype$ values and its replacement will be the - * $replTypeName$ $defaultReplName$. +#if[encoder] + * byte array { (byte)'?' }. +#end[encoder] +#if[decoder] + * string "\uFFFD". +#end[decoder] * * @param cs * The charset that created this $coder$ @@ -234,7 +239,12 @@ public abstract class Charset$Coder$ { { this(cs, average$ItypesPerOtype$, max$ItypesPerOtype$, - $defaultRepl$); +#if[encoder] + new byte[] { (byte)'?' }); +#end[encoder] +#if[decoder] + "\uFFFD"); +#end[decoder] } /** diff --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk index 61fcbdf522f..d609e8d0227 100644 --- a/test/make/TestMakeBase.gmk +++ b/test/make/TestMakeBase.gmk @@ -113,6 +113,63 @@ ifneq ($(call equals, $(EQUALS_VALUE2), $(EQUALS_EMPTY)), ) $(error The strings >$(EQUALS_VALUE2)< and >$(EQUALS_EMPTY)< are equal) endif +################################################################################ +# Test string manipulation + +$(call AssertEquals, \ + $(call uppercase, foo bar), \ + FOO BAR, \ + uppercase "foo bar" failed, \ +) + +$(call AssertEquals, \ + $(call uppercase, Foo BaR 123), \ + FOO BAR 123, \ + uppercase "Foo BaR 123" failed, \ +) + +$(call AssertEquals, \ + $(call lowercase, FOO BAR), \ + foo bar, \ + lowercase "FOO BAR" failed, \ +) + +$(call AssertEquals, \ + $(call lowercase, Foo BaR 123), \ + foo bar 123, \ + lowercase "Foo BaR 123" failed, \ +) + +$(call AssertEquals, \ + $(call titlecase, foo bar), \ + Foo Bar, \ + titlecase "foo bar" failed, \ +) + +$(call AssertEquals, \ + $(call titlecase, FOO BAR), \ + Foo Bar, \ + titlecase "FOO BAR" failed, \ +) + +$(call AssertEquals, \ + $(call titlecase, Foo BaR 123), \ + Foo Bar 123, \ + titlecase "Foo BaR 123" failed, \ +) + +$(call AssertEquals, \ + $(call firstchar, foo bar), \ + f, \ + firstchar "foo bar" failed, \ +) + +$(call AssertEquals, \ + $(call firstchar, Foo Bar), \ + F, \ + firstchar "Foo Bar" failed, \ +) + ################################################################################ # Test boolean operators From cb58e6560a3b80655224cb79d52bfd0afa3cf262 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 8 Sep 2025 16:48:35 +0000 Subject: [PATCH 181/295] 8330341: Wrap call to MT in ExecuteWithLog Reviewed-by: erikj --- make/common/native/LinkMicrosoft.gmk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/make/common/native/LinkMicrosoft.gmk b/make/common/native/LinkMicrosoft.gmk index a53afba4001..0d4212f2a4a 100644 --- a/make/common/native/LinkMicrosoft.gmk +++ b/make/common/native/LinkMicrosoft.gmk @@ -113,9 +113,10 @@ define CreateDynamicLibraryOrExecutableMicrosoft $$(CHMOD) +x $$($1_TARGET) endif ifneq ($$($1_MANIFEST), ) - $$($1_MT) -nologo -manifest $$($1_MANIFEST) \ - -identity:"$$($1_NAME).exe, version=$$($1_MANIFEST_VERSION)" \ - -outputresource:$$@;#1 + $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_run_mt, \ + $$($1_MT) -nologo -manifest $$($1_MANIFEST) \ + -identity:"$$($1_NAME).exe$$(COMMA) version=$$($1_MANIFEST_VERSION)" \ + '-outputresource:$$($1_TARGET);$$(HASH)1') endif ifneq ($(SIGNING_HOOK), ) $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_call_signing_hook, \ From 85441cec3558f76ffa2a785c959397333503d556 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Sep 2025 18:30:18 +0000 Subject: [PATCH 182/295] 8367101: Remove unused includes in cardTable.cpp Reviewed-by: stefank --- src/hotspot/share/gc/shared/cardTable.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index 76fe73abaf6..76b8eb4d718 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -34,9 +34,6 @@ #include "runtime/java.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" -#if INCLUDE_PARALLELGC -#include "gc/parallel/objectStartArray.hpp" -#endif uint CardTable::_card_shift = 0; uint CardTable::_card_size = 0; From 3e68d7d99fcf3039395ba94234ecbebe8e98c754 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Sep 2025 19:13:55 +0000 Subject: [PATCH 183/295] 8366881: Parallel: Obsolete HeapMaximumCompactionInterval Reviewed-by: iwalulya --- .../gc/parallel/parallelScavengeHeap.cpp | 23 ++++------- .../share/gc/parallel/parallel_globals.hpp | 5 --- .../share/gc/parallel/psParallelCompact.cpp | 38 +++++++------------ .../share/gc/parallel/psParallelCompact.hpp | 10 +++-- src/hotspot/share/runtime/arguments.cpp | 1 + 5 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 9b40475288d..c185b8c4437 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -334,7 +334,9 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { } void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) { - PSParallelCompact::invoke(clear_all_soft_refs); + // No need for max-compaction in this context. + const bool should_do_max_compaction = false; + PSParallelCompact::invoke(clear_all_soft_refs, should_do_max_compaction); } static bool check_gc_heap_free_limit(size_t free_bytes, size_t capacity_bytes) { @@ -394,21 +396,11 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t } } - // If we reach this point, we're really out of memory. Try every trick - // we can to reclaim memory. Force collection of soft references. Force - // a complete compaction of the heap. Any additional methods for finding - // free memory should be here, especially if they are expensive. If this - // attempt fails, an OOM exception will be thrown. + // Last resort GC; clear soft refs and do max-compaction before throwing OOM. { - // Make sure the heap is fully compacted - uintx old_interval = HeapMaximumCompactionInterval; - HeapMaximumCompactionInterval = 0; - const bool clear_all_soft_refs = true; - PSParallelCompact::invoke(clear_all_soft_refs); - - // Restore - HeapMaximumCompactionInterval = old_interval; + const bool should_do_max_compaction = true; + PSParallelCompact::invoke(clear_all_soft_refs, should_do_max_compaction); } if (check_gc_overhead_limit()) { @@ -493,7 +485,8 @@ void ParallelScavengeHeap::collect_at_safepoint(bool full) { } // Upgrade to Full-GC if young-gc fails } - PSParallelCompact::invoke(clear_soft_refs); + const bool should_do_max_compaction = false; + PSParallelCompact::invoke(clear_soft_refs, should_do_max_compaction); } void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { diff --git a/src/hotspot/share/gc/parallel/parallel_globals.hpp b/src/hotspot/share/gc/parallel/parallel_globals.hpp index 83b378d5bbe..84d884f128c 100644 --- a/src/hotspot/share/gc/parallel/parallel_globals.hpp +++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp @@ -31,11 +31,6 @@ product_pd, \ range, \ constraint) \ - product(uintx, HeapMaximumCompactionInterval, 20, \ - "How often should we maximally compact the heap (not allowing " \ - "any dead space)") \ - range(0, max_uintx) \ - \ product(bool, UseMaximumCompactionOnSystemGC, true, \ "Use maximum compaction in the Parallel Old garbage collector " \ "for a system GC") \ diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 5a0dbe3d4e6..bac536234b6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -826,7 +826,8 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { } } -bool PSParallelCompact::check_maximum_compaction(size_t total_live_words, +bool PSParallelCompact::check_maximum_compaction(bool should_do_max_compaction, + size_t total_live_words, MutableSpace* const old_space, HeapWord* full_region_prefix_end) { @@ -839,25 +840,17 @@ bool PSParallelCompact::check_maximum_compaction(size_t total_live_words, // Check if all live objs are too much for old-gen. const bool is_old_gen_too_full = (total_live_words >= old_space->capacity_in_words()); - // JVM flags - 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; - // If all regions in old-gen are full const bool is_region_full = full_region_prefix_end >= _summary_data.region_align_down(old_space->top()); - if (is_max_on_system_gc || is_old_gen_too_full || is_interval_ended || is_region_full) { - _maximum_compaction_gc_num = total_invocations; - return true; - } - - return false; + return should_do_max_compaction + || is_max_on_system_gc + || is_old_gen_too_full + || is_region_full; } -void PSParallelCompact::summary_phase() +void PSParallelCompact::summary_phase(bool should_do_max_compaction) { GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); @@ -880,9 +873,10 @@ void PSParallelCompact::summary_phase() _space_info[i].set_dense_prefix(space->bottom()); } - bool maximum_compaction = check_maximum_compaction(total_live_words, - old_space, - full_region_prefix_end); + should_do_max_compaction = check_maximum_compaction(should_do_max_compaction, + total_live_words, + old_space, + full_region_prefix_end); { GCTraceTime(Info, gc, phases) tm("Summary Phase: expand", &_gc_timer); // Try to expand old-gen in order to fit all live objs and waste. @@ -891,7 +885,7 @@ void PSParallelCompact::summary_phase() ParallelScavengeHeap::heap()->old_gen()->try_expand_till_size(target_capacity_bytes); } - HeapWord* dense_prefix_end = maximum_compaction + HeapWord* dense_prefix_end = should_do_max_compaction ? full_region_prefix_end : compute_dense_prefix_for_old_space(old_space, full_region_prefix_end); @@ -961,11 +955,7 @@ void PSParallelCompact::summary_phase() } } -// This method invokes a full collection. The argument controls whether -// soft-refs should be cleared or not. -// Note that this method should only be called from the vm_thread while at a -// safepoint. -bool PSParallelCompact::invoke(bool clear_all_soft_refs) { +bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_compaction) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); @@ -1020,7 +1010,7 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs) { marking_phase(&_gc_tracer); - summary_phase(); + summary_phase(should_do_max_compaction); #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 874c72d5671..a28df24830c 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -727,7 +727,8 @@ private: static void pre_compact(); static void post_compact(); - static bool check_maximum_compaction(size_t total_live_words, + static bool check_maximum_compaction(bool should_do_max_compaction, + size_t total_live_words, MutableSpace* const old_space, HeapWord* full_region_prefix_end); @@ -742,7 +743,7 @@ private: // make the heap parsable. static void fill_dense_prefix_end(SpaceId id); - static void summary_phase(); + static void summary_phase(bool should_do_max_compaction); static void adjust_pointers(); static void forward_to_new_addr(); @@ -761,7 +762,10 @@ private: public: static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); - static bool invoke(bool clear_all_soft_refs); + // This method invokes a full collection. + // clear_all_soft_refs controls whether soft-refs should be cleared or not. + // should_do_max_compaction controls whether all spaces for dead objs should be reclaimed. + static bool invoke(bool clear_all_soft_refs, bool should_do_max_compaction); template static void adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 21706eb7726..6cfeb1dcb0f 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -568,6 +568,7 @@ static SpecialFlag const special_jvm_flags[] = { { "UsePSAdaptiveSurvivorSizePolicy", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, { "PretenureSizeThreshold", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, + { "HeapMaximumCompactionInterval",JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, From 56e37352d5b0a749ccd150c36c9248e37d280eb6 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 8 Sep 2025 20:52:31 +0000 Subject: [PATCH 184/295] 8367130: JDK builds broken by 8366837: Clean up gensrc by spp.Spp Reviewed-by: liach --- make/modules/java.base/gensrc/GensrcVarHandles.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index e536990c2b1..341a8c9dc2c 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -157,7 +157,7 @@ $(foreach t, $(PRIMITIVE_TYPES), \ ################################################################################ -GENSRC_VARHANDLEGUARDS := $(VARHANDLES_GENSRC_DIR)/VarHandleGuards.java +GENSRC_VARHANDLEGUARDS := $(VARHANDLES_OUTPUT_DIR)/VarHandleGuards.java $(GENSRC_VARHANDLEGUARDS): $(BUILD_TOOLS_JDK) $(call LogInfo, Generating $@) From 81a1e8e1363446de499a59fc706221efde12dd86 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Mon, 8 Sep 2025 21:44:18 +0000 Subject: [PATCH 185/295] 8364936: Shenandoah: Switch nmethod entry barriers to conc_instruction_and_data_patch Reviewed-by: fyang, dzhang, kdnilsen, wkemper --- .../cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp | 8 +------- .../cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp | 3 +-- .../cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp | 2 -- .../shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp | 2 +- src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp | 3 +-- .../gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp | 2 +- .../cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp | 4 ---- .../cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp | 3 +-- .../cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp | 2 -- .../gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp | 2 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 - .../src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java | 5 ++--- 12 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 869e26d3359..302701e1cad 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -331,13 +331,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo __ ldr(rscratch2, thread_disarmed_and_epoch_addr); __ cmp(rscratch1, rscratch2); } else { - assert(patching_type == NMethodPatchingType::conc_data_patch, "must be"); - // Subsequent loads of oops must occur after load of guard value. - // BarrierSetNMethod::disarm sets guard with release semantics. - __ membar(__ LoadLoad); - Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset())); - __ ldrw(rscratch2, thread_disarmed_addr); - __ cmpw(rscratch1, rscratch2); + ShouldNotReachHere(); } __ br(condition, barrier_target); diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index 0d6bfc98a72..fa093a6ef69 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -39,8 +39,7 @@ class Node; enum class NMethodPatchingType { stw_instruction_and_data_patch, - conc_instruction_and_data_patch, - conc_data_patch + conc_instruction_and_data_patch }; class BarrierSetAssembler: public CHeapObj { diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp index c45611c882b..88c90a548d1 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp @@ -58,8 +58,6 @@ static int entry_barrier_offset(nmethod* nm) { return -4 * (4 + slow_path_size(nm)); case NMethodPatchingType::conc_instruction_and_data_patch: return -4 * (10 + slow_path_size(nm)); - case NMethodPatchingType::conc_data_patch: - return -4 * (5 + slow_path_size(nm)); } ShouldNotReachHere(); return 0; diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp index a12d4e2beec..c89847b9d52 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp @@ -67,7 +67,7 @@ private: Register scratch, RegSet saved_regs); public: - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } + virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; } #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp index f48b1bc5f66..390623f48a1 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp @@ -40,8 +40,7 @@ class Node; enum class NMethodPatchingType { stw_instruction_and_data_patch, - conc_instruction_and_data_patch, - conc_data_patch + conc_instruction_and_data_patch }; class BarrierSetAssembler: public CHeapObj { diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp index 6ee70b4b4ea..b058dcf1a2e 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp @@ -69,7 +69,7 @@ private: Register preserve); public: - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } + virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; } /* ==== C1 stubs ==== */ #ifdef COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 7e9bea381a5..387db778c1f 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -241,10 +241,6 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo __ lwu(t0, *guard); switch (patching_type) { - case NMethodPatchingType::conc_data_patch: - // Subsequent loads of oops must occur after load of guard value. - // BarrierSetNMethod::disarm sets guard with release semantics. - __ membar(MacroAssembler::LoadLoad); // fall through to stw_instruction_and_data_patch case NMethodPatchingType::stw_instruction_and_data_patch: { // With STW patching, no data or instructions are updated concurrently, diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp index 7061dca738c..63a7032bb84 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp @@ -40,8 +40,7 @@ class Node; enum class NMethodPatchingType { stw_instruction_and_data_patch, - conc_instruction_and_data_patch, - conc_data_patch + conc_instruction_and_data_patch }; class BarrierSetAssembler: public CHeapObj { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index f24e4f789bc..ac619f83f7d 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -50,8 +50,6 @@ static int entry_barrier_offset(nmethod* nm) { switch (bs_asm->nmethod_patching_type()) { case NMethodPatchingType::stw_instruction_and_data_patch: return -4 * (4 + slow_path_size(nm)); - case NMethodPatchingType::conc_data_patch: - return -4 * (5 + slow_path_size(nm)); case NMethodPatchingType::conc_instruction_and_data_patch: return -4 * (15 + slow_path_size(nm)); } diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp index 7d12cc8cbb6..3fe7c8d1740 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp @@ -69,7 +69,7 @@ private: public: - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } + virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; } #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 47ebe5aa7a7..3ddf7de0510 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -828,7 +828,6 @@ \ AARCH64_ONLY(declare_constant(NMethodPatchingType::stw_instruction_and_data_patch)) \ AARCH64_ONLY(declare_constant(NMethodPatchingType::conc_instruction_and_data_patch)) \ - AARCH64_ONLY(declare_constant(NMethodPatchingType::conc_data_patch)) \ \ declare_constant(ObjectMonitor::NO_OWNER) \ declare_constant(ObjectMonitor::ANONYMOUS_OWNER) \ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index 79a0aa60892..a26872b96ae 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -67,11 +67,10 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { // There currently only 2 variants in use that differ only by the presence of a // dmb instruction int stw = getConstant("NMethodPatchingType::stw_instruction_and_data_patch", Integer.class); - int conc1 = getConstant("NMethodPatchingType::conc_data_patch", Integer.class); - int conc2 = getConstant("NMethodPatchingType::conc_instruction_and_data_patch", Integer.class); + int conc = getConstant("NMethodPatchingType::conc_instruction_and_data_patch", Integer.class); if (patchingType == stw) { patchConcurrent = false; - } else if (patchingType == conc1 || patchingType == conc2) { + } else if (patchingType == conc) { patchConcurrent = true; } else { throw new IllegalArgumentException("unsupported barrier sequence " + patchingType); From 4ec63e8f5d1768ea78d0bbf477d68bcf3c6f96b6 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 9 Sep 2025 00:05:56 +0000 Subject: [PATCH 186/295] 8366850: Test com/sun/jdi/JdbStopInNotificationThreadTest.java failed Reviewed-by: ayang, lmesnik, syan --- test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java index 761c84d2c4c..7490d26fe6f 100644 --- a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java +++ b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java @@ -113,7 +113,7 @@ public class JdbStopInNotificationThreadTest extends JdbTest { private static final String DEBUGGEE_CLASS = JdbStopInNotificationThreadTestTarg.class.getName(); private static final String PATTERN1_TEMPLATE = "^Breakpoint hit: \"thread=Notification Thread\", " + "JdbStopInNotificationThreadTestTarg\\$1\\.handleNotification\\(\\), line=%LINE_NUMBER.*\\R%LINE_NUMBER\\s+System\\.out\\.println\\(\"Memory usage low!!!\"\\);.*"; - private static final String[] DEBUGGEE_OPTIONS = {"-Xmx64M"}; + private static final String[] DEBUGGEE_OPTIONS = {"-Xmx256M"}; private JdbStopInNotificationThreadTest() { super(new LaunchOptions(DEBUGGEE_CLASS) From 0aee7bf24d7f2578d3867bcfa25646cb0bd06d9a Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 9 Sep 2025 00:38:15 +0000 Subject: [PATCH 187/295] 8367048: RISC-V: Correct pipeline descriptions of the architecture Reviewed-by: fyang, fjiang, mli --- src/hotspot/cpu/riscv/riscv.ad | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index e02d781972b..eab19e74f93 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -3833,13 +3833,18 @@ opclass immIorL(immI, immL); pipeline %{ attributes %{ - // RISC-V instructions are of fixed length - fixed_size_instructions; // Fixed size instructions TODO does - max_instructions_per_bundle = 2; // Generic RISC-V 1, Sifive Series 7 2 - // RISC-V instructions come in 32-bit word units - instruction_unit_size = 4; // An instruction is 4 bytes long - instruction_fetch_unit_size = 64; // The processor fetches one line - instruction_fetch_units = 1; // of 64 bytes + // RISC-V instructions are of length 2 or 4 bytes. + variable_size_instructions; + instruction_unit_size = 2; + + // Up to 4 instructions per bundle + max_instructions_per_bundle = 4; + + // The RISC-V processor fetches 64 bytes... + instruction_fetch_unit_size = 64; + + // ...in one line. + instruction_fetch_units = 1; // List of nop instructions nops( MachNop ); From 680bf758980452511ea72224066358e5fd38f060 Mon Sep 17 00:00:00 2001 From: erifan Date: Tue, 9 Sep 2025 06:58:00 +0000 Subject: [PATCH 188/295] 8365911: AArch64: Fix encoding error in sve_cpy for negative floats Reviewed-by: aph, epeter --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 10 +- test/hotspot/gtest/aarch64/aarch64-asmtest.py | 2 + test/hotspot/gtest/aarch64/asmtest.out.h | 251 +++++++++--------- 3 files changed, 136 insertions(+), 127 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 4b0a0e77915..a5d2cbfac98 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -3814,7 +3814,11 @@ private: starti; assert(T != Q, "invalid size"); int sh = 0; - if (imm8 <= 127 && imm8 >= -128) { + if (isFloat) { + assert(T != B, "invalid size"); + assert((imm8 >> 8) == 0, "invalid immediate"); + sh = 0; + } else if (imm8 <= 127 && imm8 >= -128) { sh = 0; } else if (T != B && imm8 <= 32512 && imm8 >= -32768 && (imm8 & 0xff) == 0) { sh = 1; @@ -3824,7 +3828,7 @@ private: } int m = isMerge ? 1 : 0; f(0b00000101, 31, 24), f(T, 23, 22), f(0b01, 21, 20); - prf(Pg, 16), f(isFloat ? 1 : 0, 15), f(m, 14), f(sh, 13), sf(imm8, 12, 5), rf(Zd, 0); + prf(Pg, 16), f(isFloat ? 1 : 0, 15), f(m, 14), f(sh, 13), f(imm8 & 0xff, 12, 5), rf(Zd, 0); } public: @@ -3834,7 +3838,7 @@ public: } // SVE copy floating-point immediate to vector elements (predicated) void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, double d) { - sve_cpy(Zd, T, Pg, checked_cast(pack(d)), /*isMerge*/true, /*isFloat*/true); + sve_cpy(Zd, T, Pg, checked_cast(pack(d)), /*isMerge*/true, /*isFloat*/true); } // SVE conditionally select elements from two vectors diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 62274e2c10f..e1abddf3e1c 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -1958,6 +1958,8 @@ generate(SpecialCases, [["ccmn", "__ ccmn(zr, zr, 3u, Assembler::LE);", ["cpy", "__ sve_cpy(z5, __ D, p0, -32768, false);", "mov\tz5.d, p0/z, -32768"], ["cpy", "__ sve_cpy(z10, __ B, p0, -1, false);", "mov\tz10.b, p0/z, -1"], ["cpy", "__ sve_cpy(z11, __ S, p0, -1, false);", "mov\tz11.s, p0/z, -1"], + ["fcpy", "__ sve_cpy(z11, __ S, p0, 0.5);", "fcpy\tz11.s, p0/m, #0.5"], + ["fcpy", "__ sve_cpy(z11, __ S, p0, -1.0);", "fcpy\tz11.s, p0/m, #-1.0"], ["inc", "__ sve_inc(r0, __ S);", "incw\tx0"], ["dec", "__ sve_dec(r1, __ H);", "dech\tx1"], ["lsl", "__ sve_lsl(z0, __ B, z1, 7);", "lsl\tz0.b, z1.b, #7"], diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index f08c69a27dd..7a3225eaed4 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -971,6 +971,8 @@ __ sve_cpy(z5, __ D, p0, -32768, false); // mov z5.d, p0/z, -32768 __ sve_cpy(z10, __ B, p0, -1, false); // mov z10.b, p0/z, -1 __ sve_cpy(z11, __ S, p0, -1, false); // mov z11.s, p0/z, -1 + __ sve_cpy(z11, __ S, p0, 0.5); // fcpy z11.s, p0/m, #0.5 + __ sve_cpy(z11, __ S, p0, -1.0); // fcpy z11.s, p0/m, #-1.0 __ sve_inc(r0, __ S); // incw x0 __ sve_dec(r1, __ H); // dech x1 __ sve_lsl(z0, __ B, z1, 7); // lsl z0.b, z1.b, #7 @@ -1442,30 +1444,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x140004b4, 0x94000000, - 0x97ffffd4, 0x940004b1, 0x3400000a, 0x34fffa2a, - 0x340095ca, 0x35000008, 0x35fff9c8, 0x35009568, - 0xb400000b, 0xb4fff96b, 0xb400950b, 0xb500001d, - 0xb5fff91d, 0xb50094bd, 0x10000013, 0x10fff8b3, - 0x10009453, 0x90000013, 0x36300016, 0x3637f836, - 0x363093d6, 0x3758000c, 0x375ff7cc, 0x3758936c, + 0x14000000, 0x17ffffd7, 0x140004b6, 0x94000000, + 0x97ffffd4, 0x940004b3, 0x3400000a, 0x34fffa2a, + 0x3400960a, 0x35000008, 0x35fff9c8, 0x350095a8, + 0xb400000b, 0xb4fff96b, 0xb400954b, 0xb500001d, + 0xb5fff91d, 0xb50094fd, 0x10000013, 0x10fff8b3, + 0x10009493, 0x90000013, 0x36300016, 0x3637f836, + 0x36309416, 0x3758000c, 0x375ff7cc, 0x375893ac, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54009140, 0x54000001, 0x54fff541, 0x540090e1, - 0x54000002, 0x54fff4e2, 0x54009082, 0x54000002, - 0x54fff482, 0x54009022, 0x54000003, 0x54fff423, - 0x54008fc3, 0x54000003, 0x54fff3c3, 0x54008f63, - 0x54000004, 0x54fff364, 0x54008f04, 0x54000005, - 0x54fff305, 0x54008ea5, 0x54000006, 0x54fff2a6, - 0x54008e46, 0x54000007, 0x54fff247, 0x54008de7, - 0x54000008, 0x54fff1e8, 0x54008d88, 0x54000009, - 0x54fff189, 0x54008d29, 0x5400000a, 0x54fff12a, - 0x54008cca, 0x5400000b, 0x54fff0cb, 0x54008c6b, - 0x5400000c, 0x54fff06c, 0x54008c0c, 0x5400000d, - 0x54fff00d, 0x54008bad, 0x5400000e, 0x54ffefae, - 0x54008b4e, 0x5400000f, 0x54ffef4f, 0x54008aef, + 0x54009180, 0x54000001, 0x54fff541, 0x54009121, + 0x54000002, 0x54fff4e2, 0x540090c2, 0x54000002, + 0x54fff482, 0x54009062, 0x54000003, 0x54fff423, + 0x54009003, 0x54000003, 0x54fff3c3, 0x54008fa3, + 0x54000004, 0x54fff364, 0x54008f44, 0x54000005, + 0x54fff305, 0x54008ee5, 0x54000006, 0x54fff2a6, + 0x54008e86, 0x54000007, 0x54fff247, 0x54008e27, + 0x54000008, 0x54fff1e8, 0x54008dc8, 0x54000009, + 0x54fff189, 0x54008d69, 0x5400000a, 0x54fff12a, + 0x54008d0a, 0x5400000b, 0x54fff0cb, 0x54008cab, + 0x5400000c, 0x54fff06c, 0x54008c4c, 0x5400000d, + 0x54fff00d, 0x54008bed, 0x5400000e, 0x54ffefae, + 0x54008b8e, 0x5400000f, 0x54ffef4f, 0x54008b2f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1640,109 +1642,110 @@ 0x4e21c862, 0x0e79c862, 0x4e79c862, 0x4e61b8a4, 0x0e79b8a4, 0x4e79b8a4, 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, 0x05d03005, 0x05101fea, - 0x05901feb, 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, - 0x043f9c35, 0x047f9c20, 0x04ff9c20, 0x04299420, - 0x04319160, 0x0461943e, 0x04a19020, 0x04038100, - 0x040381a0, 0x040387e1, 0x04438be2, 0x04c38fe3, - 0x040181e0, 0x04018100, 0x04018621, 0x04418b22, - 0x04418822, 0x04818c23, 0x040081e0, 0x04008120, - 0x04008761, 0x04008621, 0x04408822, 0x04808c23, - 0x042053ff, 0x047f5401, 0x25208028, 0x2538cfe0, - 0x2578d001, 0x25b8efe2, 0x25f8f007, 0x2538dfea, - 0x25b8dfeb, 0xa400a3e0, 0xa420a7e0, 0xa4484be0, - 0xa467afe0, 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, - 0xa55c53e0, 0xa5e1540b, 0xe400fbf6, 0xe408ffff, - 0xe420e7e0, 0xe4484be0, 0xe460efe0, 0xe547e400, - 0xe4014be0, 0xe4a84fe0, 0xe5f15000, 0x858043e0, - 0x85a043ff, 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, - 0x04a0e3eb, 0x04e0e3ec, 0x25104042, 0x25104871, - 0x25904861, 0x25904c92, 0x05344020, 0x05744041, - 0x05b44062, 0x05f44083, 0x252c8840, 0x253c1420, - 0x25681572, 0x25a21ce3, 0x25ea1e34, 0x253c0421, - 0x25680572, 0x25a20ce3, 0x25ea0e34, 0x0522c020, - 0x05e6c0a4, 0x2401a001, 0x2443a051, 0x24858881, - 0x24c78cd1, 0x24850891, 0x24c70cc1, 0x250f9001, - 0x25508051, 0x25802491, 0x25df28c1, 0x25850c81, - 0x251e10d1, 0x65816001, 0x65c36051, 0x65854891, - 0x65c74cc1, 0x05733820, 0x05b238a4, 0x05f138e6, - 0x0570396a, 0x65d0a001, 0x65d6a443, 0x65d4a826, - 0x6594ac26, 0x6554ac26, 0x6556ac26, 0x6552ac26, - 0x65cbac85, 0x65caac01, 0x6589ac85, 0x6588ac01, - 0x65c9ac85, 0x65c8ac01, 0x65dea833, 0x659ca509, - 0x65d8a801, 0x65dcac01, 0x655cb241, 0x0520a1e0, - 0x0521a601, 0x052281e0, 0x05238601, 0x04a14026, - 0x042244a6, 0x046344a6, 0x04a444a6, 0x04e544a7, - 0x0568aca7, 0x05b23230, 0x05302a30, 0x05702a30, - 0x05b02a30, 0x05f02a30, 0x853040af, 0xc5b040af, - 0xe57080af, 0xe5b080af, 0x25034440, 0x254054c4, - 0x25034640, 0x25415a05, 0x25834440, 0x25c54489, - 0x250b5d3a, 0x2550dc20, 0x2518e3e1, 0x2518e021, - 0x2518e0a1, 0x2518e121, 0x2518e1a1, 0x2558e3e2, - 0x2558e042, 0x2558e0c2, 0x2558e142, 0x2598e3e3, - 0x2598e063, 0x2598e0e3, 0x2598e163, 0x25d8e3e4, - 0x25d8e084, 0x25d8e104, 0x25d8e184, 0x2518e407, - 0x05214800, 0x05614800, 0x05a14800, 0x05e14800, - 0x05214c00, 0x05614c00, 0x05a14c00, 0x05e14c00, - 0x05304001, 0x05314001, 0x05a18610, 0x05e18610, - 0x05271e11, 0x6545e891, 0x6585e891, 0x65c5e891, - 0x6545c891, 0x6585c891, 0x65c5c891, 0x45b0c210, - 0x45f1c231, 0x1e601000, 0x1e603000, 0x1e621000, - 0x1e623000, 0x1e641000, 0x1e643000, 0x1e661000, - 0x1e663000, 0x1e681000, 0x1e683000, 0x1e6a1000, - 0x1e6a3000, 0x1e6c1000, 0x1e6c3000, 0x1e6e1000, - 0x1e6e3000, 0x1e701000, 0x1e703000, 0x1e721000, - 0x1e723000, 0x1e741000, 0x1e743000, 0x1e761000, - 0x1e763000, 0x1e781000, 0x1e783000, 0x1e7a1000, - 0x1e7a3000, 0x1e7c1000, 0x1e7c3000, 0x1e7e1000, - 0x1e7e3000, 0xf8268267, 0xf82d023c, 0xf8301046, - 0xf83d2083, 0xf8263290, 0xf82d528c, 0xf8284299, - 0xf8337160, 0xf8386286, 0xf8bf820e, 0xf8a600e0, - 0xf8af1353, 0xf8a922ea, 0xf8b53396, 0xf8a251e3, - 0xf8b340f4, 0xf8a470fd, 0xf8a06209, 0xf8f48097, - 0xf8f002ea, 0xf8eb10d9, 0xf8ff21b0, 0xf8f7302c, - 0xf8ee52a9, 0xf8f041fa, 0xf8e471e4, 0xf8e863c6, - 0xf864823d, 0xf87d013a, 0xf86f1162, 0xf87d20e3, - 0xf86132bb, 0xf870510e, 0xf8704336, 0xf86572b4, - 0xf8706217, 0xb83e8294, 0xb8200264, 0xb8381284, - 0xb8242358, 0xb8333102, 0xb828530e, 0xb83042df, - 0xb824703f, 0xb82a6194, 0xb8a080e9, 0xb8b80090, - 0xb8bb1146, 0xb8bb21b8, 0xb8b032df, 0xb8b653f4, - 0xb8bd41c9, 0xb8b47287, 0xb8bc6169, 0xb8ee828c, - 0xb8e10138, 0xb8f3126d, 0xb8f020b0, 0xb8e03183, - 0xb8e851ef, 0xb8f041e4, 0xb8fe7005, 0xb8ea6376, - 0xb8638120, 0xb873015d, 0xb8781284, 0xb86723b8, - 0xb86e3175, 0xb87b51ed, 0xb87f41d1, 0xb863721e, - 0xb87660f4, 0xce216874, 0xce104533, 0xce648c15, - 0xce8e3302, 0xce6e82ab, 0xce6c87d1, 0xcec08063, - 0xce638937, 0x25e0c358, 0x25a1c7d3, 0x0580785a, - 0x05426328, 0x05009892, 0x25a0cc29, 0x2561cec8, - 0x058044b3, 0x05401c99, 0x05006b49, 0x25e0d6f7, - 0x2561c528, 0x0583c8bc, 0x0542522f, 0x05001ec0, - 0x25e0de65, 0x25a1c113, 0x05803cad, 0x0540f3c0, - 0x0500ab15, 0x2560c28c, 0x2561d7c0, 0x05801ed7, - 0x0542633b, 0x05003696, 0x2560d4b4, 0x25e1c918, - 0x058021ff, 0x05400e15, 0x0500f3de, 0x0473025a, - 0x04bd05ab, 0x658e0025, 0x658a08e2, 0x659a0493, - 0x043e1062, 0x04f418b4, 0x046d15bd, 0x04611fce, - 0x04d6a07c, 0x04001929, 0x041a09da, 0x04d098f4, - 0x04db10d4, 0x0459a3ad, 0x041aa029, 0x041919fb, - 0x04d39e24, 0x04118302, 0x04101dba, 0x04d7ae16, - 0x04dea571, 0x04180210, 0x05e786fc, 0x05e4915c, - 0x04881cf1, 0x044a0f04, 0x04090969, 0x048b16c4, - 0x044101e4, 0x04dcbf44, 0x65809745, 0x658d833f, - 0x65c68468, 0x65c79b07, 0x65829e38, 0x049dafca, - 0x6582bba8, 0x65c0b7ff, 0x65c1b4e0, 0x658dbadd, - 0x65819a9d, 0x65ed9246, 0x65b30815, 0x65e6263c, - 0x65eebb94, 0x65bad14e, 0x65efe178, 0x65fc5697, - 0x65e07f14, 0x040c55a6, 0x04977f4d, 0x043d3046, - 0x04b733a0, 0x046830a4, 0x04ed322d, 0x05686948, - 0x05bd6c13, 0x65c88ef0, 0x450db3d7, 0x4540b6d9, - 0x043e3979, 0x445896ce, 0x445a9005, 0x44d98069, - 0x445b87ae, 0x04da348e, 0x04982edb, 0x0499397f, - 0x0408338c, 0x04ca309c, 0x65c721e6, 0x65c63641, - 0x65982882, 0x04812b8b, 0x0e251083, 0x4e3712d5, - 0x0e61101f, 0x4e6d118b, 0x0eba1338, 0x4eb712d5, - 0x2e31120f, 0x6e2e11ac, 0x2e6810e6, 0x6e6f11cd, - 0x2eaa1128, 0x6eb1120f, + 0x05901feb, 0x0590cc0b, 0x0590de0b, 0x04b0e3e0, + 0x0470e7e1, 0x042f9c20, 0x043f9c35, 0x047f9c20, + 0x04ff9c20, 0x04299420, 0x04319160, 0x0461943e, + 0x04a19020, 0x04038100, 0x040381a0, 0x040387e1, + 0x04438be2, 0x04c38fe3, 0x040181e0, 0x04018100, + 0x04018621, 0x04418b22, 0x04418822, 0x04818c23, + 0x040081e0, 0x04008120, 0x04008761, 0x04008621, + 0x04408822, 0x04808c23, 0x042053ff, 0x047f5401, + 0x25208028, 0x2538cfe0, 0x2578d001, 0x25b8efe2, + 0x25f8f007, 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, + 0xa420a7e0, 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, + 0xa547a814, 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, + 0xe400fbf6, 0xe408ffff, 0xe420e7e0, 0xe4484be0, + 0xe460efe0, 0xe547e400, 0xe4014be0, 0xe4a84fe0, + 0xe5f15000, 0x858043e0, 0x85a043ff, 0xe59f5d08, + 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, + 0x25104042, 0x25104871, 0x25904861, 0x25904c92, + 0x05344020, 0x05744041, 0x05b44062, 0x05f44083, + 0x252c8840, 0x253c1420, 0x25681572, 0x25a21ce3, + 0x25ea1e34, 0x253c0421, 0x25680572, 0x25a20ce3, + 0x25ea0e34, 0x0522c020, 0x05e6c0a4, 0x2401a001, + 0x2443a051, 0x24858881, 0x24c78cd1, 0x24850891, + 0x24c70cc1, 0x250f9001, 0x25508051, 0x25802491, + 0x25df28c1, 0x25850c81, 0x251e10d1, 0x65816001, + 0x65c36051, 0x65854891, 0x65c74cc1, 0x05733820, + 0x05b238a4, 0x05f138e6, 0x0570396a, 0x65d0a001, + 0x65d6a443, 0x65d4a826, 0x6594ac26, 0x6554ac26, + 0x6556ac26, 0x6552ac26, 0x65cbac85, 0x65caac01, + 0x6589ac85, 0x6588ac01, 0x65c9ac85, 0x65c8ac01, + 0x65dea833, 0x659ca509, 0x65d8a801, 0x65dcac01, + 0x655cb241, 0x0520a1e0, 0x0521a601, 0x052281e0, + 0x05238601, 0x04a14026, 0x042244a6, 0x046344a6, + 0x04a444a6, 0x04e544a7, 0x0568aca7, 0x05b23230, + 0x05302a30, 0x05702a30, 0x05b02a30, 0x05f02a30, + 0x853040af, 0xc5b040af, 0xe57080af, 0xe5b080af, + 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, + 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, + 0x2518e3e1, 0x2518e021, 0x2518e0a1, 0x2518e121, + 0x2518e1a1, 0x2558e3e2, 0x2558e042, 0x2558e0c2, + 0x2558e142, 0x2598e3e3, 0x2598e063, 0x2598e0e3, + 0x2598e163, 0x25d8e3e4, 0x25d8e084, 0x25d8e104, + 0x25d8e184, 0x2518e407, 0x05214800, 0x05614800, + 0x05a14800, 0x05e14800, 0x05214c00, 0x05614c00, + 0x05a14c00, 0x05e14c00, 0x05304001, 0x05314001, + 0x05a18610, 0x05e18610, 0x05271e11, 0x6545e891, + 0x6585e891, 0x65c5e891, 0x6545c891, 0x6585c891, + 0x65c5c891, 0x45b0c210, 0x45f1c231, 0x1e601000, + 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, + 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, + 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, + 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, + 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, + 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, + 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, + 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf8268267, + 0xf82d023c, 0xf8301046, 0xf83d2083, 0xf8263290, + 0xf82d528c, 0xf8284299, 0xf8337160, 0xf8386286, + 0xf8bf820e, 0xf8a600e0, 0xf8af1353, 0xf8a922ea, + 0xf8b53396, 0xf8a251e3, 0xf8b340f4, 0xf8a470fd, + 0xf8a06209, 0xf8f48097, 0xf8f002ea, 0xf8eb10d9, + 0xf8ff21b0, 0xf8f7302c, 0xf8ee52a9, 0xf8f041fa, + 0xf8e471e4, 0xf8e863c6, 0xf864823d, 0xf87d013a, + 0xf86f1162, 0xf87d20e3, 0xf86132bb, 0xf870510e, + 0xf8704336, 0xf86572b4, 0xf8706217, 0xb83e8294, + 0xb8200264, 0xb8381284, 0xb8242358, 0xb8333102, + 0xb828530e, 0xb83042df, 0xb824703f, 0xb82a6194, + 0xb8a080e9, 0xb8b80090, 0xb8bb1146, 0xb8bb21b8, + 0xb8b032df, 0xb8b653f4, 0xb8bd41c9, 0xb8b47287, + 0xb8bc6169, 0xb8ee828c, 0xb8e10138, 0xb8f3126d, + 0xb8f020b0, 0xb8e03183, 0xb8e851ef, 0xb8f041e4, + 0xb8fe7005, 0xb8ea6376, 0xb8638120, 0xb873015d, + 0xb8781284, 0xb86723b8, 0xb86e3175, 0xb87b51ed, + 0xb87f41d1, 0xb863721e, 0xb87660f4, 0xce216874, + 0xce104533, 0xce648c15, 0xce8e3302, 0xce6e82ab, + 0xce6c87d1, 0xcec08063, 0xce638937, 0x25e0c358, + 0x25a1c7d3, 0x0580785a, 0x05426328, 0x05009892, + 0x25a0cc29, 0x2561cec8, 0x058044b3, 0x05401c99, + 0x05006b49, 0x25e0d6f7, 0x2561c528, 0x0583c8bc, + 0x0542522f, 0x05001ec0, 0x25e0de65, 0x25a1c113, + 0x05803cad, 0x0540f3c0, 0x0500ab15, 0x2560c28c, + 0x2561d7c0, 0x05801ed7, 0x0542633b, 0x05003696, + 0x2560d4b4, 0x25e1c918, 0x058021ff, 0x05400e15, + 0x0500f3de, 0x0473025a, 0x04bd05ab, 0x658e0025, + 0x658a08e2, 0x659a0493, 0x043e1062, 0x04f418b4, + 0x046d15bd, 0x04611fce, 0x04d6a07c, 0x04001929, + 0x041a09da, 0x04d098f4, 0x04db10d4, 0x0459a3ad, + 0x041aa029, 0x041919fb, 0x04d39e24, 0x04118302, + 0x04101dba, 0x04d7ae16, 0x04dea571, 0x04180210, + 0x05e786fc, 0x05e4915c, 0x04881cf1, 0x044a0f04, + 0x04090969, 0x048b16c4, 0x044101e4, 0x04dcbf44, + 0x65809745, 0x658d833f, 0x65c68468, 0x65c79b07, + 0x65829e38, 0x049dafca, 0x6582bba8, 0x65c0b7ff, + 0x65c1b4e0, 0x658dbadd, 0x65819a9d, 0x65ed9246, + 0x65b30815, 0x65e6263c, 0x65eebb94, 0x65bad14e, + 0x65efe178, 0x65fc5697, 0x65e07f14, 0x040c55a6, + 0x04977f4d, 0x043d3046, 0x04b733a0, 0x046830a4, + 0x04ed322d, 0x05686948, 0x05bd6c13, 0x65c88ef0, + 0x450db3d7, 0x4540b6d9, 0x043e3979, 0x445896ce, + 0x445a9005, 0x44d98069, 0x445b87ae, 0x04da348e, + 0x04982edb, 0x0499397f, 0x0408338c, 0x04ca309c, + 0x65c721e6, 0x65c63641, 0x65982882, 0x04812b8b, + 0x0e251083, 0x4e3712d5, 0x0e61101f, 0x4e6d118b, + 0x0eba1338, 0x4eb712d5, 0x2e31120f, 0x6e2e11ac, + 0x2e6810e6, 0x6e6f11cd, 0x2eaa1128, 0x6eb1120f, + }; // END Generated code -- do not edit From ecfba66d3d7c1fef755f0824f342189d0f231007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 9 Sep 2025 07:31:14 +0000 Subject: [PATCH 189/295] 8366363: MemBaseline accesses VMT without using lock Co-authored-by: Casper Norrbin Reviewed-by: azafari, cnorrbin --- src/hotspot/share/nmt/memBaseline.cpp | 72 +++++++------------ src/hotspot/share/nmt/memBaseline.hpp | 13 ++-- src/hotspot/share/nmt/memReporter.cpp | 10 ++- .../share/nmt/nmtNativeCallStackStorage.cpp | 18 +++++ .../share/nmt/nmtNativeCallStackStorage.hpp | 3 +- src/hotspot/share/nmt/regionsTree.cpp | 13 +++- src/hotspot/share/nmt/regionsTree.hpp | 10 ++- src/hotspot/share/nmt/vmatree.cpp | 7 ++ src/hotspot/share/nmt/vmatree.hpp | 11 ++- src/hotspot/share/utilities/rbTree.hpp | 4 ++ src/hotspot/share/utilities/rbTree.inline.hpp | 49 +++++++++++++ test/hotspot/gtest/utilities/test_rbtree.cpp | 40 +++++++++++ 12 files changed, 185 insertions(+), 65 deletions(-) diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 35dff0d8646..9b796ce0c41 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -27,8 +27,7 @@ #include "memory/metaspaceUtils.hpp" #include "nmt/memBaseline.hpp" #include "nmt/memTracker.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/safepoint.hpp" +#include "nmt/regionsTree.inline.hpp" /* * Sizes are sorted in descenting order for reporting @@ -104,38 +103,6 @@ class MallocAllocationSiteWalker : public MallocSiteWalker { } }; -// Walk all virtual memory regions for baselining -class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { - private: - typedef LinkedListImpl EntryList; - EntryList _virtual_memory_regions; - DEBUG_ONLY(address _last_base;) - public: - VirtualMemoryAllocationWalker() { - DEBUG_ONLY(_last_base = nullptr); - } - - bool do_allocation_site(const ReservedMemoryRegion* rgn) { - assert(rgn->base() >= _last_base, "region unordered?"); - DEBUG_ONLY(_last_base = rgn->base()); - if (rgn->size() > 0) { - if (_virtual_memory_regions.add(*rgn) != nullptr) { - return true; - } else { - return false; - } - } else { - // Ignore empty sites. - return true; - } - } - - LinkedList* virtual_memory_allocations() { - return &_virtual_memory_regions; - } -}; - void MemBaseline::baseline_summary() { MallocMemorySummary::snapshot(&_malloc_memory_snapshot); VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); @@ -158,14 +125,15 @@ bool MemBaseline::baseline_allocation_sites() { // The malloc sites are collected in size order _malloc_sites_order = by_size; - // Virtual memory allocation sites - VirtualMemoryAllocationWalker virtual_memory_walker; - if (!VirtualMemoryTracker::Instance::walk_virtual_memory(&virtual_memory_walker)) { - return false; - } + assert(_vma_allocations == nullptr, "must"); - // Virtual memory allocations are collected in call stack order - _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations()); + { + MemTracker::NmtVirtualMemoryLocker locker; + _vma_allocations = new (mtNMT, std::nothrow) RegionsTree(*VirtualMemoryTracker::Instance::tree()); + if (_vma_allocations == nullptr) { + return false; + } + } if (!aggregate_virtual_memory_allocation_sites()) { return false; @@ -202,20 +170,28 @@ int compare_allocation_site(const VirtualMemoryAllocationSite& s1, bool MemBaseline::aggregate_virtual_memory_allocation_sites() { SortedLinkedList allocation_sites; - VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); - const ReservedMemoryRegion* rgn; VirtualMemoryAllocationSite* site; - while ((rgn = itr.next()) != nullptr) { - VirtualMemoryAllocationSite tmp(*rgn->call_stack(), rgn->mem_tag()); + bool failed_oom = false; + _vma_allocations->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { + VirtualMemoryAllocationSite tmp(*rgn.call_stack(), rgn.mem_tag()); site = allocation_sites.find(tmp); if (site == nullptr) { LinkedListNode* node = allocation_sites.add(tmp); - if (node == nullptr) return false; + if (node == nullptr) { + failed_oom = true; + return false; + } site = node->data(); } - site->reserve_memory(rgn->size()); - site->commit_memory(VirtualMemoryTracker::Instance::committed_size(rgn)); + site->reserve_memory(rgn.size()); + + site->commit_memory(_vma_allocations->committed_size(rgn)); + return true; + }); + + if (failed_oom) { + return false; } _virtual_memory_sites.move(&allocation_sites); diff --git a/src/hotspot/share/nmt/memBaseline.hpp b/src/hotspot/share/nmt/memBaseline.hpp index 2fff4cc666c..3f1ea46d815 100644 --- a/src/hotspot/share/nmt/memBaseline.hpp +++ b/src/hotspot/share/nmt/memBaseline.hpp @@ -35,7 +35,6 @@ typedef LinkedListIterator MallocSiteIterator; typedef LinkedListIterator VirtualMemorySiteIterator; -typedef LinkedListIterator VirtualMemoryAllocationIterator; /* * Baseline a memory snapshot @@ -71,7 +70,7 @@ class MemBaseline { LinkedListImpl _malloc_sites; // All virtual memory allocations - LinkedListImpl _virtual_memory_allocations; + RegionsTree* _vma_allocations; // Virtual memory allocations by allocation sites, always in by_address // order @@ -86,6 +85,7 @@ class MemBaseline { // create a memory baseline MemBaseline(): _instance_class_count(0), _array_class_count(0), _thread_count(0), + _vma_allocations(nullptr), _baseline_type(Not_baselined) { } @@ -110,9 +110,9 @@ class MemBaseline { // Virtual memory allocation iterator always returns in virtual memory // base address order. - VirtualMemoryAllocationIterator virtual_memory_allocations() { - assert(!_virtual_memory_allocations.is_empty(), "Not detail baseline"); - return VirtualMemoryAllocationIterator(_virtual_memory_allocations.head()); + RegionsTree* virtual_memory_allocations() { + assert(_vma_allocations != nullptr, "Not detail baseline"); + return _vma_allocations; } // Total reserved memory = total malloc'd memory + total reserved virtual @@ -185,7 +185,8 @@ class MemBaseline { _malloc_sites.clear(); _virtual_memory_sites.clear(); - _virtual_memory_allocations.clear(); + delete _vma_allocations; + _vma_allocations = nullptr; } private: diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 65d4d76942b..84f0f90f6e5 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -394,13 +394,11 @@ int MemDetailReporter::report_virtual_memory_allocation_sites() { void MemDetailReporter::report_virtual_memory_map() { // Virtual memory map always in base address order - VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations(); - const ReservedMemoryRegion* rgn; - output()->print_cr("Virtual memory map:"); - while ((rgn = itr.next()) != nullptr) { - report_virtual_memory_region(rgn); - } + _baseline.virtual_memory_allocations()->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { + report_virtual_memory_region(&rgn); + return true; + }); } void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) { diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp index 3e5c1d2f0ea..9a2ecd57ecc 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -57,3 +57,21 @@ NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_ NativeCallStackStorage::~NativeCallStackStorage() { FREE_C_HEAP_ARRAY(LinkPtr, _table); } + +NativeCallStackStorage::NativeCallStackStorage(const NativeCallStackStorage& other) + : _table_size(other._table_size), + _table(nullptr), + _stacks(), + _is_detailed_mode(other._is_detailed_mode), + _fake_stack(other._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] = other._table[i]; + } + } + _stacks.reserve(other._stacks.length()); + for (int i = 0; i < other._stacks.length(); i++) { + _stacks.at_grow(i) = other._stacks.at(i); + } +} diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 6f194cfa5a1..6ead8f49248 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -95,7 +95,8 @@ public: } NativeCallStackStorage(bool is_detailed_mode, int table_size = default_table_size); - + NativeCallStackStorage(const NativeCallStackStorage& other); + NativeCallStackStorage& operator=(const NativeCallStackStorage& other) = delete; ~NativeCallStackStorage(); }; diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index 370c69a2485..8644a2d4731 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -22,6 +22,8 @@ * */ #include "nmt/regionsTree.hpp" +#include "nmt/regionsTree.inline.hpp" +#include "nmt/virtualMemoryTracker.hpp" VMATree::SummaryDiff RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack) { return commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), /*use tag inplace*/ true); @@ -54,4 +56,13 @@ void RegionsTree::print_on(outputStream* st) { return true; }); } -#endif \ No newline at end of file +#endif + +size_t RegionsTree::committed_size(ReservedMemoryRegion& rgn) { + size_t result = 0; + visit_committed_regions(rgn, [&](CommittedMemoryRegion& crgn) { + result += crgn.size(); + return true; + }); + return result; +} diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index bf2ab711b2d..b0c5d928bab 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -40,6 +40,12 @@ class RegionsTree : public VMATree { public: RegionsTree(bool with_storage) : VMATree() , _ncs_storage(with_storage), _with_storage(with_storage) { } + RegionsTree(const RegionsTree& other) + : VMATree(other), + _ncs_storage(other._ncs_storage), + _with_storage(other._with_storage) {} + RegionsTree& operator=(const RegionsTree& other) = delete; + ReservedMemoryRegion find_reserved_region(address addr); SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); @@ -91,6 +97,8 @@ class RegionsTree : public VMATree { NativeCallStackStorage::StackIndex si = node.out_stack_index(); return _ncs_storage.get(si); } + + size_t committed_size(ReservedMemoryRegion& rgn); }; -#endif // NMT_REGIONSTREE_HPP \ No newline at end of file +#endif // NMT_REGIONSTREE_HPP diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 4f6f8e12185..69887068cb2 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -744,3 +744,10 @@ void VMATree::SummaryDiff::print_on(outputStream* out) { } } #endif + +void VMATree::clear() { + _tree.remove_all(); +}; +bool VMATree::is_empty() { + return _tree.size() == 0; +}; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 1b5729054e4..88b680a045c 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -30,6 +30,7 @@ #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/rbTree.hpp" #include "utilities/rbTree.inline.hpp" #include @@ -39,7 +40,7 @@ // For example, the state may go from released memory to committed memory, // or from committed memory of a certain MemTag to committed memory of a different MemTag. // The set of points is stored in a balanced binary tree for efficient querying and updating. -class VMATree { +class VMATree : public CHeapObjBase { friend class NMTVMATreeTest; friend class VMTWithVMATreeTest; // A position in memory. @@ -65,7 +66,6 @@ private: static const char* statetype_strings[static_cast(StateType::st_number_of_states)]; public: - NONCOPYABLE(VMATree); static const char* statetype_to_string(StateType type) { assert(type < StateType::st_number_of_states, "must be"); @@ -226,6 +226,10 @@ private: public: VMATree() : _tree() {} + VMATree(const VMATree& other) : _tree() { + assert(other._tree.copy_into(_tree), "VMATree dies on OOM"); + } + VMATree& operator=(VMATree const&) = delete; struct SingleDiff { using delta = int64_t; @@ -329,5 +333,8 @@ public: _tree.visit_range_in_order(from, to, f); } VMARBTree& tree() { return _tree; } + + void clear(); + bool is_empty(); }; #endif diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 4c358b53ff0..fd0e25051f5 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -428,6 +428,7 @@ public: template void visit_in_order(F f); + // Visit all RBNodes in ascending order whose keys are in range [from, to], calling f on each node. // If f returns `true` the iteration continues, otherwise it is stopped at the current node. template @@ -475,6 +476,7 @@ class RBTree : public AbstractRBTree, COMPARATOR> { public: RBTree() : BaseType(), _allocator() {} + NONCOPYABLE(RBTree); ~RBTree() { remove_all(); } RBTree(const RBTree& other) : BaseType(), _allocator() { assert(std::is_copy_constructible(), "Value type must be copy-constructible"); @@ -485,6 +487,8 @@ public: } RBTree& operator=(const RBTree& other) = delete; + bool copy_into(RBTree& other) const; + typedef typename BaseType::Cursor Cursor; using BaseType::cursor; using BaseType::insert_at_cursor; diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index f28923eb867..b7de0a7ac4c 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -753,4 +753,53 @@ void AbstractRBTree::print_on(outputStream* st, const P } } +template +bool RBTree::copy_into(RBTree& other) const { + assert(other.size() == 0, "You can only copy into an empty RBTree"); + assert(std::is_copy_constructible::value, "Key type must be copy-constructible when copying a RBTree"); + assert(std::is_copy_constructible::value, "Value type must be copy-constructible when copying a RBTree"); + enum class Dir { Left, Right }; + struct node_pair { const IntrusiveRBNode* current; IntrusiveRBNode* other_parent; Dir dir; }; + struct stack { + node_pair s[64]; + int idx = 0; + stack() : idx(0) {} + node_pair pop() { idx--; return s[idx]; }; + void push(node_pair n) { s[idx] = n; idx++; }; + bool is_empty() { return idx == 0; }; + }; + + stack visit_stack; + if (this->_root == nullptr) { + return true; + } + RBNode* root = static_cast*>(this->_root); + other._root = other.allocate_node(root->key(), root->val()); + if (other._root == nullptr) return false; + + visit_stack.push({this->_root->_left, other._root, Dir::Left}); + visit_stack.push({this->_root->_right, other._root, Dir::Right}); + while (!visit_stack.is_empty()) { + node_pair n = visit_stack.pop(); + const RBNode* current = static_cast*>(n.current); + if (current == nullptr) continue; + RBNode* new_node = other.allocate_node(current->key(), current->val()); + if (new_node == nullptr) { + return false; + } + if (n.dir == Dir::Left) { + n.other_parent->_left = new_node; + } else { + n.other_parent->_right = new_node; + } + new_node->set_parent(n.other_parent); + new_node->_parent |= n.current->_parent & 0x1; + visit_stack.push({n.current->_left, new_node, Dir::Left}); + visit_stack.push({n.current->_right, new_node, Dir::Right}); + } + other._num_nodes = this->_num_nodes; + DEBUG_ONLY(other._expected_visited = this->_expected_visited); + return true; +} + #endif // SHARE_UTILITIES_RBTREE_INLINE_HPP diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index ff234dd764a..a351e2141e8 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -1200,6 +1200,46 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { } } +TEST_VM_F(RBTreeTest, TestCopyInto) { + { + RBTreeInt rbtree1; + RBTreeInt rbtree2; + + rbtree1.copy_into(rbtree2); + rbtree2.verify_self(); + } + + RBTreeInt rbtree1; + RBTreeInt rbtree2; + + int size = 1000; + for (int i = 0; i < size; i++) { + rbtree1.upsert(i, i); + } + + rbtree1.copy_into(rbtree2); + rbtree2.verify_self(); + + ResourceMark rm; + GrowableArray allocations(size); + int size1 = 0; + rbtree1.visit_in_order([&](RBTreeIntNode* node) { + size1++; + allocations.append(node->key()); + return true; + }); + + int size2 = 0; + rbtree2.visit_in_order([&](RBTreeIntNode* node) { + EXPECT_EQ(node->key(), allocations.at(size2++)); + return true; + }); + + EXPECT_EQ(size1, size2); + EXPECT_EQ(rbtree1.size(), rbtree2.size()); + EXPECT_EQ(size2, static_cast(rbtree2.size())); +} + struct OomAllocator { void* allocate(size_t sz) { return nullptr; From 67bb22f3d661d7edf7a0949612d9fb64f0124cad Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Tue, 9 Sep 2025 07:36:57 +0000 Subject: [PATCH 190/295] 8367085: Sort os/posix includes Reviewed-by: ayang, dholmes --- src/hotspot/os/posix/attachListener_posix.cpp | 8 ++++---- src/hotspot/os/posix/os_posix.cpp | 5 ++--- src/hotspot/os/posix/os_posix.inline.hpp | 4 ++-- src/hotspot/os/posix/perfMemory_posix.cpp | 13 ++++++------- src/hotspot/os/posix/safefetch_sigjmp.cpp | 2 +- src/hotspot/os/posix/semaphore_posix.cpp | 3 ++- src/hotspot/os/posix/threadLocalStorage_posix.cpp | 1 + .../jtreg/sources/TestIncludesAreSorted.java | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/hotspot/os/posix/attachListener_posix.cpp b/src/hotspot/os/posix/attachListener_posix.cpp index d3e24807124..a7cf1703128 100644 --- a/src/hotspot/os/posix/attachListener_posix.cpp +++ b/src/hotspot/os/posix/attachListener_posix.cpp @@ -24,19 +24,19 @@ #include "logging/log.hpp" #include "memory/allocation.inline.hpp" +#include "os_posix.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.inline.hpp" -#include "os_posix.hpp" #include "services/attachListener.hpp" #include "utilities/checkedCast.hpp" #include "utilities/macros.hpp" -#include #include -#include #include -#include #include +#include +#include +#include #if INCLUDE_SERVICES #ifndef AIX diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 6a39c95db52..8f188ef002f 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -70,14 +70,13 @@ #include #include #include -#include #include +#include #include +#include #include #include #include -#include -#include #include #include #include diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp index cf81c5d6286..67be82e4d63 100644 --- a/src/hotspot/os/posix/os_posix.inline.hpp +++ b/src/hotspot/os/posix/os_posix.inline.hpp @@ -30,9 +30,9 @@ #include "runtime/mutex.hpp" #include "runtime/os.hpp" -#include -#include #include +#include +#include // Aix does not have NUMA support but need these for compilation. inline bool os::numa_has_group_homing() { AIX_ONLY(ShouldNotReachHere();) return false; } diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index c58f216b2c3..ed83487265c 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -40,15 +40,14 @@ #include "os_linux.hpp" #endif -// put OS-includes here -# include -# include # include -# include -# include -# include -# include # include +# include +# include +# include +# include +# include +# include #if defined(LINUX) # include diff --git a/src/hotspot/os/posix/safefetch_sigjmp.cpp b/src/hotspot/os/posix/safefetch_sigjmp.cpp index 57f0f8460bf..9f6ef34070b 100644 --- a/src/hotspot/os/posix/safefetch_sigjmp.cpp +++ b/src/hotspot/os/posix/safefetch_sigjmp.cpp @@ -32,8 +32,8 @@ #ifdef SAFEFETCH_METHOD_SIGSETJMP // For SafeFetch we need POSIX TLS and sigsetjmp/longjmp. -#include #include +#include static pthread_key_t g_jmpbuf_key; struct InitTLSKey { InitTLSKey() { pthread_key_create(&g_jmpbuf_key, nullptr); } }; diff --git a/src/hotspot/os/posix/semaphore_posix.cpp b/src/hotspot/os/posix/semaphore_posix.cpp index 23a5225eba3..cb0afaafe42 100644 --- a/src/hotspot/os/posix/semaphore_posix.cpp +++ b/src/hotspot/os/posix/semaphore_posix.cpp @@ -25,9 +25,10 @@ #ifndef __APPLE__ #include "os_posix.hpp" #include "runtime/os.hpp" -#include "utilities/debug.hpp" // POSIX unnamed semaphores are not supported on OS X. #include "semaphore_posix.hpp" +#include "utilities/debug.hpp" + #include PosixSemaphore::PosixSemaphore(uint value) { diff --git a/src/hotspot/os/posix/threadLocalStorage_posix.cpp b/src/hotspot/os/posix/threadLocalStorage_posix.cpp index 44a1d294cd5..8d1dad54a01 100644 --- a/src/hotspot/os/posix/threadLocalStorage_posix.cpp +++ b/src/hotspot/os/posix/threadLocalStorage_posix.cpp @@ -24,6 +24,7 @@ #include "runtime/threadLocalStorage.hpp" #include "utilities/debug.hpp" + #include static pthread_key_t _thread_key; diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 119f32ffe2e..e0e77992ace 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -44,6 +44,7 @@ public class TestIncludesAreSorted { */ private static final String[] HOTSPOT_SOURCES_TO_CHECK = { "os/linux", + "os/posix", "share" }; From e16c510071f84bdbd57a8b2d3810c484c314ccf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 9 Sep 2025 08:14:55 +0000 Subject: [PATCH 191/295] 8367231: [BACKOUT] JDK-8366363: MemBaseline accesses VMT without using lock Reviewed-by: kbarrett, dholmes --- src/hotspot/share/nmt/memBaseline.cpp | 72 ++++++++++++------- src/hotspot/share/nmt/memBaseline.hpp | 13 ++-- src/hotspot/share/nmt/memReporter.cpp | 10 +-- .../share/nmt/nmtNativeCallStackStorage.cpp | 18 ----- .../share/nmt/nmtNativeCallStackStorage.hpp | 3 +- src/hotspot/share/nmt/regionsTree.cpp | 13 +--- src/hotspot/share/nmt/regionsTree.hpp | 10 +-- src/hotspot/share/nmt/vmatree.cpp | 7 -- src/hotspot/share/nmt/vmatree.hpp | 11 +-- src/hotspot/share/utilities/rbTree.hpp | 4 -- src/hotspot/share/utilities/rbTree.inline.hpp | 49 ------------- test/hotspot/gtest/utilities/test_rbtree.cpp | 40 ----------- 12 files changed, 65 insertions(+), 185 deletions(-) diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 9b796ce0c41..35dff0d8646 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -27,7 +27,8 @@ #include "memory/metaspaceUtils.hpp" #include "nmt/memBaseline.hpp" #include "nmt/memTracker.hpp" -#include "nmt/regionsTree.inline.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/safepoint.hpp" /* * Sizes are sorted in descenting order for reporting @@ -103,6 +104,38 @@ class MallocAllocationSiteWalker : public MallocSiteWalker { } }; +// Walk all virtual memory regions for baselining +class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { + private: + typedef LinkedListImpl EntryList; + EntryList _virtual_memory_regions; + DEBUG_ONLY(address _last_base;) + public: + VirtualMemoryAllocationWalker() { + DEBUG_ONLY(_last_base = nullptr); + } + + bool do_allocation_site(const ReservedMemoryRegion* rgn) { + assert(rgn->base() >= _last_base, "region unordered?"); + DEBUG_ONLY(_last_base = rgn->base()); + if (rgn->size() > 0) { + if (_virtual_memory_regions.add(*rgn) != nullptr) { + return true; + } else { + return false; + } + } else { + // Ignore empty sites. + return true; + } + } + + LinkedList* virtual_memory_allocations() { + return &_virtual_memory_regions; + } +}; + void MemBaseline::baseline_summary() { MallocMemorySummary::snapshot(&_malloc_memory_snapshot); VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); @@ -125,16 +158,15 @@ bool MemBaseline::baseline_allocation_sites() { // The malloc sites are collected in size order _malloc_sites_order = by_size; - assert(_vma_allocations == nullptr, "must"); - - { - MemTracker::NmtVirtualMemoryLocker locker; - _vma_allocations = new (mtNMT, std::nothrow) RegionsTree(*VirtualMemoryTracker::Instance::tree()); - if (_vma_allocations == nullptr) { - return false; - } + // Virtual memory allocation sites + VirtualMemoryAllocationWalker virtual_memory_walker; + if (!VirtualMemoryTracker::Instance::walk_virtual_memory(&virtual_memory_walker)) { + return false; } + // Virtual memory allocations are collected in call stack order + _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations()); + if (!aggregate_virtual_memory_allocation_sites()) { return false; } @@ -170,28 +202,20 @@ int compare_allocation_site(const VirtualMemoryAllocationSite& s1, bool MemBaseline::aggregate_virtual_memory_allocation_sites() { SortedLinkedList allocation_sites; + VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); + const ReservedMemoryRegion* rgn; VirtualMemoryAllocationSite* site; - bool failed_oom = false; - _vma_allocations->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { - VirtualMemoryAllocationSite tmp(*rgn.call_stack(), rgn.mem_tag()); + while ((rgn = itr.next()) != nullptr) { + VirtualMemoryAllocationSite tmp(*rgn->call_stack(), rgn->mem_tag()); site = allocation_sites.find(tmp); if (site == nullptr) { LinkedListNode* node = allocation_sites.add(tmp); - if (node == nullptr) { - failed_oom = true; - return false; - } + if (node == nullptr) return false; site = node->data(); } - site->reserve_memory(rgn.size()); - - site->commit_memory(_vma_allocations->committed_size(rgn)); - return true; - }); - - if (failed_oom) { - return false; + site->reserve_memory(rgn->size()); + site->commit_memory(VirtualMemoryTracker::Instance::committed_size(rgn)); } _virtual_memory_sites.move(&allocation_sites); diff --git a/src/hotspot/share/nmt/memBaseline.hpp b/src/hotspot/share/nmt/memBaseline.hpp index 3f1ea46d815..2fff4cc666c 100644 --- a/src/hotspot/share/nmt/memBaseline.hpp +++ b/src/hotspot/share/nmt/memBaseline.hpp @@ -35,6 +35,7 @@ typedef LinkedListIterator MallocSiteIterator; typedef LinkedListIterator VirtualMemorySiteIterator; +typedef LinkedListIterator VirtualMemoryAllocationIterator; /* * Baseline a memory snapshot @@ -70,7 +71,7 @@ class MemBaseline { LinkedListImpl _malloc_sites; // All virtual memory allocations - RegionsTree* _vma_allocations; + LinkedListImpl _virtual_memory_allocations; // Virtual memory allocations by allocation sites, always in by_address // order @@ -85,7 +86,6 @@ class MemBaseline { // create a memory baseline MemBaseline(): _instance_class_count(0), _array_class_count(0), _thread_count(0), - _vma_allocations(nullptr), _baseline_type(Not_baselined) { } @@ -110,9 +110,9 @@ class MemBaseline { // Virtual memory allocation iterator always returns in virtual memory // base address order. - RegionsTree* virtual_memory_allocations() { - assert(_vma_allocations != nullptr, "Not detail baseline"); - return _vma_allocations; + VirtualMemoryAllocationIterator virtual_memory_allocations() { + assert(!_virtual_memory_allocations.is_empty(), "Not detail baseline"); + return VirtualMemoryAllocationIterator(_virtual_memory_allocations.head()); } // Total reserved memory = total malloc'd memory + total reserved virtual @@ -185,8 +185,7 @@ class MemBaseline { _malloc_sites.clear(); _virtual_memory_sites.clear(); - delete _vma_allocations; - _vma_allocations = nullptr; + _virtual_memory_allocations.clear(); } private: diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 84f0f90f6e5..65d4d76942b 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -394,11 +394,13 @@ int MemDetailReporter::report_virtual_memory_allocation_sites() { void MemDetailReporter::report_virtual_memory_map() { // Virtual memory map always in base address order + VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations(); + const ReservedMemoryRegion* rgn; + output()->print_cr("Virtual memory map:"); - _baseline.virtual_memory_allocations()->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { - report_virtual_memory_region(&rgn); - return true; - }); + while ((rgn = itr.next()) != nullptr) { + report_virtual_memory_region(rgn); + } } void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) { diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp index 9a2ecd57ecc..3e5c1d2f0ea 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -57,21 +57,3 @@ NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_ NativeCallStackStorage::~NativeCallStackStorage() { FREE_C_HEAP_ARRAY(LinkPtr, _table); } - -NativeCallStackStorage::NativeCallStackStorage(const NativeCallStackStorage& other) - : _table_size(other._table_size), - _table(nullptr), - _stacks(), - _is_detailed_mode(other._is_detailed_mode), - _fake_stack(other._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] = other._table[i]; - } - } - _stacks.reserve(other._stacks.length()); - for (int i = 0; i < other._stacks.length(); i++) { - _stacks.at_grow(i) = other._stacks.at(i); - } -} diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 6ead8f49248..6f194cfa5a1 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -95,8 +95,7 @@ public: } NativeCallStackStorage(bool is_detailed_mode, int table_size = default_table_size); - NativeCallStackStorage(const NativeCallStackStorage& other); - NativeCallStackStorage& operator=(const NativeCallStackStorage& other) = delete; + ~NativeCallStackStorage(); }; diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index 8644a2d4731..370c69a2485 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -22,8 +22,6 @@ * */ #include "nmt/regionsTree.hpp" -#include "nmt/regionsTree.inline.hpp" -#include "nmt/virtualMemoryTracker.hpp" VMATree::SummaryDiff RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack) { return commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), /*use tag inplace*/ true); @@ -56,13 +54,4 @@ void RegionsTree::print_on(outputStream* st) { return true; }); } -#endif - -size_t RegionsTree::committed_size(ReservedMemoryRegion& rgn) { - size_t result = 0; - visit_committed_regions(rgn, [&](CommittedMemoryRegion& crgn) { - result += crgn.size(); - return true; - }); - return result; -} +#endif \ No newline at end of file diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index b0c5d928bab..bf2ab711b2d 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -40,12 +40,6 @@ class RegionsTree : public VMATree { public: RegionsTree(bool with_storage) : VMATree() , _ncs_storage(with_storage), _with_storage(with_storage) { } - RegionsTree(const RegionsTree& other) - : VMATree(other), - _ncs_storage(other._ncs_storage), - _with_storage(other._with_storage) {} - RegionsTree& operator=(const RegionsTree& other) = delete; - ReservedMemoryRegion find_reserved_region(address addr); SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); @@ -97,8 +91,6 @@ class RegionsTree : public VMATree { NativeCallStackStorage::StackIndex si = node.out_stack_index(); return _ncs_storage.get(si); } - - size_t committed_size(ReservedMemoryRegion& rgn); }; -#endif // NMT_REGIONSTREE_HPP +#endif // NMT_REGIONSTREE_HPP \ No newline at end of file diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 69887068cb2..4f6f8e12185 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -744,10 +744,3 @@ void VMATree::SummaryDiff::print_on(outputStream* out) { } } #endif - -void VMATree::clear() { - _tree.remove_all(); -}; -bool VMATree::is_empty() { - return _tree.size() == 0; -}; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 88b680a045c..1b5729054e4 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -30,7 +30,6 @@ #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" -#include "utilities/rbTree.hpp" #include "utilities/rbTree.inline.hpp" #include @@ -40,7 +39,7 @@ // For example, the state may go from released memory to committed memory, // or from committed memory of a certain MemTag to committed memory of a different MemTag. // The set of points is stored in a balanced binary tree for efficient querying and updating. -class VMATree : public CHeapObjBase { +class VMATree { friend class NMTVMATreeTest; friend class VMTWithVMATreeTest; // A position in memory. @@ -66,6 +65,7 @@ private: static const char* statetype_strings[static_cast(StateType::st_number_of_states)]; public: + NONCOPYABLE(VMATree); static const char* statetype_to_string(StateType type) { assert(type < StateType::st_number_of_states, "must be"); @@ -226,10 +226,6 @@ private: public: VMATree() : _tree() {} - VMATree(const VMATree& other) : _tree() { - assert(other._tree.copy_into(_tree), "VMATree dies on OOM"); - } - VMATree& operator=(VMATree const&) = delete; struct SingleDiff { using delta = int64_t; @@ -333,8 +329,5 @@ public: _tree.visit_range_in_order(from, to, f); } VMARBTree& tree() { return _tree; } - - void clear(); - bool is_empty(); }; #endif diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index fd0e25051f5..4c358b53ff0 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -428,7 +428,6 @@ public: template void visit_in_order(F f); - // Visit all RBNodes in ascending order whose keys are in range [from, to], calling f on each node. // If f returns `true` the iteration continues, otherwise it is stopped at the current node. template @@ -476,7 +475,6 @@ class RBTree : public AbstractRBTree, COMPARATOR> { public: RBTree() : BaseType(), _allocator() {} - NONCOPYABLE(RBTree); ~RBTree() { remove_all(); } RBTree(const RBTree& other) : BaseType(), _allocator() { assert(std::is_copy_constructible(), "Value type must be copy-constructible"); @@ -487,8 +485,6 @@ public: } RBTree& operator=(const RBTree& other) = delete; - bool copy_into(RBTree& other) const; - typedef typename BaseType::Cursor Cursor; using BaseType::cursor; using BaseType::insert_at_cursor; diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index b7de0a7ac4c..f28923eb867 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -753,53 +753,4 @@ void AbstractRBTree::print_on(outputStream* st, const P } } -template -bool RBTree::copy_into(RBTree& other) const { - assert(other.size() == 0, "You can only copy into an empty RBTree"); - assert(std::is_copy_constructible::value, "Key type must be copy-constructible when copying a RBTree"); - assert(std::is_copy_constructible::value, "Value type must be copy-constructible when copying a RBTree"); - enum class Dir { Left, Right }; - struct node_pair { const IntrusiveRBNode* current; IntrusiveRBNode* other_parent; Dir dir; }; - struct stack { - node_pair s[64]; - int idx = 0; - stack() : idx(0) {} - node_pair pop() { idx--; return s[idx]; }; - void push(node_pair n) { s[idx] = n; idx++; }; - bool is_empty() { return idx == 0; }; - }; - - stack visit_stack; - if (this->_root == nullptr) { - return true; - } - RBNode* root = static_cast*>(this->_root); - other._root = other.allocate_node(root->key(), root->val()); - if (other._root == nullptr) return false; - - visit_stack.push({this->_root->_left, other._root, Dir::Left}); - visit_stack.push({this->_root->_right, other._root, Dir::Right}); - while (!visit_stack.is_empty()) { - node_pair n = visit_stack.pop(); - const RBNode* current = static_cast*>(n.current); - if (current == nullptr) continue; - RBNode* new_node = other.allocate_node(current->key(), current->val()); - if (new_node == nullptr) { - return false; - } - if (n.dir == Dir::Left) { - n.other_parent->_left = new_node; - } else { - n.other_parent->_right = new_node; - } - new_node->set_parent(n.other_parent); - new_node->_parent |= n.current->_parent & 0x1; - visit_stack.push({n.current->_left, new_node, Dir::Left}); - visit_stack.push({n.current->_right, new_node, Dir::Right}); - } - other._num_nodes = this->_num_nodes; - DEBUG_ONLY(other._expected_visited = this->_expected_visited); - return true; -} - #endif // SHARE_UTILITIES_RBTREE_INLINE_HPP diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index a351e2141e8..ff234dd764a 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -1200,46 +1200,6 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { } } -TEST_VM_F(RBTreeTest, TestCopyInto) { - { - RBTreeInt rbtree1; - RBTreeInt rbtree2; - - rbtree1.copy_into(rbtree2); - rbtree2.verify_self(); - } - - RBTreeInt rbtree1; - RBTreeInt rbtree2; - - int size = 1000; - for (int i = 0; i < size; i++) { - rbtree1.upsert(i, i); - } - - rbtree1.copy_into(rbtree2); - rbtree2.verify_self(); - - ResourceMark rm; - GrowableArray allocations(size); - int size1 = 0; - rbtree1.visit_in_order([&](RBTreeIntNode* node) { - size1++; - allocations.append(node->key()); - return true; - }); - - int size2 = 0; - rbtree2.visit_in_order([&](RBTreeIntNode* node) { - EXPECT_EQ(node->key(), allocations.at(size2++)); - return true; - }); - - EXPECT_EQ(size1, size2); - EXPECT_EQ(rbtree1.size(), rbtree2.size()); - EXPECT_EQ(size2, static_cast(rbtree2.size())); -} - struct OomAllocator { void* allocate(size_t sz) { return nullptr; From cfb809344c0205875b35991ce6807333df41c949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Tue, 9 Sep 2025 09:01:46 +0000 Subject: [PATCH 192/295] 8364103: Convert existing sprintf-chains to stringStream Reviewed-by: kbarrett, dholmes, iklam --- src/hotspot/share/classfile/javaClasses.cpp | 69 +++++++-------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 8cc00d1feb9..3617f318b83 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -2583,85 +2583,64 @@ class BacktraceIterator : public StackObj { }; -// Print stack trace element to resource allocated buffer +// Print stack trace element to the specified output stream. +// The output is formatted into a stringStream and written to the outputStream in one step. static void print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id, int version, int bci, Symbol* name) { ResourceMark rm; + stringStream ss; - // Get strings and string lengths InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); const char* klass_name = holder->external_name(); - int buf_len = (int)strlen(klass_name); - char* method_name = name->as_C_string(); - buf_len += (int)strlen(method_name); + ss.print("\tat %s.%s(", klass_name, method_name); + + // Print module information + ModuleEntry* module = holder->module(); + if (module->is_named()) { + char* module_name = module->name()->as_C_string(); + if (module->version() != nullptr) { + char* module_version = module->version()->as_C_string(); + ss.print("%s@%s/", module_name, module_version); + } else { + ss.print("%s/", module_name); + } + } char* source_file_name = nullptr; Symbol* source = Backtrace::get_source_file_name(holder, version); if (source != nullptr) { source_file_name = source->as_C_string(); - buf_len += (int)strlen(source_file_name); - } - - char *module_name = nullptr, *module_version = nullptr; - ModuleEntry* module = holder->module(); - if (module->is_named()) { - module_name = module->name()->as_C_string(); - buf_len += (int)strlen(module_name); - if (module->version() != nullptr) { - module_version = module->version()->as_C_string(); - buf_len += (int)strlen(module_version); - } - } - - // Allocate temporary buffer with extra space for formatting and line number - const size_t buf_size = buf_len + 64; - char* buf = NEW_RESOURCE_ARRAY(char, buf_size); - - // Print stack trace line in buffer - int buf_off = os::snprintf(buf, buf_size, "\tat %s.%s(", klass_name, method_name); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); - // Print module information - if (module_name != nullptr) { - if (module_version != nullptr) { - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s@%s/", module_name, module_version); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); - } else { - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s/", module_name); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); - } } // The method can be null if the requested class version is gone Method* method = holder->method_with_orig_idnum(method_id, version); if (!version_matches(method, version)) { - strcat(buf, "Redefined)"); + ss.print("Redefined)"); } else { int line_number = Backtrace::get_line_number(method, bci); if (line_number == -2) { - strcat(buf, "Native Method)"); + ss.print("Native Method)"); } else { if (source_file_name != nullptr && (line_number != -1)) { // Sourcename and linenumber - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s:%d)", source_file_name, line_number); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); + ss.print("%s:%d)", source_file_name, line_number); } else if (source_file_name != nullptr) { // Just sourcename - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s)", source_file_name); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); + ss.print("%s)", source_file_name); } else { // Neither sourcename nor linenumber - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "Unknown Source)"); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); + ss.print("Unknown Source)"); } nmethod* nm = method->code(); if (WizardMode && nm != nullptr) { - os::snprintf_checked(buf + buf_off, buf_size - buf_off, "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); + ss.print("(nmethod " INTPTR_FORMAT ")", p2i(nm)); } } } - st->print_cr("%s", buf); + ss.cr(); + st->print_raw(ss.freeze(), ss.size()); } void java_lang_Throwable::print_stack_element(outputStream *st, Method* method, int bci) { From f51e442b0e26d0e9ebb6ec0da9584ba4f548322c Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 9 Sep 2025 09:29:23 +0000 Subject: [PATCH 193/295] 8367098: RISC-V: sync CPU features with related JVM flags for dependant ones Reviewed-by: fyang --- src/hotspot/cpu/riscv/vm_version_riscv.hpp | 40 ++++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index a0a42fb5463..188f7e0b1c3 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -86,25 +86,27 @@ class VM_Version : public Abstract_VM_Version { } \ } \ - #define UPDATE_DEFAULT_DEP(flag, dep) \ - void update_flag() { \ - assert(enabled(), "Must be."); \ - /* dep must be declared before */ \ - assert((uintptr_t)(this) > \ - (uintptr_t)(&dep), "Invalid");\ - if (FLAG_IS_DEFAULT(flag)) { \ - if (dep.enabled()) { \ - FLAG_SET_DEFAULT(flag, true); \ - } else { \ - FLAG_SET_DEFAULT(flag, false); \ - } \ - } else { \ - /* Sync CPU features with flags */ \ - if (!flag) { \ - disable_feature(); \ - } \ - } \ - } \ + #define UPDATE_DEFAULT_DEP(flag, dep) \ + void update_flag() { \ + assert(enabled(), "Must be."); \ + /* dep must be declared before */ \ + assert((uintptr_t)(this) > \ + (uintptr_t)(&dep), "Invalid"); \ + if (FLAG_IS_DEFAULT(flag)) { \ + if (dep.enabled()) { \ + FLAG_SET_DEFAULT(flag, true); \ + } else { \ + FLAG_SET_DEFAULT(flag, false); \ + /* Sync CPU features with flags */ \ + disable_feature(); \ + } \ + } else { \ + /* Sync CPU features with flags */ \ + if (!flag) { \ + disable_feature(); \ + } \ + } \ + } \ #define NO_UPDATE_DEFAULT \ void update_flag() {} \ From 4fc917c25005d1f88fe43069fe623e243bd022c3 Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Tue, 9 Sep 2025 10:15:53 +0000 Subject: [PATCH 194/295] 8366486: Test jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java is timing out Reviewed-by: jbachorik --- .../profiling/TestCPUTimeSampleMultipleRecordings.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java index 976d08f1250..efc4da28021 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java @@ -39,20 +39,15 @@ import jdk.test.lib.jfr.EventNames; * @run main/timeout=480 jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings */ public class TestCPUTimeSampleMultipleRecordings { - - static String nativeEvent = EventNames.CPUTimeSample; - static volatile boolean alive = true; public static void main(String[] args) throws Exception { Thread t = new Thread(TestCPUTimeSampleMultipleRecordings::nativeMethod); - t.setDaemon(true); t.start(); for (int i = 0; i < 2; i++) { try (RecordingStream rs = new RecordingStream()) { - rs.enable(nativeEvent).with("throttle", "1ms"); - rs.onEvent(nativeEvent, e -> { - alive = false; + rs.enable(EventNames.CPUTimeSample).with("throttle", "1ms"); + rs.onEvent(EventNames.CPUTimeSample, e -> { rs.close(); }); @@ -60,6 +55,7 @@ public class TestCPUTimeSampleMultipleRecordings { } } alive = false; + t.join(); } public static void nativeMethod() { From 002f936ef21943ff1c8c03618091793768e756ac Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Tue, 9 Sep 2025 10:16:22 +0000 Subject: [PATCH 195/295] 8366082: Improve queue size computation in CPU-time sampler Reviewed-by: jbachorik --- .../sampling/jfrCPUTimeThreadSampler.cpp | 101 +++++++++--- .../sampling/jfrCPUTimeThreadSampler.hpp | 20 ++- .../periodic/sampling/jfrThreadSampling.cpp | 1 + .../share/jfr/support/jfrThreadLocal.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 30 ++++ .../TestCPUTimeSampleQueueAutoSizes.java | 154 ++++++++++++++++++ test/lib/jdk/test/whitebox/WhiteBox.java | 7 + 7 files changed, 292 insertions(+), 23 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index db3ca758cc1..579710a62a7 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -25,7 +25,6 @@ #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "logging/log.hpp" - #if defined(LINUX) #include "jfr/periodic/sampling/jfrThreadSampling.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -67,7 +66,7 @@ static JavaThread* get_java_thread_if_valid() { } JfrCPUTimeTraceQueue::JfrCPUTimeTraceQueue(u4 capacity) : - _data(nullptr), _capacity(capacity), _head(0), _lost_samples(0) { + _data(nullptr), _capacity(capacity), _head(0), _lost_samples(0), _lost_samples_due_to_queue_full(0) { if (capacity != 0) { _data = JfrCHeapObj::new_array(capacity); } @@ -110,10 +109,13 @@ void JfrCPUTimeTraceQueue::set_size(u4 size) { } u4 JfrCPUTimeTraceQueue::capacity() const { - return _capacity; + return Atomic::load_acquire(&_capacity); } void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { + if (capacity == Atomic::load(&_capacity)) { + return; + } _head = 0; if (_data != nullptr) { assert(_capacity != 0, "invariant"); @@ -124,7 +126,7 @@ void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { } else { _data = nullptr; } - _capacity = capacity; + Atomic::release_store(&_capacity, capacity); } bool JfrCPUTimeTraceQueue::is_empty() const { @@ -140,28 +142,51 @@ void JfrCPUTimeTraceQueue::increment_lost_samples() { Atomic::inc(&_lost_samples); } +void JfrCPUTimeTraceQueue::increment_lost_samples_due_to_queue_full() { + Atomic::inc(&_lost_samples_due_to_queue_full); +} + u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples() { return Atomic::xchg(&_lost_samples, (u4)0); } -void JfrCPUTimeTraceQueue::resize(u4 capacity) { - if (capacity != _capacity) { - set_capacity(capacity); - } +u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples_due_to_queue_full() { + return Atomic::xchg(&_lost_samples_due_to_queue_full, (u4)0); } -void JfrCPUTimeTraceQueue::resize_for_period(u4 period_millis) { - u4 capacity = CPU_TIME_QUEUE_CAPACITY; - if (period_millis > 0 && period_millis < 10) { - capacity = (u4) ((double) capacity * 10 / period_millis); - } - resize(capacity); +void JfrCPUTimeTraceQueue::init() { + set_capacity(JfrCPUTimeTraceQueue::CPU_TIME_QUEUE_INITIAL_CAPACITY); } void JfrCPUTimeTraceQueue::clear() { Atomic::release_store(&_head, (u4)0); } +void JfrCPUTimeTraceQueue::resize_if_needed() { + u4 lost_samples_due_to_queue_full = get_and_reset_lost_samples_due_to_queue_full(); + if (lost_samples_due_to_queue_full == 0) { + return; + } + u4 capacity = Atomic::load(&_capacity); + if (capacity < CPU_TIME_QUEUE_MAX_CAPACITY) { + float ratio = (float)lost_samples_due_to_queue_full / (float)capacity; + int factor = 1; + if (ratio > 8) { // idea is to quickly scale the queue in the worst case + factor = ratio; + } else if (ratio > 2) { + factor = 8; + } else if (ratio > 0.5) { + factor = 4; + } else if (ratio > 0.01) { + factor = 2; + } + if (factor > 1) { + u4 new_capacity = MIN2(CPU_TIME_QUEUE_MAX_CAPACITY, capacity * factor); + set_capacity(new_capacity); + } + } +} + // A throttle is either a rate or a fixed period class JfrCPUSamplerThrottle { @@ -205,6 +230,8 @@ class JfrCPUSamplerThread : public NonJavaThread { volatile bool _is_async_processing_of_cpu_time_jfr_requests_triggered; volatile bool _warned_about_timer_creation_failure; volatile bool _signal_handler_installed; + DEBUG_ONLY(volatile bool _out_of_stack_walking_enabled;) + DEBUG_ONLY(volatile u8 _out_of_stack_walking_iterations;) static const u4 STOP_SIGNAL_BIT = 0x80000000; @@ -250,6 +277,16 @@ public: void stop_timer(); void trigger_async_processing_of_cpu_time_jfr_requests(); + + #ifdef ASSERT + void set_out_of_stack_walking_enabled(bool runnable) { + Atomic::release_store(&_out_of_stack_walking_enabled, runnable); + } + + u8 out_of_stack_walking_iterations() const { + return Atomic::load(&_out_of_stack_walking_iterations); + } + #endif }; JfrCPUSamplerThread::JfrCPUSamplerThread(JfrCPUSamplerThrottle& throttle) : @@ -275,7 +312,7 @@ void JfrCPUSamplerThread::on_javathread_create(JavaThread* thread) { } JfrThreadLocal* tl = thread->jfr_thread_local(); assert(tl != nullptr, "invariant"); - tl->cpu_time_jfr_queue().resize_for_period(_current_sampling_period_ns / 1000000); + tl->cpu_time_jfr_queue().init(); timer_t timerid; if (create_timer_for_thread(thread, timerid)) { tl->set_cpu_timer(&timerid); @@ -294,12 +331,14 @@ void JfrCPUSamplerThread::on_javathread_terminate(JavaThread* thread) { if (timer == nullptr) { return; // no timer was created for this thread } + tl->acquire_cpu_time_jfr_dequeue_lock(); tl->unset_cpu_timer(); tl->deallocate_cpu_time_jfr_queue(); s4 lost_samples = tl->cpu_time_jfr_queue().lost_samples(); if (lost_samples > 0) { JfrCPUTimeThreadSampling::send_lost_event(JfrTicks::now(), JfrThreadLocal::thread_id(thread), lost_samples); } + tl->release_cpu_time_jfr_queue_lock(); } void JfrCPUSamplerThread::start_thread() { @@ -352,10 +391,12 @@ void JfrCPUSamplerThread::run() { recompute_period_if_needed(); last_recompute_check = os::javaTimeNanos(); } - - if (Atomic::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) { - stackwalk_threads_in_native(); - } + DEBUG_ONLY(if (Atomic::load_acquire(&_out_of_stack_walking_enabled)) {) + if (Atomic::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) { + DEBUG_ONLY(Atomic::inc(&_out_of_stack_walking_iterations);) + stackwalk_threads_in_native(); + } + DEBUG_ONLY(}) os::naked_sleep(100); } } @@ -545,6 +586,21 @@ void JfrCPUTimeThreadSampling::handle_timer_signal(siginfo_t* info, void* contex _sampler->decrement_signal_handler_count(); } +#ifdef ASSERT +void JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { + if (_instance != nullptr && _instance->_sampler != nullptr) { + _instance->_sampler->set_out_of_stack_walking_enabled(runnable); + } +} + +u8 JfrCPUTimeThreadSampling::out_of_stack_walking_iterations() { + if (_instance != nullptr && _instance->_sampler != nullptr) { + return _instance->_sampler->out_of_stack_walking_iterations(); + } + return 0; +} +#endif + void JfrCPUSamplerThread::sample_thread(JfrSampleRequest& request, void* ucontext, JavaThread* jt, JfrThreadLocal* tl, JfrTicks& now) { JfrSampleRequestBuilder::build_cpu_time_sample_request(request, ucontext, jt, jt->jfr_thread_local(), now); } @@ -590,6 +646,7 @@ void JfrCPUSamplerThread::handle_timer_signal(siginfo_t* info, void* context) { } } else { queue.increment_lost_samples(); + queue.increment_lost_samples_due_to_queue_full(); } if (jt->thread_state() == _thread_in_native) { @@ -807,4 +864,10 @@ void JfrCPUTimeThreadSampling::on_javathread_create(JavaThread* thread) { void JfrCPUTimeThreadSampling::on_javathread_terminate(JavaThread* thread) { } +#ifdef ASSERT +static void set_out_of_stack_walking_enabled(bool runnable) { + warn(); +} +#endif + #endif // defined(LINUX) && defined(INCLUDE_JFR) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp index dae0be5c3a7..e17e63fc3ed 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp @@ -50,12 +50,15 @@ class JfrCPUTimeTraceQueue { static const u4 CPU_TIME_QUEUE_CAPACITY = 500; JfrCPUTimeSampleRequest* _data; - u4 _capacity; + volatile u4 _capacity; // next unfilled index volatile u4 _head; volatile u4 _lost_samples; + volatile u4 _lost_samples_due_to_queue_full; + static const u4 CPU_TIME_QUEUE_INITIAL_CAPACITY = 20; + static const u4 CPU_TIME_QUEUE_MAX_CAPACITY = 2000; public: JfrCPUTimeTraceQueue(u4 capacity); @@ -81,12 +84,17 @@ public: void increment_lost_samples(); + void increment_lost_samples_due_to_queue_full(); + // returns the previous lost samples count u4 get_and_reset_lost_samples(); - void resize(u4 capacity); + u4 get_and_reset_lost_samples_due_to_queue_full(); - void resize_for_period(u4 period_millis); + void resize_if_needed(); + + // init the queue capacity + void init(); void clear(); @@ -130,6 +138,10 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj { static void send_lost_event(const JfrTicks& time, traceid tid, s4 lost_samples); static void trigger_async_processing_of_cpu_time_jfr_requests(); + + DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable);) + + DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) }; #else @@ -150,6 +162,8 @@ private: static void on_javathread_create(JavaThread* thread); static void on_javathread_terminate(JavaThread* thread); + DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable)); + DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) }; #endif // defined(LINUX) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp index ddc9d59b295..f7a725fce6d 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp @@ -368,6 +368,7 @@ static void drain_enqueued_cpu_time_requests(const JfrTicks& now, JfrThreadLocal tl->set_has_cpu_time_jfr_requests(false); if (queue.lost_samples() > 0) { JfrCPUTimeThreadSampling::send_lost_event( now, JfrThreadLocal::thread_id(jt), queue.get_and_reset_lost_samples()); + queue.resize_if_needed(); } if (lock) { tl->release_cpu_time_jfr_queue_lock(); diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp index 291169b9aa7..037faee1b9f 100644 --- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp +++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp @@ -656,7 +656,7 @@ JfrCPUTimeTraceQueue& JfrThreadLocal::cpu_time_jfr_queue() { } void JfrThreadLocal::deallocate_cpu_time_jfr_queue() { - cpu_time_jfr_queue().resize(0); + cpu_time_jfr_queue().set_capacity(0); } void JfrThreadLocal::set_do_async_processing_of_cpu_time_jfr_requests(bool wants) { diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index cbb135a82d9..4b3583edf51 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -46,6 +46,7 @@ #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/gcConfig.hpp" #include "gc/shared/genArguments.hpp" +#include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jvm.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" @@ -2660,6 +2661,32 @@ WB_ENTRY(void, WB_WaitUnsafe(JNIEnv* env, jobject wb, jint time)) os::naked_short_sleep(time); WB_END +WB_ENTRY(void, WB_BusyWait(JNIEnv* env, jobject wb, jint time)) + ThreadToNativeFromVM ttn(thread); + u8 start = os::current_thread_cpu_time(); + u8 target_duration = time * (u8)1000000; + while (os::current_thread_cpu_time() - start < target_duration) { + for (volatile int i = 0; i < 1000000; i++); + } +WB_END + +WB_ENTRY(jboolean, WB_CPUSamplerSetOutOfStackWalking(JNIEnv* env, jobject wb, jboolean enable)) + #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) + JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(enable == JNI_TRUE); + return JNI_TRUE; + #else + return JNI_FALSE; + #endif +WB_END + +WB_ENTRY(jlong, WB_CPUSamplerOutOfStackWalkingIterations(JNIEnv* env, jobject wb)) + #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) + return (jlong)JfrCPUTimeThreadSampling::out_of_stack_walking_iterations(); + #else + return 0; + #endif +WB_END + WB_ENTRY(jstring, WB_GetLibcName(JNIEnv* env, jobject o)) ThreadToNativeFromVM ttn(thread); jstring info_string = env->NewStringUTF(XSTR(LIBC)); @@ -3013,6 +3040,9 @@ static JNINativeMethod methods[] = { {CC"isJVMTIIncluded", CC"()Z", (void*)&WB_IsJVMTIIncluded}, {CC"waitUnsafe", CC"(I)V", (void*)&WB_WaitUnsafe}, + {CC"busyWait", CC"(I)V", (void*)&WB_BusyWait}, + {CC"cpuSamplerSetOutOfStackWalking", CC"(Z)Z", (void*)&WB_CPUSamplerSetOutOfStackWalking}, + {CC"cpuSamplerOutOfStackWalkingIterations", CC"()J",(void*)&WB_CPUSamplerOutOfStackWalkingIterations}, {CC"getLibcName", CC"()Ljava/lang/String;", (void*)&WB_GetLibcName}, {CC"pinObject", CC"(Ljava/lang/Object;)V", (void*)&WB_PinObject}, diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java new file mode 100644 index 00000000000..1ea96e3bad3 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025 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. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.stream.Collectors; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.internal.JVM; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.whitebox.WhiteBox; + + +/* + * Tests the sample queues increase in size as needed, when loss is recorded. + * @test + * @requires vm.hasJFR & os.family == "linux" & vm.debug + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @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 + * -Xbatch -XX:StartFlightRecording:dumponexit=true jdk.jfr.event.profiling.TestCPUTimeSampleQueueAutoSizes + */ +public class TestCPUTimeSampleQueueAutoSizes { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static final String BURST_THREAD_NAME = "Burst-Thread-1"; + + static volatile boolean alive = true; + + record LossEvent(long relativeTimeMillis, long lostSamples) {} + + /** A data collection from the CPUTimeSampleLost events for the burst thread */ + static class LossEventCollection { + private final List events = new ArrayList<>(); + + public synchronized void addEvent(LossEvent event) { + events.add(event); + } + + public synchronized List getSortedEvents() { + return events.stream() + .sorted(Comparator.comparingLong(e -> e.relativeTimeMillis)) + .collect(Collectors.toList()); + } + + public List getEventsPerInterval(long widthMillis, long stopTimeMillis) { + List ret = new ArrayList<>(); + for (long start = 0; start < stopTimeMillis; start += widthMillis) { + long actualStart = Math.min(start, stopTimeMillis - widthMillis); + long lostSamples = events.stream() + .filter(e -> e.relativeTimeMillis >= actualStart && e.relativeTimeMillis < actualStart + widthMillis) + .mapToLong(e -> e.lostSamples) + .sum(); + ret.add(new LossEvent(actualStart, lostSamples)); + } + return ret; + } + + } + + public static void main(String[] args) throws Exception { + try (RecordingStream rs = new RecordingStream()) { + // setup recording + AtomicLong firstSampleTimeMillis = new AtomicLong(0); + AtomicLong lastSampleTimeMillis = new AtomicLong(0); + LossEventCollection lossEvents = new LossEventCollection(); + rs.enable(EventNames.CPUTimeSample).with("throttle", "1ms"); + rs.onEvent(EventNames.CPUTimeSample, e -> { + if (firstSampleTimeMillis.get() == 0 && e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + firstSampleTimeMillis.set(e.getStartTime().toEpochMilli()); + } + if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + lastSampleTimeMillis.set(e.getStartTime().toEpochMilli()); + } + }); + rs.enable(EventNames.CPUTimeSamplesLost); + rs.onEvent(EventNames.CPUTimeSamplesLost, e -> { + if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + long eventTime = e.getStartTime().toEpochMilli(); + long relativeTime = firstSampleTimeMillis.get() > 0 ? (eventTime - firstSampleTimeMillis.get()) : eventTime; + System.out.println("Lost samples: " + e.getLong("lostSamples") + " at " + relativeTime); + lossEvents.addEvent(new LossEvent(relativeTime, e.getLong("lostSamples"))); + } + }); + WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); + rs.startAsync(); + // this thread runs all along + Thread burstThread = new Thread(() -> WHITE_BOX.busyWait(11000)); + burstThread.setName(BURST_THREAD_NAME); + burstThread.start(); + // now we toggle out-of-stack-walking off, wait 1 second and then turn it on for 500ms a few times + for (int i = 0; i < 5; i++) { + boolean supported = WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); + if (!supported) { + System.out.println("Out-of-stack-walking not supported, skipping test"); + Asserts.assertFalse(true); + return; + } + Thread.sleep(700); + long iterations = WHITE_BOX.cpuSamplerOutOfStackWalkingIterations(); + WHITE_BOX.cpuSamplerSetOutOfStackWalking(true); + Thread.sleep(300); + while (WHITE_BOX.cpuSamplerOutOfStackWalkingIterations() == iterations) { + Thread.sleep(50); // just to make sure the stack walking really ran + } + } + rs.close(); + checkThatLossDecreased(lossEvents, lastSampleTimeMillis.get() - firstSampleTimeMillis.get()); + } + } + + static void checkThatLossDecreased(LossEventCollection lossEvents, long lastSampleTimeMillis) { + List intervalLosses = lossEvents.getEventsPerInterval(1000, lastSampleTimeMillis); + for (LossEvent interval : intervalLosses) { + System.out.println("Lost samples in interval " + interval.relativeTimeMillis + ": " + interval.lostSamples); + } + // check that there are at least 3 intervals + Asserts.assertTrue(intervalLosses.size() > 2); + // check that the second to last interval has far fewer lost samples than the first + Asserts.assertTrue(intervalLosses.get(intervalLosses.size() - 2).lostSamples < + intervalLosses.get(0).lostSamples / 2); + } +} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index ce8b61b6393..5adb7bf5127 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -841,6 +841,13 @@ public class WhiteBox { public native void waitUnsafe(int time_ms); + public native void busyWait(int cpuTimeMs); + + // returns true if supported, false if not + public native boolean cpuSamplerSetOutOfStackWalking(boolean enable); + + public native long cpuSamplerOutOfStackWalkingIterations(); + public native void pinObject(Object o); public native void unpinObject(Object o); From a25dde6279c100dcff266d19b263e764f5da244e Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 9 Sep 2025 10:58:21 +0000 Subject: [PATCH 196/295] 8365231: Don't build gtest with /EHsc Reviewed-by: kbarrett, stuefe --- make/hotspot/lib/CompileGtest.gmk | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index d2cdc7685c9..30d3e3b524c 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -62,13 +62,13 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ DISABLED_WARNINGS_gcc := format-nonliteral maybe-uninitialized undef \ unused-result zero-as-null-pointer-constant, \ DISABLED_WARNINGS_clang := format-nonliteral undef unused-result, \ + DISABLED_WARNINGS_microsoft := 4530, \ DEFAULT_CFLAGS := false, \ CFLAGS := $(JVM_CFLAGS) \ -I$(GTEST_FRAMEWORK_SRC)/googletest \ -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ -I$(GTEST_FRAMEWORK_SRC)/googlemock \ -I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \ - CFLAGS_windows := -EHsc, \ CFLAGS_macosx := -DGTEST_OS_MAC=1, \ OPTIMIZATION := $(JVM_OPTIMIZATION), \ COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \ @@ -98,7 +98,6 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ -I$(GTEST_FRAMEWORK_SRC)/googlemock/include \ $(addprefix -I, $(GTEST_TEST_SRC)), \ - CFLAGS_windows := -EHsc, \ CFLAGS_macosx := -DGTEST_OS_MAC=1, \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \ undef stringop-overflow, \ @@ -110,7 +109,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ self-assign-overloaded, \ DISABLED_WARNINGS_clang_test_g1ServiceThread.cpp := delete-abstract-non-virtual-dtor, \ DISABLED_WARNINGS_clang_test_logDecorations.cpp := missing-field-initializers, \ - DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft), \ + DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) 4530, \ LD_SET_ORIGIN := false, \ DEFAULT_LDFLAGS := false, \ LDFLAGS := $(JVM_LDFLAGS), \ From a1ab12b77266c7124a297e1b2e0a8608b8facb2a Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 9 Sep 2025 11:17:33 +0000 Subject: [PATCH 197/295] 8366854: Extend jtreg failure handler with THP info Reviewed-by: ayang, shade, tschatzl, lmesnik, sjohanss --- test/failure_handler/src/share/conf/linux.properties | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/failure_handler/src/share/conf/linux.properties b/test/failure_handler/src/share/conf/linux.properties index 44d96620ad0..08e4ea8bd87 100644 --- a/test/failure_handler/src/share/conf/linux.properties +++ b/test/failure_handler/src/share/conf/linux.properties @@ -78,6 +78,8 @@ environment=\ process.top process.ps \ memory.free memory.vmstat.default memory.vmstat.statistics \ memory.vmstat.slabinfo memory.vmstat.disk \ + memory.proc_meminfo memory.proc_vmstat \ + memory.thp \ files \ locks \ net.sockets net.statistics net.ifconfig net.hostsfile \ @@ -115,6 +117,15 @@ memory.vmstat.default.args=3 3 memory.vmstat.statistics.args=-s memory.vmstat.slabinfo.args=-m memory.vmstat.disk.args=-d +memory.proc_meminfo.app=bash +memory.proc_meminfo.args=-c\0cat /proc/meminfo +memory.proc_meminfo.delimiter=\0 +memory.proc_vmstat.app=bash +memory.proc_vmstat.args=-c\0cat /proc/vmstat +memory.proc_vmstat.delimiter=\0 +memory.thp.app=bash +memory.thp.args=-c\0cat /sys/kernel/mm/transparent_hugepage/{enabled,defrag,shmem_enabled} +memory.thp.delimiter=\0 files.app=lsof locks.app=lslocks From 0632617670f991da23c3892d357e8d1f051d29a0 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 9 Sep 2025 11:17:48 +0000 Subject: [PATCH 198/295] 8367135: Test compiler/loopstripmining/CheckLoopStripMining.java needs internal timeouts adjusted Reviewed-by: thartmann, chagedorn --- .../compiler/loopstripmining/CheckLoopStripMining.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java index cdbf5affd01..3ed50619f77 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java @@ -42,8 +42,8 @@ public class CheckLoopStripMining { "-XX:+SafepointTimeout", "-XX:+SafepointALot", "-XX:+AbortVMOnSafepointTimeout", - "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(300), - "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(300), + "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(1200), + "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(1200), "-XX:-TieredCompilation", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", @@ -58,8 +58,8 @@ public class CheckLoopStripMining { "-XX:+SafepointTimeout", "-XX:+SafepointALot", "-XX:+AbortVMOnSafepointTimeout", - "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(300), - "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(300), + "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(1200), + "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(1200), "-XX:-TieredCompilation", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", From f10c85fbc336f6908a4f1ecae9fb5ab52984f636 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 9 Sep 2025 13:13:08 +0000 Subject: [PATCH 199/295] 8367027: java/lang/ProcessBuilder/Basic.java fails on Windows AArch64 Reviewed-by: rriggs --- test/jdk/java/lang/ProcessBuilder/Basic.java | 25 ++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index c06ecbdb871..551a4869e86 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -212,7 +212,7 @@ public class Basic { private static String winEnvFilter(String env) { return env.replaceAll("\r", "") - .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n",""); + .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT|PROCESSOR_ARCHITECTURE)=.*\n",""); } private static String unixEnvProg() { @@ -811,6 +811,14 @@ public class Basic { return vars.replace("AIXTHREAD_GUARDPAGES=0,", ""); } + /* Only used for Windows AArch64 -- + * Windows AArch64 adds the variable PROCESSOR_ARCHITECTURE=ARM64 to the environment. + * Remove it from the list of env variables + */ + private static String removeWindowsAArch64ExpectedVars(String vars) { + return vars.replace("PROCESSOR_ARCHITECTURE=ARM64,", ""); + } + private static String sortByLinesWindowsly(String text) { String[] lines = text.split("\n"); Arrays.sort(lines, new WindowsComparator()); @@ -1321,6 +1329,9 @@ public class Basic { if (AIX.is()) { result = removeAixExpectedVars(result); } + if (Windows.is() && Platform.isAArch64()) { + result = removeWindowsAArch64ExpectedVars(result); + } equal(result, expected); } catch (Throwable t) { unexpected(t); } @@ -1833,6 +1844,9 @@ public class Basic { if (AIX.is()) { commandOutput = removeAixExpectedVars(commandOutput); } + if (Windows.is() && Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } equal(commandOutput, expected); if (Windows.is()) { ProcessBuilder pb = new ProcessBuilder(childArgs); @@ -1840,7 +1854,11 @@ public class Basic { pb.environment().put("SystemRoot", systemRoot); pb.environment().put("=ExitValue", "3"); pb.environment().put("=C:", "\\"); - equal(commandOutput(pb), expected); + commandOutput = commandOutput(pb); + if (Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } + equal(commandOutput, expected); } } catch (Throwable t) { unexpected(t); } @@ -1892,6 +1910,9 @@ public class Basic { if (AIX.is()) { commandOutput = removeAixExpectedVars(commandOutput); } + if (Windows.is() && Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } check(commandOutput.equals(Windows.is() ? "LC_ALL=C,SystemRoot="+systemRoot+"," : AIX.is() From b653ae92d5941202780873fad1a7cefd51e4e7a8 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Sep 2025 15:02:54 +0000 Subject: [PATCH 200/295] 8367051: Build failure with clang on linux and AIX after switch to C++17 Reviewed-by: dholmes, ayang, mbaesken, mdoerr --- src/hotspot/share/utilities/forbiddenFunctions.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp index a8dcba95a6d..871fff5b727 100644 --- a/src/hotspot/share/utilities/forbiddenFunctions.hpp +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -38,6 +38,15 @@ #include #endif +// Workaround for noexcept functions in glibc when using clang. +// clang errors if declaration without exception specification preceeds +// noexcept declaration, but not the other way around. +#ifdef __clang__ +#include +#include +#include +#endif + #ifdef _WINDOWS #include "forbiddenFunctions_windows.hpp" #else From cc6d34b2fa299a68a05e65e25c1f41dffa67c118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 9 Sep 2025 15:08:30 +0000 Subject: [PATCH 201/295] 8366971: C2: Remove unused nop_list from PhaseOutput::init_buffer Reviewed-by: epeter, dlong --- src/hotspot/cpu/aarch64/aarch64.ad | 3 --- src/hotspot/cpu/arm/arm.ad | 3 --- src/hotspot/cpu/ppc/ppc.ad | 4 ---- src/hotspot/cpu/riscv/riscv.ad | 3 --- src/hotspot/cpu/x86/x86_64.ad | 3 --- src/hotspot/share/adlc/adlparse.cpp | 32 ++--------------------------- src/hotspot/share/adlc/formsopt.cpp | 8 +------- src/hotspot/share/adlc/formsopt.hpp | 5 +---- src/hotspot/share/adlc/output_c.cpp | 14 +------------ src/hotspot/share/adlc/output_h.cpp | 6 ------ src/hotspot/share/opto/output.cpp | 7 +------ 11 files changed, 6 insertions(+), 82 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 33466453b76..e0459716122 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -5965,9 +5965,6 @@ attributes %{ instruction_unit_size = 4; // An instruction is 4 bytes long instruction_fetch_unit_size = 64; // The processor fetches one line instruction_fetch_units = 1; // of 64 bytes - - // List of nop instructions - nops( MachNop ); %} // We don't use an actual pipeline model so don't care about resources diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 3b6faa6c81a..45d51aaac57 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -2638,9 +2638,6 @@ attributes %{ instruction_unit_size = 4; // An instruction is 4 bytes long instruction_fetch_unit_size = 16; // The processor fetches one line instruction_fetch_units = 1; // of 16 bytes - - // List of nop instructions - nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR ); %} //----------RESOURCES---------------------------------------------------------- diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index cd71e298b7d..290369360fc 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -4920,10 +4920,6 @@ attributes %{ // ...in one line instruction_fetch_units = 1 - - // Unused, list one so that array generated by adlc is not empty. - // Aix compiler chokes if _nop_count = 0. - nops(fxNop); %} //----------RESOURCES---------------------------------------------------------- diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index eab19e74f93..0c4dd7b71e2 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -3845,9 +3845,6 @@ attributes %{ // ...in one line. instruction_fetch_units = 1; - - // List of nop instructions - nops( MachNop ); %} // We don't use an actual pipeline model so don't care about resources diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 932dc9e1ca7..0914bea82a1 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -3429,9 +3429,6 @@ attributes %{ instruction_unit_size = 1; // An instruction is 1 bytes long instruction_fetch_unit_size = 16; // The processor fetches one line instruction_fetch_units = 1; // of 16 bytes - - // List of nop instructions - nops( MachNop ); %} //----------RESOURCES---------------------------------------------------------- diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index 033e8d26ca7..15dbf070674 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1507,36 +1507,8 @@ void ADLParser::pipe_parse(void) { } if (!strcmp(ident, "nops")) { + parse_err(WARN, "Using obsolete token, nops"); skipws(); - if (_curchar != '(') { - parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar); - break; - } - - next_char(); skipws(); - - while (_curchar != ')') { - ident = get_ident(); - if (ident == nullptr) { - parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar); - break; - } - - pipeline->_noplist.addName(ident); - pipeline->_nopcnt++; - skipws(); - - if (_curchar == ',') { - next_char(); skipws(); - } - } - - next_char(); skipws(); - - if (_curchar == ';') { - next_char(); skipws(); - } - continue; } diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 5de8974e2c0..01fe6288c53 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -511,8 +511,6 @@ PipelineForm::PipelineForm() , _stagecnt (0) , _classlist () , _classcnt (0) - , _noplist () - , _nopcnt (0) , _variableSizeInstrs (false) , _branchHasDelaySlot (false) , _maxInstrsPerBundle (0) @@ -533,7 +531,6 @@ void PipelineForm::output(FILE *fp) { // Write info to output files const char *res; const char *stage; const char *cls; - const char *nop; int count = 0; fprintf(fp,"\nPipeline:"); @@ -574,9 +571,6 @@ void PipelineForm::output(FILE *fp) { // Write info to output files for ( _classlist.reset(); (cls = _classlist.iter()) != nullptr; ) _classdict[cls]->is_pipeclass()->output(fp); - fprintf(fp,"\nNop Instructions:"); - for ( _noplist.reset(); (nop = _noplist.iter()) != nullptr; ) - fprintf(fp, " \"%s\"", nop); fprintf(fp,"\n"); } diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index d183a46b875..db7b9dbd8d8 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -386,9 +386,6 @@ public: FormDict _classdict; // Class Name -> PipeClassForm mapping int _classcnt; // Number of classes - NameList _noplist; // List of NOP instructions - int _nopcnt; // Number of nop instructions - bool _variableSizeInstrs; // Indicates if this architecture has variable sized instructions bool _branchHasDelaySlot; // Indicates that branches have delay slot instructions int _maxInstrsPerBundle; // Indicates the maximum number of instructions for ILP diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 0620f2f4496..abebf39a2b2 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -977,18 +977,6 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { } fprintf(fp_cpp, "}\n\n"); - // Output the list of nop nodes - fprintf(fp_cpp, "// Descriptions for emitting different functional unit nops\n"); - const char *nop; - int nopcnt = 0; - for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != nullptr; nopcnt++ ); - - fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d]) {\n", nopcnt); - int i = 0; - for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != nullptr; i++ ) { - fprintf(fp_cpp, " nop_list[%d] = (MachNode *) new %sNode();\n", i, nop); - } - fprintf(fp_cpp, "};\n\n"); fprintf(fp_cpp, "#ifndef PRODUCT\n"); fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n"); fprintf(fp_cpp, " static const char * bundle_flags[] = {\n"); @@ -1004,7 +992,7 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount); // Don't add compound resources to the list of resource names const char* resource; - i = 0; + int i = 0; for (_pipeline->_reslist.reset(); (resource = _pipeline->_reslist.iter()) != nullptr;) { if (_pipeline->_resdict[resource]->is_resource()->is_discrete()) { fprintf(fp_cpp, " \"%s\"%c", resource, i < _pipeline->_rescount - 1 ? ',' : ' '); diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index cbcc00efa3b..78cf5ea7988 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -1115,12 +1115,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " bool use_delay() { return ((_flags & _use_delay) != 0); }\n"); fprintf(fp_hpp, " bool used_in_delay() { return ((_flags & _used_in_delay) != 0); }\n\n"); - fprintf(fp_hpp, " enum {\n"); - fprintf(fp_hpp, " _nop_count = %d\n", - _pipeline->_nopcnt); - fprintf(fp_hpp, " };\n\n"); - fprintf(fp_hpp, " static void initialize_nops(MachNode *nop_list[%d]);\n\n", - _pipeline->_nopcnt); fprintf(fp_hpp, "#ifndef PRODUCT\n"); fprintf(fp_hpp, " void dump(outputStream *st = tty) const;\n"); fprintf(fp_hpp, "#endif\n"); diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 124b00a6549..9a6970ebf20 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -1399,10 +1399,6 @@ CodeBuffer* PhaseOutput::init_buffer() { cb->initialize_stubs_size(stub_req); cb->initialize_oop_recorder(C->env()->oop_recorder()); - // fill in the nop array for bundling computations - MachNode *_nop_list[Bundle::_nop_count]; - Bundle::initialize_nops(_nop_list); - return cb; } @@ -2062,8 +2058,7 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) // Create a MachNopNode _nop = new MachNopNode(); - // Now that the nops are in the array, save the count - // (but allow entries for the nops) + // Save the count _node_bundling_limit = compile.unique(); uint node_max = _regalloc->node_regs_max_index(); From a12e9fcebda1d7b75cb892e7920333d73fb5de9c Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 9 Sep 2025 19:37:57 +0000 Subject: [PATCH 202/295] 8366261: Provide utility methods for sun.security.util.Password Reviewed-by: smarks, weijun --- .../share/classes/java/io/Console.java | 26 +++++++++-- .../jdk/internal/access/JavaIOAccess.java | 3 +- .../jdk/internal/io/JdkConsoleImpl.java | 43 ++++++++++++++++++- .../unix/native/libjava/Console_md.c | 19 ++++++-- .../windows/native/libjava/Console_md.c | 27 +++++++----- .../java/io/Console/ModuleSelectionTest.java | 13 +++--- 6 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 2878de79718..96df4c5fd24 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -25,6 +25,7 @@ package java.io; +import java.lang.annotation.Native; import java.util.*; import java.nio.charset.Charset; import jdk.internal.access.JavaIOAccess; @@ -550,7 +551,12 @@ public sealed class Console implements Flushable permits ProxyingConsole { "Console class itself does not provide implementation"); } - private static final boolean istty = istty(); + @Native static final int TTY_STDIN_MASK = 0x00000001; + @Native static final int TTY_STDOUT_MASK = 0x00000002; + @Native static final int TTY_STDERR_MASK = 0x00000004; + // ttyStatus() returns bit patterns above, a bit is set if the corresponding file + // descriptor is a character device + private static final int ttyStatus = ttyStatus(); private static final Charset STDIN_CHARSET = Charset.forName(StaticProperty.stdinEncoding(), UTF_8.INSTANCE); private static final Charset STDOUT_CHARSET = @@ -562,6 +568,9 @@ public sealed class Console implements Flushable permits ProxyingConsole { public Console console() { return cons; } + public boolean isStdinTty() { + return Console.isStdinTty(); + } }); } @@ -583,7 +592,7 @@ public sealed class Console implements Flushable permits ProxyingConsole { for (var jcp : ServiceLoader.load(ModuleLayer.boot(), JdkConsoleProvider.class)) { if (consModName.equals(jcp.getClass().getModule().getName())) { - var jc = jcp.console(istty, STDIN_CHARSET, STDOUT_CHARSET); + var jc = jcp.console(isStdinTty() && isStdoutTty(), STDIN_CHARSET, STDOUT_CHARSET); if (jc != null) { c = new ProxyingConsole(jc); } @@ -594,12 +603,21 @@ public sealed class Console implements Flushable permits ProxyingConsole { } // If not found, default to built-in Console - if (istty && c == null) { + if (isStdinTty() && isStdoutTty() && c == null) { c = new ProxyingConsole(new JdkConsoleImpl(STDIN_CHARSET, STDOUT_CHARSET)); } return c; } - private static native boolean istty(); + private static boolean isStdinTty() { + return (ttyStatus & TTY_STDIN_MASK) != 0; + } + private static boolean isStdoutTty() { + return (ttyStatus & TTY_STDOUT_MASK) != 0; + } + private static boolean isStderrTty() { + return (ttyStatus & TTY_STDERR_MASK) != 0; + } + private static native int ttyStatus(); } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java index 532c1f259d4..bdeb2282a02 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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,4 +29,5 @@ import java.io.Console; public interface JavaIOAccess { Console console(); + boolean isStdinTty(); } diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index ec94d4ec4d6..c9c6b53fcda 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -38,10 +38,13 @@ import java.util.Arrays; import java.util.Formatter; import java.util.Locale; import java.util.Objects; +import java.util.Optional; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.StaticProperty; import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamEncoder; +import sun.nio.cs.UTF_8; /** * JdkConsole implementation based on the platform's TTY. @@ -103,6 +106,42 @@ public final class JdkConsoleImpl implements JdkConsole { @Override public char[] readPassword(Locale locale, String format, Object ... args) { + return readPassword0(false, locale, format, args); + } + + // These two methods are intended for sun.security.util.Password, so tools like keytool can + // use JdkConsoleImpl even when standard output is redirected. The Password class should first + // check if `System.console()` returns a Console instance and use it if available. Otherwise, + // it should call this method to obtain a JdkConsoleImpl. This ensures only one Console + // instance exists in the Java runtime. + private static final StableValue> INSTANCE = StableValue.of(); + public static Optional passwordConsole() { + return INSTANCE.orElseSet(() -> { + // If there's already a proper console, throw an exception + if (System.console() != null) { + throw new IllegalStateException("Can’t create a dedicated password " + + "console since a real console already exists"); + } + + // If stdin is NOT redirected, return an Optional containing a JdkConsoleImpl + // instance, otherwise an empty Optional. + return SharedSecrets.getJavaIOAccess().isStdinTty() ? + Optional.of( + new JdkConsoleImpl( + Charset.forName(StaticProperty.stdinEncoding(), UTF_8.INSTANCE), + Charset.forName(StaticProperty.stdoutEncoding(), UTF_8.INSTANCE))) : + Optional.empty(); + }); + } + + // Dedicated entry for sun.security.util.Password when stdout is redirected. + // This method strictly avoids producing any output by using noNewLine = true + // and an empty format string. + public char[] readPasswordNoNewLine() { + return readPassword0(true, Locale.getDefault(Locale.Category.FORMAT), ""); + } + + private char[] readPassword0(boolean noNewLine, Locale locale, String format, Object ... args) { char[] passwd = null; synchronized (writeLock) { synchronized(readLock) { @@ -146,7 +185,9 @@ public final class JdkConsoleImpl implements JdkConsole { throw ioe; } } - pw.println(); + if (!noNewLine) { + pw.println(); + } } } return passwd; diff --git a/src/java.base/unix/native/libjava/Console_md.c b/src/java.base/unix/native/libjava/Console_md.c index 1e71ab3a6b2..17643779b31 100644 --- a/src/java.base/unix/native/libjava/Console_md.c +++ b/src/java.base/unix/native/libjava/Console_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,19 @@ #include #include -JNIEXPORT jboolean JNICALL -Java_java_io_Console_istty(JNIEnv *env, jclass cls) +JNIEXPORT jint JNICALL +Java_java_io_Console_ttyStatus(JNIEnv *env, jclass cls) { - return isatty(fileno(stdin)) && isatty(fileno(stdout)); + jint ret = 0; + + if (isatty(fileno(stdin))) { + ret |= java_io_Console_TTY_STDIN_MASK; + } + if (isatty(fileno(stdout))) { + ret |= java_io_Console_TTY_STDOUT_MASK; + } + if (isatty(fileno(stderr))) { + ret |= java_io_Console_TTY_STDERR_MASK; + } + return ret; } diff --git a/src/java.base/windows/native/libjava/Console_md.c b/src/java.base/windows/native/libjava/Console_md.c index f73e62f8e26..07749f2775a 100644 --- a/src/java.base/windows/native/libjava/Console_md.c +++ b/src/java.base/windows/native/libjava/Console_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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,21 +31,28 @@ #include #include -JNIEXPORT jboolean JNICALL -Java_java_io_Console_istty(JNIEnv *env, jclass cls) +JNIEXPORT jint JNICALL +Java_java_io_Console_ttyStatus(JNIEnv *env, jclass cls) { + jint ret = 0; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE); - if (hStdIn == INVALID_HANDLE_VALUE || - hStdOut == INVALID_HANDLE_VALUE) { - return JNI_FALSE; + if (hStdIn != INVALID_HANDLE_VALUE && + GetFileType(hStdIn) == FILE_TYPE_CHAR) { + ret |= java_io_Console_TTY_STDIN_MASK; } - if (GetFileType(hStdIn) != FILE_TYPE_CHAR || - GetFileType(hStdOut) != FILE_TYPE_CHAR) { - return JNI_FALSE; + if (hStdOut != INVALID_HANDLE_VALUE && + GetFileType(hStdOut) == FILE_TYPE_CHAR) { + ret |= java_io_Console_TTY_STDOUT_MASK; } - return JNI_TRUE; + if (hStdErr != INVALID_HANDLE_VALUE && + GetFileType(hStdErr) == FILE_TYPE_CHAR) { + ret |= java_io_Console_TTY_STDERR_MASK; + } + + return ret; } diff --git a/test/jdk/java/io/Console/ModuleSelectionTest.java b/test/jdk/java/io/Console/ModuleSelectionTest.java index 332acf83fbd..f5f02ae13f4 100644 --- a/test/jdk/java/io/Console/ModuleSelectionTest.java +++ b/test/jdk/java/io/Console/ModuleSelectionTest.java @@ -21,9 +21,9 @@ * questions. */ -/** +/* * @test - * @bug 8295803 8299689 8351435 8361613 + * @bug 8295803 8299689 8351435 8361613 8366261 * @summary Tests System.console() returns correct Console (or null) from the expected * module. * @library /test/lib @@ -92,9 +92,12 @@ public class ModuleSelectionTest { var con = System.console(); var pc = Class.forName("java.io.ProxyingConsole"); var jdkc = Class.forName("jdk.internal.io.JdkConsole"); - var istty = (boolean)MethodHandles.privateLookupIn(Console.class, MethodHandles.lookup()) - .findStatic(Console.class, "istty", MethodType.methodType(boolean.class)) - .invoke(); + var lookup = MethodHandles.privateLookupIn(Console.class, MethodHandles.lookup()); + var istty = (boolean)lookup.findStatic(Console.class, "isStdinTty", MethodType.methodType(boolean.class)) + .invoke() && + (boolean)lookup.findStatic(Console.class, "isStdoutTty", MethodType.methodType(boolean.class)) + .invoke(); + var impl = con != null ? MethodHandles.privateLookupIn(pc, MethodHandles.lookup()) .findGetter(pc, "delegate", jdkc) .invoke(con) : null; From 24a734938e555882857cf0b06ea693ec6f18085f Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 9 Sep 2025 22:03:25 +0000 Subject: [PATCH 203/295] 8366733: Re-examine older java.text NF, DF, and DFS serialization tests Reviewed-by: naoto --- .../DecimalFormat/DFSSerializationTest.java | 90 ++++- .../DecimalFormat.114.txt | 0 .../DecimalFormatSymbols.114.txt | 0 .../DecimalFormatSymbols.142.txt | 0 .../NumberFormat4185761a.ser.txt | 0 .../NumberFormat4185761b.ser.txt | 0 .../DecimalFormat/SerializationTest.java | 355 ++++++++++++++++-- .../NumberFormat/DFSDeserialization142.java | 56 --- .../Format/NumberFormat/DFSSerialization.java | 162 -------- .../NumberFormat/DFSSerialization142.java | 54 --- .../Format/NumberFormat/NumberRegression.java | 101 +---- .../NumberFormat/SerializationLoadTest.java | 89 ----- .../NumberFormat/SerializationSaveTest.java | 81 ---- 13 files changed, 397 insertions(+), 591 deletions(-) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/DecimalFormat.114.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/DecimalFormatSymbols.114.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/DecimalFormatSymbols.142.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/NumberFormat4185761a.ser.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/NumberFormat4185761b.ser.txt (100%) delete mode 100644 test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/DFSSerialization.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java diff --git a/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java index 9e875e851c8..d4ccb77c137 100644 --- a/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java @@ -23,7 +23,9 @@ /* * @test - * @bug 8366401 + * @bug 4068067 4101150 8366401 + * @library /java/text/testlib + * @build HexDumpReader * @summary Check serialization of DecimalFormatSymbols. That is, ensure the * behavior for each stream version is correct during de-serialization. * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED DFSSerializationTest @@ -35,9 +37,11 @@ import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.reflect.Field; import java.text.DecimalFormatSymbols; import java.util.Currency; @@ -51,13 +55,36 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class DFSSerializationTest { + // Test that rely on hex dump files that were written from older JDK versions @Nested - class VersionTests { + class HexDumpTests { + + @Test // See 4068067 and CDFS which is the class in the serialized hex dump + void JDK1_1_4Test() { + // Reconstruct a class serialized during 1.1.4 which has a DFS holder + var cdfs = (CheckDecimalFormatSymbols) assertDoesNotThrow( + () -> deSer("DecimalFormatSymbols.114.txt")); + assertDoesNotThrow(cdfs::Update); // Checks getDigit call succeeds + } + + @Test // See 4068067 + void JDK1_4_2Test() { + // Reconstruct a 1.4.2 DFS + var dfs = (DecimalFormatSymbols) assertDoesNotThrow( + () -> deSer("DecimalFormatSymbols.142.txt")); + // Checks curr symbol is saved, and exponent separator default set + assertEquals("E", dfs.getExponentSeparator()); + assertEquals("*SpecialCurrencySymbol*", dfs.getCurrencySymbol()); + } + } + + @Nested + class StreamVersionTests { // Ensure correct monetarySeparator and exponential field defaults // Reads monetary from decimal, and sets exponential to 'E' @Test - public void version0Test() { + void version0Test() { var crafted = new DFSBuilder() .setVer(0) .set("monetarySeparator", '~') @@ -76,7 +103,7 @@ public class DFSSerializationTest { // Note that other versions did allow a locale field, which was nullable. // E.g. see nullableLocaleTest which does not set locale when it is `null` @Test - public void version1Test() { + void version1Test() { var crafted = new DFSBuilder() .setVer(1) .set("locale", null) @@ -89,7 +116,7 @@ public class DFSSerializationTest { // Version 2 did not have an exponential separator, and created it via exponent // char field. @Test - public void version2Test() { + void version2Test() { var crafted = new DFSBuilder() .setVer(2) .set("exponentialSeparator", null) @@ -103,7 +130,7 @@ public class DFSSerializationTest { // Version 3 didn't have perMillText, percentText, and minusSignText. // These were created from the corresponding char equivalents. @Test - public void version3Test() { + void version3Test() { var crafted = new DFSBuilder() .setVer(3) .set("perMillText", null) @@ -125,7 +152,7 @@ public class DFSSerializationTest { // Version 4 did not have monetaryGroupingSeparator. It should be based // off of groupingSeparator. @Test - public void version4Test() { + void version4Test() { var crafted = new DFSBuilder() .setVer(4) .set("monetaryGroupingSeparator", 'Z') @@ -142,7 +169,7 @@ public class DFSSerializationTest { // the case and previous stream versions can contain a null locale. Thus, // ensure that a null locale does not cause number data loading to fail. @Test - public void nullableLocaleTest() { + void nullableLocaleTest() { var bytes = ser(new DFSBuilder() .set("locale", null) .set("minusSignText", "zFoo") @@ -157,7 +184,7 @@ public class DFSSerializationTest { // readObject fails when the {@code char} and {@code String} representations // of percent, per mille, and/or minus sign disagree. @Test - public void disagreeingTextTest() { + void disagreeingTextTest() { var expected = "'char' and 'String' representations of either percent, " + "per mille, and/or minus sign disagree."; assertEquals(expected, assertThrows(InvalidObjectException.class, () -> @@ -179,7 +206,7 @@ public class DFSSerializationTest { // Ensure the serial version is updated to the current after de-serialization. @Test - public void updatedVersionTest() { + void updatedVersionTest() { var bytes = ser(new DFSBuilder().setVer(-25).build()); var dfs = assertDoesNotThrow(() -> deSer(bytes)); assertEquals(5, readField(dfs, "serialVersionOnStream")); @@ -187,7 +214,7 @@ public class DFSSerializationTest { // Should set currency from 4217 code when it is valid. @Test - public void validIntlCurrencyTest() { + void validIntlCurrencyTest() { var bytes = ser(new DFSBuilder().set("intlCurrencySymbol", "JPY").build()); var dfs = assertDoesNotThrow(() -> deSer(bytes)); assertEquals(Currency.getInstance("JPY"), dfs.getCurrency()); @@ -195,7 +222,7 @@ public class DFSSerializationTest { // Should not set currency when 4217 code is invalid, it remains null. @Test - public void invalidIntlCurrencyTest() { + void invalidIntlCurrencyTest() { var bytes = ser(new DFSBuilder() .set("intlCurrencySymbol", ">.,") .set("locale", Locale.JAPAN) @@ -205,6 +232,26 @@ public class DFSSerializationTest { assertNull(dfs.getCurrency()); } + // Ensure the currency symbol is read properly + @Test + void currencySymbolTest() { + var crafted = new DecimalFormatSymbols(); + crafted.setCurrencySymbol("*SpecialCurrencySymbol*"); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals("*SpecialCurrencySymbol*", dfs.getCurrencySymbol()); + } + + // Ensure the exponent separator is read properly + @Test + void exponentSeparatorTest() { + var crafted = new DecimalFormatSymbols(); + crafted.setExponentSeparator("*SpecialExponentSeparator*"); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals("*SpecialExponentSeparator*", dfs.getExponentSeparator()); + } + // Utilities ---- // Utility to serialize @@ -218,7 +265,7 @@ public class DFSSerializationTest { }, "Unexpected error during serialization"); } - // Utility to deserialize + // Utility to deserialize from byte array private static DecimalFormatSymbols deSer(byte[] bytes) throws IOException, ClassNotFoundException { try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { @@ -226,6 +273,14 @@ public class DFSSerializationTest { } } + // Utility to deserialize from file in hex format + private static Object deSer(String file) throws IOException, ClassNotFoundException { + try (InputStream stream = HexDumpReader.getStreamFromHexDump(file); + ObjectInputStream ois = new ObjectInputStream(stream)) { + return ois.readObject(); + } + } + // Utility to read a private field private static Object readField(DecimalFormatSymbols dfs, String name) { return assertDoesNotThrow(() -> { @@ -262,3 +317,12 @@ public class DFSSerializationTest { } } } + +// Not nested, so that it can be cast correctly for the 1.1.4 test +class CheckDecimalFormatSymbols implements Serializable { + DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols(); + public char Update() + { + return _decFormatSymbols.getDigit(); + } +} diff --git a/test/jdk/java/text/Format/NumberFormat/DecimalFormat.114.txt b/test/jdk/java/text/Format/DecimalFormat/DecimalFormat.114.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/DecimalFormat.114.txt rename to test/jdk/java/text/Format/DecimalFormat/DecimalFormat.114.txt diff --git a/test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.114.txt b/test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.114.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.114.txt rename to test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.114.txt diff --git a/test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.142.txt b/test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.142.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.142.txt rename to test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.142.txt diff --git a/test/jdk/java/text/Format/NumberFormat/NumberFormat4185761a.ser.txt b/test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761a.ser.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/NumberFormat4185761a.ser.txt rename to test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761a.ser.txt diff --git a/test/jdk/java/text/Format/NumberFormat/NumberFormat4185761b.ser.txt b/test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761b.ser.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/NumberFormat4185761b.ser.txt rename to test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761b.ser.txt diff --git a/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java b/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java index 09e3f6cf809..6a639b8fea1 100644 --- a/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,65 +22,344 @@ */ /* * @test - * @bug 8327640 - * @summary Check parseStrict correctness for DecimalFormat serialization - * @run junit/othervm SerializationTest + * @bug 4069754 4067878 4101150 4185761 8327640 + * @library /java/text/testlib + * @build HexDumpReader + * @summary Check de-serialization correctness for DecimalFormat. That is, ensure the + * behavior for each stream version is correct during de-serialization. + * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED SerializationTest */ -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.math.RoundingMode; +import java.text.DateFormat; +import java.text.DecimalFormat; import java.text.NumberFormat; -import java.text.ParseException; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Random; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SerializationTest { - private static final NumberFormat FORMAT = NumberFormat.getInstance(); + @Nested // Test that rely on hex dump files that were written from older JDK versions + class HexDumpTests { - @BeforeAll - public static void mutateFormat() { - FORMAT.setStrict(true); - } + @Test // See 4101150 and CDF which is the serialized hex dump + void JDK1_1_4Test() { + // Reconstruct a 1.1.4 serializable class which has a DF holder + var cdf = (CheckDecimalFormat) assertDoesNotThrow( + () -> deSer("DecimalFormat.114.txt")); + assertDoesNotThrow(cdf::Update); // Checks format call succeeds + } - @Test - public void testSerialization() throws IOException, ClassNotFoundException { - // Serialize - serialize("fmt.ser", FORMAT); - // Deserialize - deserialize("fmt.ser", FORMAT); - } + @Test // See 4185761 + void minMaxDigitsTest() { + // Reconstructing a DFS stream from an older JDK version + // The min digits are smaller than the max digits and should fail + // minint maxint minfrac maxfrac + // 0x122 0x121 0x124 0x123 + assertEquals("Digit count range invalid", + assertThrows(InvalidObjectException.class, + () -> deSer("NumberFormat4185761a.ser.txt")).getMessage()); + } - private void serialize(String fileName, NumberFormat... formats) - throws IOException { - try (ObjectOutputStream os = new ObjectOutputStream( - new FileOutputStream(fileName))) { - for (NumberFormat fmt : formats) { - os.writeObject(fmt); - } + @Test // See 4185761 + void digitLimitTest() { + // Reconstructing a DFS stream from an older JDK version + // The digit values exceed the class invariant limits + // minint maxint minfrac maxfrac + // 0x311 0x312 0x313 0x314 + assertEquals("Digit count out of range", + assertThrows(InvalidObjectException.class, + () -> deSer("NumberFormat4185761b.ser.txt")).getMessage()); } } - private static void deserialize(String fileName, NumberFormat... formats) - throws IOException, ClassNotFoundException { - try (ObjectInputStream os = new ObjectInputStream( - new FileInputStream(fileName))) { - for (NumberFormat fmt : formats) { - NumberFormat obj = (NumberFormat) os.readObject(); - assertEquals(fmt, obj, "Serialized and deserialized" - + " objects do not match"); + @Nested + class VersionTests { - String badNumber = "fooofooo23foo"; - assertThrows(ParseException.class, () -> fmt.parse(badNumber)); - assertThrows(ParseException.class, () -> obj.parse(badNumber)); + // Version 0 did not have exponential fields and defaulted the value to false + @Test + void version0Test() { + var crafted = new DFBuilder() + .setVer(0) + .set("useExponentialNotation", true) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + // Ensure we do not observe exponential notation form + assertFalse(df.format(0).contains("E")); + } + + // Version 1 did not support the affix pattern Strings. Ensure when they + // are read in from the stream they are not defaulted and remain null. + @Test + void version1Test() { + var crafted = new DFBuilder() + .setVer(1) + .set("posPrefixPattern", null) + .set("posSuffixPattern", null) + .set("negPrefixPattern", null) + .set("negSuffixPattern", null) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertNull(readField(df, "posPrefixPattern")); + assertNull(readField(df, "posSuffixPattern")); + assertNull(readField(df, "negPrefixPattern")); + assertNull(readField(df, "negSuffixPattern")); + } + + // Version 2 did not support the min/max int and frac digits. + // Ensure the proper defaults are set. + @Test + void version2Test() { + var crafted = new DFBuilder() + .setVer(2) + .set("maximumIntegerDigits", -1) + .set("maximumFractionDigits", -1) + .set("minimumIntegerDigits", -1) + .set("minimumFractionDigits", -1) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(1, df.getMinimumIntegerDigits()); + assertEquals(3, df.getMaximumFractionDigits()); + assertEquals(309, df.getMaximumIntegerDigits()); + assertEquals(0, df.getMinimumFractionDigits()); + } + + // Version 3 did not support rounding mode. Should default to HALF_EVEN + @Test + void version3Test() { + var crafted = new DFBuilder() + .setVer(3) + .set("roundingMode", RoundingMode.UNNECESSARY) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(RoundingMode.HALF_EVEN, df.getRoundingMode()); + } + } + + // Some invariant checking in DF relies on checking NF fields. + // Either via NF.readObject() or through super calls in DF.readObject + @Nested // For all these nested tests, see 4185761 + class NumberFormatTests { + + // Ensure the max integer value invariant is not exceeded + @Test + void integerTest() { + var crafted = new DFBuilder() + .setSuper("maximumIntegerDigits", 786) + .setSuper("minimumIntegerDigits", 785) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count out of range", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + + // Ensure the max fraction value invariant is not exceeded + @Test + void fractionTest() { + var crafted = new DFBuilder() + .setSuper("maximumFractionDigits", 788) + .setSuper("minimumFractionDigits", 787) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count out of range", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + + // Ensure the minimum integer digits cannot be greater than the max + @Test + void maxMinIntegerTest() { + var crafted = new DFBuilder() + .setSuper("maximumIntegerDigits", 5) + .setSuper("minimumIntegerDigits", 6) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count range invalid", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + + // Ensure the minimum fraction digits cannot be greater than the max + @Test + void maxMinFractionTest() { + var crafted = new DFBuilder() + .setSuper("maximumFractionDigits", 5) + .setSuper("minimumFractionDigits", 6) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count range invalid", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + } + + // Ensure the serial version is updated to the current after de-serialization. + @Test + void versionTest() { + var bytes = ser(new DFBuilder().setVer(-25).build()); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(4, readField(df, "serialVersionOnStream")); + } + + // Ensure strictness value is read properly when it is set. + @Test + void strictnessTest() { + var crafted = new DecimalFormat(); + crafted.setStrict(true); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertTrue(df.isStrict()); + } + + // Ensure invalid grouping sizes are corrected to the default invariant. + @Test + void groupingSizeTest() { + var crafted = new DFBuilder() + .set("groupingSize", (byte) -5) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(3, df.getGroupingSize()); + } + + // Ensure a de-serialized dFmt does not throw NPE from missing digitList + // later when formatting. i.e. re-construct the transient digitList field + @Test // See 4069754, 4067878 + void digitListTest() { + var crafted = new DecimalFormat(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertDoesNotThrow(() -> df.format(1)); + assertNotNull(readField(df, "digitList")); + } + + // Similar to the previous test, but the original regression test + // which was a failure in DateFormat due to DecimalFormat NPE + @Test // See 4069754 and 4067878 + void digitListDateFormatTest() { + var fmt = new FooFormat(); + fmt.now(); + var bytes = ser(fmt); + var ff = (FooFormat) assertDoesNotThrow(() -> deSer0(bytes)); + assertDoesNotThrow(ff::now); + } + + static class FooFormat implements Serializable { + DateFormat dateFormat = DateFormat.getDateInstance(); + + public String now() { + GregorianCalendar calendar = new GregorianCalendar(); + Date t = calendar.getTime(); + return dateFormat.format(t); + } + } + +// Utilities ---- + + // Utility to serialize + private static byte[] ser(Object obj) { + return assertDoesNotThrow(() -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) { + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); } + }, "Unexpected error during serialization"); + } + + // Utility to deserialize + private static Object deSer0(byte[] bytes) throws IOException, ClassNotFoundException { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { + return ois.readObject(); + } + } + + // Convenience cast to DF + private static DecimalFormat deSer(byte[] bytes) throws IOException, ClassNotFoundException { + return (DecimalFormat) deSer0(bytes); + } + + // Utility to deserialize from file in hex format + private static Object deSer(String file) throws IOException, ClassNotFoundException { + try (InputStream stream = HexDumpReader.getStreamFromHexDump(file); + ObjectInputStream ois = new ObjectInputStream(stream)) { + return ois.readObject(); + } + } + + // Utility to read a private field + private static Object readField(DecimalFormat df, String name) { + return assertDoesNotThrow(() -> { + var field = DecimalFormat.class.getDeclaredField(name); + field.setAccessible(true); + return field.get(df); + }, "Unexpected error during field reading"); + } + + // Utility class to build instances of DF via reflection + private static class DFBuilder { + + private final DecimalFormat df; + + private DFBuilder() { + df = new DecimalFormat(); + } + + private DFBuilder setVer(Object value) { + return set("serialVersionOnStream", value); + } + + private DFBuilder setSuper(String field, Object value) { + return set(df.getClass().getSuperclass(), field, value); + } + + private DFBuilder set(String field, Object value) { + return set(df.getClass(), field, value); + } + + private DFBuilder set(Class clzz, String field, Object value) { + return assertDoesNotThrow(() -> { + Field f = clzz.getDeclaredField(field); + f.setAccessible(true); + f.set(df, value); + return this; + }, "Unexpected error during reflection setting"); + } + + private DecimalFormat build() { + return df; } } } + +// Not nested, so that it can be recognized and cast correctly for the 1.1.4 test +class CheckDecimalFormat implements Serializable { + DecimalFormat _decFormat = (DecimalFormat) NumberFormat.getInstance(); + public String Update() { + Random r = new Random(); + return _decFormat.format(r.nextDouble()); + } +} diff --git a/test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java b/test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java deleted file mode 100644 index 2927f4e2c3b..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2005, 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. - */ - -/* - * No at-test for this test, because it needs to be run on older version JDK than 1.6 to test. - * It was tested using 1.4.2. The file object was created using JDK1.6. - */ - - - -import java.awt.*; -import java.text.*; -import java.util.*; -import java.io.*; - -public class DFSDeserialization142{ - - public static void main(String[] args) - { - try { - - File file = new File("DecimalFormatSymbols.current"); - FileInputStream istream = new FileInputStream(file); - ObjectInputStream p = new ObjectInputStream(istream); - DecimalFormatSymbols dfs = (DecimalFormatSymbols)p.readObject(); - if (dfs.getCurrencySymbol().equals("*SpecialCurrencySymbol*")){ - System.out.println("Serialization/Deserialization Test Passed."); - }else{ - throw new Exception("Serialization/Deserialization Test Failed:"+dfs.getCurrencySymbol()); - } - istream.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/DFSSerialization.java b/test/jdk/java/text/Format/NumberFormat/DFSSerialization.java deleted file mode 100644 index dea1d68ff6e..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/DFSSerialization.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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 - * 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 4068067 - * @library /java/text/testlib - * @build DFSSerialization HexDumpReader - * @run junit DFSSerialization - * @summary Three different tests are done. - * 1. read from the object created using jdk1.4.2 - * 2. create a valid DecimalFormatSymbols object with current JDK, then read the object - * 3. Try to create an valid DecimalFormatSymbols object by passing null to set null - * for the exponent separator symbol. Expect the NullPointerException. - */ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.fail; - -public class DFSSerialization{ - - @Test - public void TestDFSSerialization(){ - /* - * 1. read from the object created using jdk1.4.2 - */ - File oldFile = new File(System.getProperty("test.src", "."), "DecimalFormatSymbols.142.txt"); - DecimalFormatSymbols dfs142 = readTestObject(oldFile); - if (dfs142 != null){ - if (dfs142.getExponentSeparator().equals("E") && dfs142.getCurrencySymbol().equals("*SpecialCurrencySymbol*")){ - System.out.println("\n Deserialization of JDK1.4.2 Object from the current JDK: Passed."); - System.out.println(" Deserialization of JDK1.4.2 Object from the current JDK: Passed."); - } else { - fail(" Deserialization of JDK1.4.2 Object from the current JDK was Failed:" - +dfs142.getCurrencySymbol()+" "+dfs142.getExponentSeparator()); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException(" Deserialization of JDK1.4.2 Object from the current JDK was Failed:" - +dfs142.getCurrencySymbol()+" "+dfs142.getExponentSeparator()); - } - } - /* - * 2. create a valid DecimalFormatSymbols object with current JDK, then read the object - */ - String validObject = "DecimalFormatSymbols.current"; - File currentFile = createTestObject(validObject, "*SpecialExponentSeparator*"); - - DecimalFormatSymbols dfsValid = readTestObject(currentFile); - if (dfsValid != null){ - if (dfsValid.getExponentSeparator().equals("*SpecialExponentSeparator*") && - dfsValid.getCurrencySymbol().equals("*SpecialCurrencySymbol*")){ - System.out.println(" Deserialization of current JDK Object from the current JDK: Passed."); - System.out.println(" Deserialization of current JDK Object from the current JDK: Passed."); - } else { - fail(" Deserialization of current JDK Object from the current JDK was Failed:" - +dfsValid.getCurrencySymbol()+" "+dfsValid.getExponentSeparator()); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException(" Deserialization of current Object from the current JDK was Failed:" - +dfsValid.getCurrencySymbol()+" "+dfsValid.getExponentSeparator()); - } - } - /* - * 3. Try to create an valid DecimalFormatSymbols object by passing null - * to set null for the exponent separator symbol. Expect the NullPointerException. - */ - DecimalFormatSymbols symNPE = new DecimalFormatSymbols(Locale.US); - boolean npePassed = false; - try { - symNPE.setExponentSeparator(null); - } catch (NullPointerException npe){ - npePassed = true; - System.out.println(" Trying to set exponent separator with null: Passed."); - System.out.println(" Trying to set exponent separator with null: Passed."); - } - if (!npePassed){ - System.out.println(" Trying to set exponent separator with null:Failed."); - fail(" Trying to set exponent separator with null:Failed."); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException(" Trying to set exponent separator with null:Failed."); - } - - } - - private DecimalFormatSymbols readTestObject(File inputFile){ - try (InputStream istream = inputFile.getName().endsWith(".txt") ? - HexDumpReader.getStreamFromHexDump(inputFile) : - new FileInputStream(inputFile)) { - ObjectInputStream p = new ObjectInputStream(istream); - DecimalFormatSymbols dfs = (DecimalFormatSymbols)p.readObject(); - return dfs; - } catch (Exception e) { - fail("Test Malfunction in DFSSerialization: Exception while reading the object"); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException("Test Malfunction: re-throwing the exception", e); - } - } - - private File createTestObject(String objectName, String expString){ - DecimalFormatSymbols dfs= new DecimalFormatSymbols(); - dfs.setExponentSeparator(expString); - dfs.setCurrencySymbol("*SpecialCurrencySymbol*"); - System.out.println(" The special exponent separator is set : " + dfs.getExponentSeparator()); - System.out.println(" The special currency symbol is set : " + dfs.getCurrencySymbol()); - - // 6345659: create a test object in the test.class dir where test user has a write permission. - File file = new File(System.getProperty("test.class", "."), objectName); - try (FileOutputStream ostream = new FileOutputStream(file)) { - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(dfs); - //System.out.println(" The special currency symbol is set : " + dfs.getCurrencySymbol()); - return file; - } catch (Exception e){ - fail("Test Malfunction in DFSSerialization: Exception while creating an object"); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException("Test Malfunction: re-throwing the exception", e); - } - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java b/test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java deleted file mode 100644 index 4a5e873ee23..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2005, 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. - */ - -/* - * No at-test for this test, because it needs to be run on JDK 1.4.2 - * Instead, the resulting serialized file - * DecimalFormatSymbols.142 is archived. - */ - -import java.awt.*; -import java.text.*; -import java.util.*; -import java.io.*; - -public class DFSSerialization142 { - - public static void main(String[] args) - { - try { - - DecimalFormatSymbols dfs= new DecimalFormatSymbols(); - System.out.println("Default currency symbol in the default locale : " + dfs.getCurrencySymbol()); - dfs.setCurrencySymbol("*SpecialCurrencySymbol*"); - System.out.println("The special currency symbol is set : " + dfs.getCurrencySymbol()); - FileOutputStream ostream = new FileOutputStream("DecimalFormatSymbols.142"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(dfs); - ostream.close(); - System.out.println("DecimalFormatSymbols saved ok."); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index 2ff111f0e4b..dcc87643b2b 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +28,8 @@ * 4087251 4087535 4088161 4088503 4090489 4090504 4092480 4092561 4095713 * 4098741 4099404 4101481 4106658 4106662 4106664 4108738 4110936 4122840 * 4125885 4134034 4134300 4140009 4141750 4145457 4147295 4147706 4162198 - * 4162852 4167494 4170798 4176114 4179818 4185761 4212072 4212073 4216742 - * 4217661 4243011 4243108 4330377 4233840 4241880 4833877 8008577 8227313 - * 8174269 + * 4162852 4167494 4170798 4176114 4179818 4212072 4212073 4216742 4217661 + * 4243011 4243108 4330377 4233840 4241880 4833877 8008577 8227313 8174269 * @summary Regression tests for NumberFormat and associated classes * @library /java/text/testlib * @build HexDumpReader TestUtils @@ -307,33 +306,6 @@ public class NumberRegression { Locale.setDefault(savedLocale); } - /* bugs 4069754, 4067878 - * null pointer thrown when accessing a deserialized DecimalFormat - * object. - */ - @Test - public void Test4069754() - { - try { - myformat it = new myformat(); - System.out.println(it.Now()); - FileOutputStream ostream = new FileOutputStream("t.tmp"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(it); - ostream.close(); - System.out.println("Saved ok."); - - FileInputStream istream = new FileInputStream("t.tmp"); - ObjectInputStream p2 = new ObjectInputStream(istream); - myformat it2 = (myformat)p2.readObject(); - System.out.println(it2.Now()); - istream.close(); - System.out.println("Loaded ok."); - } catch (Exception foo) { - fail("Test for bug 4069754 or 4057878 failed => Exception: " + foo.getMessage()); - } - } - /** * DecimalFormat.applyPattern(String) allows illegal patterns */ @@ -1485,59 +1457,6 @@ public class NumberRegression { } } - @Test - public void Test4185761() throws IOException, ClassNotFoundException { - /* Code used to write out the initial files, which are - * then edited manually: - NumberFormat nf = NumberFormat.getInstance(Locale.US); - nf.setMinimumIntegerDigits(0x111); // Keep under 309 - nf.setMaximumIntegerDigits(0x112); // Keep under 309 - nf.setMinimumFractionDigits(0x113); // Keep under 340 - nf.setMaximumFractionDigits(0x114); // Keep under 340 - FileOutputStream ostream = - new FileOutputStream("NumberFormat4185761"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(nf); - ostream.close(); - */ - - // File minint maxint minfrac maxfrac - // NumberFormat4185761a 0x122 0x121 0x124 0x123 - // NumberFormat4185761b 0x311 0x312 0x313 0x314 - // File a is bad because the mins are smaller than the maxes. - // File b is bad because the values are too big for a DecimalFormat. - // These files have a sufix ".ser.txt". - - InputStream istream = HexDumpReader.getStreamFromHexDump("NumberFormat4185761a.ser.txt"); - ObjectInputStream p = new ObjectInputStream(istream); - try { - NumberFormat nf = (NumberFormat) p.readObject(); - fail("FAIL: Deserialized bogus NumberFormat int:" + - nf.getMinimumIntegerDigits() + ".." + - nf.getMaximumIntegerDigits() + " frac:" + - nf.getMinimumFractionDigits() + ".." + - nf.getMaximumFractionDigits()); - } catch (InvalidObjectException e) { - System.out.println("Ok: " + e.getMessage()); - } - istream.close(); - - istream = HexDumpReader.getStreamFromHexDump("NumberFormat4185761b.ser.txt"); - p = new ObjectInputStream(istream); - try { - NumberFormat nf = (NumberFormat) p.readObject(); - fail("FAIL: Deserialized bogus DecimalFormat int:" + - nf.getMinimumIntegerDigits() + ".." + - nf.getMaximumIntegerDigits() + " frac:" + - nf.getMinimumFractionDigits() + ".." + - nf.getMaximumFractionDigits()); - } catch (InvalidObjectException e) { - System.out.println("Ok: " + e.getMessage()); - } - istream.close(); - } - - /** * Some DecimalFormatSymbols changes are not picked up by DecimalFormat. * This includes the minus sign, currency symbol, international currency @@ -1930,20 +1849,6 @@ public class NumberRegression { } } -@SuppressWarnings("serial") -class myformat implements Serializable -{ - DateFormat _dateFormat = DateFormat.getDateInstance(); - - public String Now() - { - GregorianCalendar calendar = new GregorianCalendar(); - Date t = calendar.getTime(); - String nowStr = _dateFormat.format(t); - return nowStr; - } -} - @SuppressWarnings("serial") class MyNumberFormatTest extends NumberFormat { public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) { diff --git a/test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java b/test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java deleted file mode 100644 index 501af54c7da..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 1998, 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 - * @bug 4101150 - * @library /java/text/testlib - * @build SerializationLoadTest HexDumpReader - * @run main SerializationLoadTest - * @summary test serialization compatibility of DecimalFormat and DecimalFormatSymbols - * @key randomness - */ - -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.util.Random; - -public class SerializationLoadTest { - - public static void main(String[] args) - { - try { - InputStream istream1 = HexDumpReader.getStreamFromHexDump("DecimalFormat.114.txt"); - ObjectInputStream p = new ObjectInputStream(istream1); - CheckDecimalFormat it = (CheckDecimalFormat)p.readObject(); - System.out.println("1.1.4 DecimalFormat Loaded ok."); - System.out.println(it.Update()); - System.out.println("Called Update successfully."); - istream1.close(); - - InputStream istream2 = HexDumpReader.getStreamFromHexDump("DecimalFormatSymbols.114.txt"); - ObjectInputStream p2 = new ObjectInputStream(istream2); - CheckDecimalFormatSymbols it2 = (CheckDecimalFormatSymbols)p2.readObject(); - System.out.println("1.1.4 DecimalFormatSymbols Loaded ok."); - System.out.println("getDigit : " + it2.Update()); - System.out.println("Called Update successfully."); - istream2.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormat implements Serializable -{ - DecimalFormat _decFormat = (DecimalFormat)NumberFormat.getInstance(); - - public String Update() - { - Random r = new Random(); - return _decFormat.format(r.nextDouble()); - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormatSymbols implements Serializable -{ - DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols(); - - public char Update() - { - return _decFormatSymbols.getDigit(); - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java b/test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java deleted file mode 100644 index 0332efeca0f..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 1998, 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. - */ - -/* - * No at-test for this test, because it needs to be run on JDK 1.1.4. - * Instead, the resulting serialized files DecimalFormat.114 and - * DecimalFormatSymbols.114 are archived. - */ - -import java.awt.*; -import java.text.*; -import java.util.*; -import java.io.*; - -public class SerializationSaveTest { - - public static void main(String[] args) - { - try { - CheckDecimalFormat it = new CheckDecimalFormat(); - System.out.println(it.Update()); - FileOutputStream ostream = new FileOutputStream("DecimalFormat.114"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(it); - ostream.close(); - System.out.println("DecimalFormat saved ok."); - CheckDecimalFormatSymbols it2 = new CheckDecimalFormatSymbols(); - System.out.println("getDigit : " + it2.Update()); - FileOutputStream ostream2 = new FileOutputStream("DecimalFormatSymbols.114"); - ObjectOutputStream p2 = new ObjectOutputStream(ostream2); - p2.writeObject(it2); - ostream2.close(); - System.out.println("DecimalFormatSymbols saved ok."); - } catch (Exception e) { - e.printStackTrace(); - } - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormat implements Serializable -{ - DecimalFormat _decFormat = (DecimalFormat)NumberFormat.getInstance(); - - public String Update() - { - Random r = new Random(); - return _decFormat.format(r.nextDouble()); - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormatSymbols implements Serializable -{ - DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols(); - - public char Update() - { - return _decFormatSymbols.getDigit(); - } -} From f96403986b99008593e025c4991ee865fce59bb1 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 9 Sep 2025 23:27:33 +0000 Subject: [PATCH 204/295] 8361376: Regressions 1-6% in several Renaissance in 26-b4 only MacOSX aarch64 Co-authored-by: Martin Doerr Reviewed-by: mdoerr, aph, eosterlund --- .../gc/shared/barrierSetNMethod_aarch64.cpp | 22 ++++++-- .../arm/gc/shared/barrierSetNMethod_arm.cpp | 22 ++++++-- .../ppc/gc/shared/barrierSetAssembler_ppc.cpp | 12 +++-- .../ppc/gc/shared/barrierSetNMethod_ppc.cpp | 53 ++++++++++++++----- src/hotspot/cpu/ppc/nativeInst_ppc.hpp | 6 ++- .../gc/shared/barrierSetNMethod_riscv.cpp | 22 ++++++-- .../s390/gc/shared/barrierSetNMethod_s390.cpp | 27 +++++++--- .../x86/gc/shared/barrierSetNMethod_x86.cpp | 29 ++++++++-- .../zero/gc/shared/barrierSetNMethod_zero.cpp | 2 +- .../share/gc/shared/barrierSetNMethod.cpp | 27 ++-------- .../share/gc/shared/barrierSetNMethod.hpp | 19 +++---- src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 28 ---------- src/hotspot/share/gc/z/zBarrierSetNMethod.hpp | 8 --- src/hotspot/share/runtime/mutexLocker.cpp | 3 -- src/hotspot/share/runtime/mutexLocker.hpp | 1 - 15 files changed, 169 insertions(+), 112 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp index 88c90a548d1..3a4ba913a8f 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp @@ -115,8 +115,22 @@ public: return Atomic::load_acquire(guard_addr()); } - void set_value(int value) { - Atomic::release_store(guard_addr(), value); + void set_value(int value, int bit_mask) { + if (bit_mask == ~0) { + Atomic::release_store(guard_addr(), value); + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int old_value = Atomic::load(guard_addr()); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(guard_addr(), old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } bool check_barrier(err_msg& msg) const; @@ -179,7 +193,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } @@ -196,7 +210,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { } NativeNMethodBarrier barrier(nm); - barrier.set_value(value); + barrier.set_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp index 52d71ca65c2..81b14f28c35 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp @@ -51,8 +51,22 @@ public: return Atomic::load_acquire(guard_addr()); } - void set_value(int value) { - Atomic::release_store(guard_addr(), value); + void set_value(int value, int bit_mask) { + if (bit_mask == ~0) { + Atomic::release_store(guard_addr(), value); + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int old_value = Atomic::load(guard_addr()); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(guard_addr(), old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } void verify() const; @@ -115,7 +129,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } @@ -123,7 +137,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier. // Symmetric "LDR; DMB ISHLD" is in the nmethod barrier. NativeNMethodBarrier* barrier = native_nmethod_barrier(nm); - barrier->set_value(value); + barrier->set_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 405ac4b2310..b2e830bcdb8 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -183,12 +183,9 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); assert_different_registers(tmp, R0); - __ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {"); + __ align(8); // must align the following block which requires atomic updates - // Load stub address using toc (fixed instruction size, unlike load_const_optimized) - __ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(), - true, true, false); // 2 instructions - __ mtctr(tmp); + __ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {"); // This is a compound instruction. Patching support is provided by NativeMovRegMem. // Actual patching is done in (platform-specific part of) BarrierSetNMethod. @@ -198,6 +195,11 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t __ ld(R0, in_bytes(bs_nm->thread_disarmed_guard_value_offset()), R16_thread); __ cmpw(CR0, R0, tmp); + // Load stub address using toc (fixed instruction size, unlike load_const_optimized) + __ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(), + true, true, false); // 2 instructions + __ mtctr(tmp); + __ bnectrl(CR0); // Oops may have been changed. Make those updates observable. diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp index d3bb9cc3c04..02423e13308 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp @@ -38,7 +38,7 @@ class NativeNMethodBarrier: public NativeInstruction { NativeMovRegMem* get_patchable_instruction_handle() const { // Endianness is handled by NativeMovRegMem - return reinterpret_cast(get_barrier_start_address() + 3 * 4); + return reinterpret_cast(get_barrier_start_address()); } public: @@ -47,7 +47,7 @@ public: return get_patchable_instruction_handle()->offset(); } - void release_set_guard_value(int value) { + void release_set_guard_value(int value, int bit_mask) { // Patching is not atomic. // Stale observations of the "armed" state is okay as invoking the barrier stub in that case has no // unwanted side effects. Disarming is thus a non-critical operation. @@ -55,8 +55,37 @@ public: OrderAccess::release(); // Release modified oops - // Set the guard value (naming of 'offset' function is misleading). - get_patchable_instruction_handle()->set_offset(value); + if (bit_mask == ~0) { + // Set the guard value (naming of 'offset' function is misleading). + get_patchable_instruction_handle()->set_offset(value); + return; + } + + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + + NativeMovRegMem* mov = get_patchable_instruction_handle(); + assert(align_up(mov->instruction_address(), sizeof(uint64_t)) == + align_down(mov->instruction_address(), sizeof(uint64_t)), "instruction not aligned"); + uint64_t *instr = (uint64_t*)mov->instruction_address(); + assert(NativeMovRegMem::instruction_size == sizeof(*instr), "must be"); + union { + u_char buf[NativeMovRegMem::instruction_size]; + uint64_t u64; + } new_mov_instr, old_mov_instr; + new_mov_instr.u64 = old_mov_instr.u64 = Atomic::load(instr); + while (true) { + // Only bits in the mask are changed + int old_value = nativeMovRegMem_at(old_mov_instr.buf)->offset(); + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) return; // skip icache flush if nothing changed + nativeMovRegMem_at(new_mov_instr.buf)->set_offset(new_value, false /* no icache flush */); + // Swap in the new value + uint64_t v = Atomic::cmpxchg(instr, old_mov_instr.u64, new_mov_instr.u64, memory_order_relaxed); + if (v == old_mov_instr.u64) break; + old_mov_instr.u64 = v; + } + ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); } void verify() const { @@ -66,12 +95,6 @@ public: uint* current_instruction = reinterpret_cast(get_barrier_start_address()); - // calculate_address_from_global_toc (compound instruction) - verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction)); - verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction)); - - verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction)); - get_patchable_instruction_handle()->verify(); current_instruction += 2; @@ -80,6 +103,12 @@ public: // cmpw (mnemonic) verify_op_code(current_instruction, Assembler::CMP_OPCODE); + // calculate_address_from_global_toc (compound instruction) + verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction)); + verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction)); + + verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction)); + // bnectrl (mnemonic) (weak check; not checking the exact type) verify_op_code(current_instruction, Assembler::BCCTR_OPCODE); @@ -117,13 +146,13 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { // Thus, there's nothing to do here. } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } NativeNMethodBarrier* barrier = get_nmethod_barrier(nm); - barrier->release_set_guard_value(value); + barrier->release_set_guard_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp index 38126ec858d..d5dec3f4b1f 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp @@ -462,7 +462,7 @@ class NativeMovRegMem: public NativeInstruction { return ((*hi_ptr) << 16) | ((*lo_ptr) & 0xFFFF); } - void set_offset(intptr_t x) { + void set_offset(intptr_t x, bool flush_icache = true) { #ifdef VM_LITTLE_ENDIAN short *hi_ptr = (short*)(addr_at(0)); short *lo_ptr = (short*)(addr_at(4)); @@ -472,7 +472,9 @@ class NativeMovRegMem: public NativeInstruction { #endif *hi_ptr = x >> 16; *lo_ptr = x & 0xFFFF; - ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); + if (flush_icache) { + ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); + } } void add_offset_in_bytes(intptr_t radd_offset) { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index ac619f83f7d..4fa9b4b04fb 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -109,8 +109,22 @@ public: return Atomic::load_acquire(guard_addr()); } - void set_value(int value) { - Atomic::release_store(guard_addr(), value); + void set_value(int value, int bit_mask) { + if (bit_mask == ~0) { + Atomic::release_store(guard_addr(), value); + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int old_value = Atomic::load(guard_addr()); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(guard_addr(), old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } bool check_barrier(err_msg& msg) const; @@ -192,7 +206,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } @@ -209,7 +223,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { } NativeNMethodBarrier barrier(nm); - barrier.set_value(value); + barrier.set_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp index 88b3199e4e1..1a609ad8d45 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp @@ -53,11 +53,26 @@ class NativeMethodBarrier: public NativeInstruction { return *((int32_t*)data_addr); } - void set_guard_value(int value) { - int32_t* data_addr = (int32_t*)get_patchable_data_address(); + void set_guard_value(int value, int bit_mask) { + if (bit_mask == ~0) { + int32_t* data_addr = (int32_t*)get_patchable_data_address(); - // Set guard instruction value - *data_addr = value; + // Set guard instruction value + *data_addr = value; + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int32_t* data_addr = (int32_t*)get_patchable_data_address(); + int old_value = Atomic::load(data_addr); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(data_addr, old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } #ifdef ASSERT @@ -100,13 +115,13 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { return; } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } NativeMethodBarrier* barrier = get_nmethod_barrier(nm); - barrier->set_guard_value(value); + barrier->set_guard_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp index c27af4a29cd..124daef4fa7 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp @@ -50,8 +50,31 @@ public: address instruction_address() const { return addr_at(0); } address immediate_address() const { return addr_at(imm_offset); } + NativeNMethodCmpBarrier* nativeNMethodCmpBarrier_at(address a) { return (NativeNMethodCmpBarrier*)a; } + jint get_immediate() const { return int_at(imm_offset); } - void set_immediate(jint imm) { set_int_at(imm_offset, imm); } + void set_immediate(jint imm, int bit_mask) { + if (bit_mask == ~0) { + set_int_at(imm_offset, imm); + return; + } + + assert((imm & ~bit_mask) == 0, "trying to set bits outside the mask"); + imm &= bit_mask; + + assert(align_up(immediate_address(), sizeof(jint)) == + align_down(immediate_address(), sizeof(jint)), "immediate not aligned"); + jint* data_addr = (jint*)immediate_address(); + jint old_value = Atomic::load(data_addr); + while (true) { + // Only bits in the mask are changed + jint new_value = imm | (old_value & ~bit_mask); + if (new_value == old_value) break; + jint v = Atomic::cmpxchg(data_addr, old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } + } bool check_barrier(err_msg& msg) const; void verify() const { #ifdef ASSERT @@ -159,13 +182,13 @@ static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) { return barrier; } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm); - cmp->set_immediate(value); + cmp->set_immediate(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp index 62e7134ed61..e9220ff57e4 100644 --- a/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp +++ b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp @@ -29,7 +29,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { ShouldNotReachHere(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { ShouldNotReachHere(); } diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 522000e0a99..0e5c5d02d1c 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -72,21 +72,12 @@ bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) { } void BarrierSetNMethod::disarm(nmethod* nm) { - guard_with(nm, disarmed_guard_value()); + set_guard_value(nm, disarmed_guard_value()); } void BarrierSetNMethod::guard_with(nmethod* nm, int value) { assert((value & not_entrant) == 0, "not_entrant bit is reserved"); - // Enter critical section. Does not block for safepoint. - ConditionalMutexLocker ml(NMethodEntryBarrier_lock, !NMethodEntryBarrier_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); - // Do not undo sticky bit - if (is_not_entrant(nm)) { - value |= not_entrant; - } - if (guard_value(nm) != value) { - // Patch the code only if needed. - set_guard_value(nm, value); - } + set_guard_value(nm, value); } bool BarrierSetNMethod::is_armed(nmethod* nm) { @@ -119,6 +110,8 @@ bool BarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { return true; } + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); + // 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 @@ -179,10 +172,6 @@ void BarrierSetNMethod::arm_all_nmethods() { } int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { - // Enable WXWrite: the function is called directly from nmethod_entry_barrier - // stub. - MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); - address return_address = *return_address_ptr; AARCH64_PORT_ONLY(return_address = pauth_strip_pointer(return_address)); CodeBlob* cb = CodeCache::find_blob(return_address); @@ -243,13 +232,7 @@ oop BarrierSetNMethod::oop_load_phantom(const nmethod* nm, int index) { // nmethod_stub_entry_barrier() may appear to be spurious, because is_armed() still returns // false and nmethod_entry_barrier() is not called. void BarrierSetNMethod::make_not_entrant(nmethod* nm) { - // Enter critical section. Does not block for safepoint. - ConditionalMutexLocker ml(NMethodEntryBarrier_lock, !NMethodEntryBarrier_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); - int value = guard_value(nm) | not_entrant; - if (guard_value(nm) != value) { - // Patch the code only if needed. - set_guard_value(nm, value); - } + set_guard_value(nm, not_entrant, not_entrant); } bool BarrierSetNMethod::is_not_entrant(nmethod* nm) { diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp index b905e8869b5..88bae4d5c1c 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp @@ -36,17 +36,18 @@ class nmethod; class BarrierSetNMethod: public CHeapObj { private: int _current_phase; + + void deoptimize(nmethod* nm, address* return_addr_ptr); + +protected: enum { not_entrant = 1 << 31, // armed sticky bit, see make_not_entrant armed = 0, initial = 1, }; - void deoptimize(nmethod* nm, address* return_addr_ptr); - -protected: - virtual int guard_value(nmethod* nm); - void set_guard_value(nmethod* nm, int value); + int guard_value(nmethod* nm); + void set_guard_value(nmethod* nm, int value, int bit_mask = ~not_entrant); public: BarrierSetNMethod() : _current_phase(initial) {} @@ -60,13 +61,13 @@ public: static int nmethod_stub_entry_barrier(address* return_address_ptr); bool nmethod_osr_entry_barrier(nmethod* nm); - virtual bool is_armed(nmethod* nm); + bool is_armed(nmethod* nm); void arm(nmethod* nm) { guard_with(nm, armed); } void disarm(nmethod* nm); - virtual void make_not_entrant(nmethod* nm); - virtual bool is_not_entrant(nmethod* nm); + void make_not_entrant(nmethod* nm); + bool is_not_entrant(nmethod* nm); - virtual void guard_with(nmethod* nm, int value); + void guard_with(nmethod* nm, int value); virtual void arm_all_nmethods(); diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index 392d194a65b..d80ce4e149d 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -106,34 +106,6 @@ oop ZBarrierSetNMethod::oop_load_phantom(const nmethod* nm, int index) { return ZNMethod::oop_load_phantom(nm, index); } -void ZBarrierSetNMethod::guard_with(nmethod* nm, int value) { - assert((value & not_entrant) == 0, "not_entrant bit is reserved"); - ZLocker locker(ZNMethod::lock_for_nmethod(nm)); - // Preserve the sticky bit - if (is_not_entrant(nm)) { - value |= not_entrant; - } - if (guard_value(nm) != value) { - // Patch the code only if needed. - set_guard_value(nm, value); - } -} - -bool ZBarrierSetNMethod::is_armed(nmethod* nm) { - int value = guard_value(nm) & ~not_entrant; - return value != disarmed_guard_value(); -} - -void ZBarrierSetNMethod::make_not_entrant(nmethod* nm) { - ZLocker locker(ZNMethod::lock_for_nmethod(nm)); - int value = guard_value(nm) | not_entrant; // permanent sticky value - set_guard_value(nm, value); -} - -bool ZBarrierSetNMethod::is_not_entrant(nmethod* nm) { - return (guard_value(nm) & not_entrant) != 0; -} - uintptr_t ZBarrierSetNMethod::color(nmethod* nm) { // color is stored at low order bits of int; conversion to uintptr_t is fine return uintptr_t(guard_value(nm) & ~not_entrant); diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp index e0b7ba6c773..f51aa53a7e9 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp @@ -30,10 +30,6 @@ class nmethod; class ZBarrierSetNMethod : public BarrierSetNMethod { - enum : int { - not_entrant = 1 << 31, // armed sticky bit, see make_not_entrant - }; - protected: virtual bool nmethod_entry_barrier(nmethod* nm); @@ -46,10 +42,6 @@ public: virtual oop oop_load_no_keepalive(const nmethod* nm, int index); virtual oop oop_load_phantom(const nmethod* nm, int index); - virtual void make_not_entrant(nmethod* nm); - virtual bool is_not_entrant(nmethod* nm); - virtual void guard_with(nmethod* nm, int value); - virtual bool is_armed(nmethod* nm); virtual void arm_all_nmethods() { ShouldNotCallThis(); } }; diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 3f8915973e2..0c604205939 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -36,7 +36,6 @@ // Mutexes used in the VM (see comment in mutexLocker.hpp): Mutex* NMethodState_lock = nullptr; -Mutex* NMethodEntryBarrier_lock = nullptr; Monitor* SystemDictionary_lock = nullptr; Mutex* InvokeMethodTypeTable_lock = nullptr; Monitor* InvokeMethodIntrinsicTable_lock = nullptr; @@ -207,8 +206,6 @@ void assert_lock_strong(const Mutex* lock) { void mutex_init() { MUTEX_DEFN(tty_lock , PaddedMutex , tty); // allow to lock in VM - MUTEX_DEFN(NMethodEntryBarrier_lock , PaddedMutex , service-1); - MUTEX_DEFN(STS_lock , PaddedMonitor, nosafepoint); #if INCLUDE_G1GC diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f888c789eb7..3a73edc7bf2 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -34,7 +34,6 @@ class Thread; // Mutexes used in the VM. extern Mutex* NMethodState_lock; // a lock used to guard a compiled method state -extern Mutex* NMethodEntryBarrier_lock; // protects nmethod entry barrier extern Monitor* SystemDictionary_lock; // a lock on the system dictionary extern Mutex* InvokeMethodTypeTable_lock; extern Monitor* InvokeMethodIntrinsicTable_lock; From 8cd4e7d856dcc68243505f4e771dc8ab87176584 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 9 Sep 2025 23:50:33 +0000 Subject: [PATCH 205/295] 8365192: post_meth_exit should be in vm state when calling get_jvmti_thread_state Reviewed-by: mdoerr, dholmes --- src/hotspot/share/prims/jvmtiExport.cpp | 68 +++++++++++++------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 8c10a371e5a..2da9a074fb6 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -418,6 +418,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { JvmtiThreadState* JvmtiExport::get_jvmti_thread_state(JavaThread *thread, bool allow_suspend) { assert(thread == JavaThread::current(), "must be current thread"); + assert(thread->thread_state() == _thread_in_vm, "thread should be in vm"); if (thread->is_vthread_mounted() && thread->jvmti_thread_state() == nullptr) { JvmtiEventController::thread_started(thread); if (allow_suspend && thread->is_suspended()) { @@ -1826,47 +1827,50 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu } void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame current_frame) { + // At this point we only have the address of a "raw result" and + // we just call into the interpreter to convert this into a jvalue. + // This method always makes transition to vm and back where GC can happen. + // So it is needed to preserve result and then restore it + // even if events are not actually posted. + // Saving oop_result into value.j is deferred until jvmti state is ready. HandleMark hm(thread); methodHandle mh(thread, method); - - JvmtiThreadState *state = get_jvmti_thread_state(thread); - - if (state == nullptr || !state->is_interp_only_mode()) { - // for any thread that actually wants method exit, interp_only_mode is set - return; - } - Handle result; + oop oop_result; jvalue value; value.j = 0L; - - if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { - // At this point we only have the address of a "raw result" and - // we just call into the interpreter to convert this into a jvalue. - oop oop_result; - BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); - assert(type == T_VOID || current_frame.interpreter_frame_expression_stack_size() > 0, - "Stack shouldn't be empty"); - if (is_reference_type(type)) { - result = Handle(thread, oop_result); - value.l = JNIHandles::make_local(thread, result()); - } + BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); + assert(mh->is_native() || type == T_VOID || current_frame.interpreter_frame_expression_stack_size() > 0, + "Stack shouldn't be empty"); + if (is_reference_type(type)) { + result = Handle(thread, oop_result); } - - // Do not allow NotifyFramePop to add new FramePop event request at - // depth 0 as it is already late in the method exiting dance. - state->set_top_frame_is_exiting(); - - // Deferred transition to VM, so we can stash away the return oop before GC. + JvmtiThreadState* state; // should be initialized in vm state only JavaThread* current = thread; // for JRT_BLOCK + bool interp_only; // might be changed in JRT_BLOCK_END JRT_BLOCK - post_method_exit_inner(thread, mh, state, false /* not exception exit */, current_frame, value); + state = get_jvmti_thread_state(thread); + interp_only = state != nullptr && state->is_interp_only_mode(); + if (interp_only) { + if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { + // Deferred saving Object result into value. + if (is_reference_type(type)) { + value.l = JNIHandles::make_local(thread, result()); + } + } + + // Do not allow NotifyFramePop to add new FramePop event request at + // depth 0 as it is already late in the method exiting dance. + state->set_top_frame_is_exiting(); + + post_method_exit_inner(thread, mh, state, false /* not exception exit */, current_frame, value); + } JRT_BLOCK_END - - // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava desctructor. Now it is safe to allow - // adding FramePop event requests as no safepoint can happen before removing activation. - state->clr_top_frame_is_exiting(); - + if (interp_only) { + // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava destructor. Now it is safe to allow + // adding FramePop event requests as no safepoint can happen before removing activation. + state->clr_top_frame_is_exiting(); + } if (result.not_null() && !mh->is_native()) { // We have to restore the oop on the stack for interpreter frames *(oop*)current_frame.interpreter_frame_tos_address() = result(); From 53b3e0567d2801ddf62c5849b219324ddfcb264a Mon Sep 17 00:00:00 2001 From: erifan Date: Wed, 10 Sep 2025 01:49:55 +0000 Subject: [PATCH 206/295] 8366588: VectorAPI: Re-intrinsify VectorMask.laneIsSet where the input index is a variable Reviewed-by: shade, xgong, epeter --- src/hotspot/share/opto/vectorIntrinsics.cpp | 2 +- .../compiler/lib/ir_framework/IRNode.java | 5 + .../vectorapi/VectorMaskLaneIsSetTest.java | 160 ++++++++++++++++++ .../vector/VectorExtractBenchmark.java | 5 +- 4 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 43ca51fca67..85d9790c0eb 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -2502,7 +2502,7 @@ bool LibraryCallKit::inline_vector_extract() { if (vector_klass == nullptr || vector_klass->const_oop() == nullptr || elem_klass == nullptr || elem_klass->const_oop() == nullptr || vlen == nullptr || !vlen->is_con() || - idx == nullptr || !idx->is_con()) { + idx == nullptr) { log_if_needed(" ** missing constant: vclass=%s etype=%s vlen=%s", NodeClassNames[argument(0)->Opcode()], NodeClassNames[argument(1)->Opcode()], diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 16c6d99a64f..52fc9a05f98 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1417,6 +1417,11 @@ public class IRNode { beforeMatchingNameRegex(VECTOR_MASK_TO_LONG, "VectorMaskToLong"); } + public static final String VECTOR_MASK_LANE_IS_SET = PREFIX + "VECTOR_MASK_LANE_IS_SET" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_LANE_IS_SET, "ExtractUB"); + } + // Can only be used if avx512_vnni is available. public static final String MUL_ADD_VS2VI_VNNI = PREFIX + "MUL_ADD_VS2VI_VNNI" + POSTFIX; static { diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java new file mode 100644 index 00000000000..b7f2103c56c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * 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.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8366588 + * @key randomness + * @library /test/lib / + * @summary VectorAPI: Re-intrinsify VectorMask.laneIsSet where the input index is a variable + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorMaskLaneIsSetTest + */ + +public class VectorMaskLaneIsSetTest { + static final VectorSpecies B_SPECIES = ByteVector.SPECIES_MAX; + static final VectorSpecies S_SPECIES = ShortVector.SPECIES_MAX; + static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + static final VectorSpecies F_SPECIES = FloatVector.SPECIES_MAX; + static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_MAX; + static final int LENGTH = 512; + static boolean[] ma; + static VectorMask mask_b; + static VectorMask mask_s; + static VectorMask mask_i; + static VectorMask mask_l; + static VectorMask mask_f; + static VectorMask mask_d; + + static { + ma = new boolean[LENGTH]; + for (int i = 0; i < LENGTH; i++) { + ma[i] = i % 2 == 0; + } + mask_b = VectorMask.fromArray(B_SPECIES, ma, 0); + mask_s = VectorMask.fromArray(S_SPECIES, ma, 0); + mask_i = VectorMask.fromArray(I_SPECIES, ma, 0); + mask_l = VectorMask.fromArray(L_SPECIES, ma, 0); + mask_f = VectorMask.fromArray(F_SPECIES, ma, 0); + mask_d = VectorMask.fromArray(D_SPECIES, ma, 0); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 6" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeature = { "avx2", "true" }) + public static void testVectorMaskLaneIsSetByte_const() { + Asserts.assertEquals(ma[0], mask_b.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_s.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_i.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_l.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_f.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_d.laneIsSet(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Byte_variable(int i) { + return mask_b.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Byte_variable") + public static void testVectorMaskLaneIsSet_Byte_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Byte_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Short_variable(int i) { + return mask_s.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Short_variable") + public static void testVectorMaskLaneIsSet_Short_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Short_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Int_variable(int i) { + return mask_i.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Int_variable") + public static void testVectorMaskLaneIsSet_Int_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Int_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + public static boolean testVectorMaskLaneIsSet_Long_variable(int i) { + return mask_l.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Long_variable") + public static void testVectorMaskLaneIsSet_Long_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Long_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Float_variable(int i) { + return mask_f.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Float_variable") + public static void testVectorMaskLaneIsSet_Float_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Float_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + public static boolean testVectorMaskLaneIsSet_Double_variable(int i) { + return mask_d.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Double_variable") + public static void testVectorMaskLaneIsSet_Double_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Double_variable(0)); + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java index 6358cb0a5d4..84c9031739c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Arm Limited. All rights reserved. + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * 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 +29,9 @@ import org.openjdk.jmh.annotations.*; @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorExtractBenchmark { private int idx = 0; private boolean[] res = new boolean[8]; From af9b9050ec51d0c43690fc42658741bd865b0310 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 10 Sep 2025 03:30:16 +0000 Subject: [PATCH 207/295] 8366057: HotSpot Style Guide should permit trailing return types Reviewed-by: dholmes, stefank, kvn, adinn, jsjolen --- doc/hotspot-style.html | 52 ++++++++++++++++++++++++++++++++++++++---- doc/hotspot-style.md | 37 ++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 98d813242a5..fb4cffc9d43 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -75,6 +75,9 @@ Standard Library

      • Deduction
      • Expression SFINAE
      • +
      • Trailing return type +syntax for functions
      • Non-type template parameter values
      • @@ -719,11 +722,14 @@ href="http://wg21.link/p0127r2">p0127r2)
        auto may be used as a placeholder for the type of a non-type template parameter. The type is deduced from the value provided in a template instantiation.

        -
      • Function return type deduction ( +

        * Function return type +deduction (n3638)
        Only use if the function body has a very small number of return -statements, and generally relatively little other code.

      • -
      • Class template argument deduction ( +

          +
        • Class template argument deduction (n3602, p0091r3)
          The template arguments of a class template may be deduced from the arguments to a constructor. @@ -736,7 +742,7 @@ harder to understand, because explicit type information is lacking. But it can also remove the need to be explicit about types that are either obvious, or that are very hard to write. For example, these allow the addition of a scope-guard mechanism with nice syntax; something like -this

        • +this
          ScopeGuard guard{[&]{ ... cleanup code ... }};
          @@ -771,6 +777,44 @@ class="uri">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468
          https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html

          +

          Trailing return type +syntax for functions

          +

          A function's return type may be specified after the parameters and +qualifiers (n2541). +In such a declaration the normal return type is auto and +the return type is indicated by -> followed by the type. +Although both use auto in the "normal" leading return type +position, this differs from function return type +deduction, in that the return type is explicit rather than deduced, +but specified in a trailing position.

          +

          Use of trailing return types is permitted. However, the normal, +leading position for the return type is preferred. A trailing return +type should only be used where it provides some benefit. Such benefits +usually arise because a trailing return type is in a different scope +than a leading return type.

          +
            +
          • If the function identifier is a nested name specifier, then the +trailing return type occurs in the nested scope. This may permit simpler +naming in the return type because of the different name lookup +context.

          • +
          • The trailing return type is in the scope of the parameters, +making their types accessible via decltype. For +example

          • +
          +
          template<typename T, typename U> auto add(T t, U u) -> decltype(t + u);
          +

          rather than

          +
          template<typename T, typename U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
          +
            +
          • Complex calculated leading return types may obscure the normal +syntactic boundaries, making it more difficult for a reader to find the +function name and parameters. This is particularly common in cases where +the return type is being used for SFINAE. A trailing +return type may be preferable in such situations.
          • +

          Non-type template parameter values

          C++17 extended the arguments permitted for non-type template diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index e3ba4b470ce..3fd5468d531 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -642,6 +642,7 @@ use can make code much harder to understand. parameter. The type is deduced from the value provided in a template instantiation. + * Function return type deduction ([n3638](https://isocpp.org/files/papers/N3638.html))
          Only use if the function body has a very small number of `return` @@ -691,6 +692,42 @@ Here are a few closely related example bugs:

          +### Trailing return type syntax for functions + +A function's return type may be specified after the parameters and qualifiers +([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)). +In such a declaration the normal return type is `auto` and the return type is +indicated by `->` followed by the type. Although both use `auto` in the +"normal" leading return type position, this differs from +[function return type deduction](#function-return-type-deduction), +in that the return type is explicit rather than deduced, but specified in a +trailing position. + +Use of trailing return types is permitted. However, the normal, leading +position for the return type is preferred. A trailing return type should only +be used where it provides some benefit. Such benefits usually arise because a +trailing return type is in a different scope than a leading return type. + +* If the function identifier is a nested name specifier, then the trailing +return type occurs in the nested scope. This may permit simpler naming in the +return type because of the different name lookup context. + +* The trailing return type is in the scope of the parameters, making their +types accessible via `decltype`. For example +``` +template auto add(T t, U u) -> decltype(t + u); +``` +rather than +``` +template decltype((*(T*)0) + (*(U*)0)) add(T t, U u); +``` + +* Complex calculated leading return types may obscure the normal syntactic +boundaries, making it more difficult for a reader to find the function name and +parameters. This is particularly common in cases where the return type is +being used for [SFINAE]. A trailing return type may be preferable in such +situations. + ### Non-type template parameter values C++17 extended the arguments permitted for non-type template parameters From 8ab8d02e40e987a5eb5e8036ff4f12146ac2b16a Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 10 Sep 2025 05:45:31 +0000 Subject: [PATCH 208/295] 8366938: Test runtime/handshake/HandshakeTimeoutTest.java crashed Reviewed-by: kbarrett --- .../hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java b/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java index a1a5ff68c31..7f1ee4be711 100644 --- a/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java +++ b/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +36,7 @@ import jdk.test.whitebox.WhiteBox; * @library /testlibrary /test/lib * @build HandshakeTimeoutTest * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver HandshakeTimeoutTest + * @run driver/timeout=480 HandshakeTimeoutTest */ public class HandshakeTimeoutTest { From 2705e880b64825044e67487f01263121780d8f7a Mon Sep 17 00:00:00 2001 From: Disha Date: Wed, 10 Sep 2025 06:16:12 +0000 Subject: [PATCH 209/295] 8366764: Deproblemlist java/awt/ScrollPane/ScrollPositionTest.java Reviewed-by: azvegint --- test/jdk/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index aac9d9a8a21..475704f7e95 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -455,7 +455,6 @@ java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java 6848810 macosx-all java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java 8194751 linux-all java/awt/image/VolatileImage/BitmaskVolatileImage.java 8133102 linux-all java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 8203004 linux-all -java/awt/ScrollPane/ScrollPositionTest.java 8040070 linux-all java/awt/ScrollPane/ScrollPaneEventType.java 8296516 macosx-all java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all From b7b01d6f564ae34e913ae51bd2f8243a32807136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 10 Sep 2025 06:16:39 +0000 Subject: [PATCH 210/295] 8366984: Remove delay slot support Reviewed-by: dlong, epeter --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 5 - src/hotspot/cpu/arm/arm.ad | 20 +- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 5 - src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 5 - .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 - src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 4 - src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 5 - src/hotspot/share/adlc/adlparse.cpp | 32 +- src/hotspot/share/adlc/formsopt.cpp | 4 - src/hotspot/share/adlc/formsopt.hpp | 4 - src/hotspot/share/adlc/output_c.cpp | 23 +- src/hotspot/share/adlc/output_h.cpp | 42 +-- src/hotspot/share/c1/c1_LIR.cpp | 20 -- src/hotspot/share/c1/c1_LIR.hpp | 24 -- src/hotspot/share/c1/c1_LIRAssembler.cpp | 3 +- src/hotspot/share/c1/c1_LIRAssembler.hpp | 6 +- src/hotspot/share/code/relocInfo.hpp | 4 +- src/hotspot/share/opto/output.cpp | 304 ++---------------- src/hotspot/share/runtime/sharedRuntime.cpp | 2 - 19 files changed, 54 insertions(+), 460 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index e9bb2350b5b..d788c0c201a 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -2585,11 +2585,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { - Unimplemented(); -} - - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ lea(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 45d51aaac57..2835a256153 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -3281,18 +3281,18 @@ pipe_class loadPollP(iRegP poll) %{ %} pipe_class br(Universe br, label labl) %{ - single_instruction_with_delay_slot; + single_instruction; BR : R; %} pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{ - single_instruction_with_delay_slot; + single_instruction; cr : E(read); BR : R; %} pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{ - single_instruction_with_delay_slot; + single_instruction; op1 : E(read); BR : R; MS : R; @@ -3323,14 +3323,14 @@ pipe_class call(method meth) %{ %} pipe_class tail_call(Universe ignore, label labl) %{ - single_instruction; has_delay_slot; + single_instruction; fixed_latency(100); BR : R(1); MS : R(1); %} pipe_class ret(Universe ignore) %{ - single_instruction; has_delay_slot; + single_instruction; BR : R(1); MS : R(1); %} @@ -3373,14 +3373,6 @@ pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{ IALU : R(3) %} -// Perform a compare, then move conditionally in a branch delay slot. -pipe_class min_max( iRegI src2, iRegI srcdst ) %{ - src2 : E(read); - srcdst : E(read); - IALU : R; - BR : R; -%} - // Define the class for the Nop node define %{ MachNop = ialu_nop; @@ -9053,7 +9045,7 @@ instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dum format %{ "MOV $zero,0\n" " MOV $temp,$cnt\n" "loop: SUBS $temp,$temp,4\t! Count down a dword of bytes\n" - " STR.ge $zero,[$base+$temp]\t! delay slot" + " STR.ge $zero,[$base+$temp]\n" " B.gt loop\t\t! Clearing loop\n" %} ins_encode %{ __ mov($zero$$Register, 0); diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index c3b91e8c76f..d6ed82dcdb2 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -2552,11 +2552,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { fatal("Type profiling not implemented on this platform"); } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { - Unimplemented(); -} - - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no); __ add_slow(dst->as_pointer_register(), mon_addr.base(), mon_addr.disp()); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 73509c22134..3ca75305eca 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2747,11 +2747,6 @@ void LIR_Assembler::align_backward_branch_target() { } -void LIR_Assembler::emit_delay(LIR_OpDelay* op) { - Unimplemented(); -} - - void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { // tmp must be unused assert(tmp->is_illegal(), "wasting a register if tmp is allocated"); diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index f60be85a141..c3fe72870cf 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1590,8 +1590,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); } - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ la(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 87dc8b9286d..b875eeca9ad 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -2816,10 +2816,6 @@ void LIR_Assembler::align_backward_branch_target() { __ align(OptoLoopAlignment); } -void LIR_Assembler::emit_delay(LIR_OpDelay* op) { - ShouldNotCallThis(); // There are no delay slots on ZARCH_64. -} - void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { // tmp must be unused assert(tmp->is_illegal(), "wasting a register if tmp is allocated"); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index a30bbe08c55..98759295bb1 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -3001,11 +3001,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ bind(next); } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { - Unimplemented(); -} - - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ lea(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index 15dbf070674..356c24760e8 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -1389,13 +1389,8 @@ void ADLParser::pipe_parse(void) { } if (!strcmp(ident, "branch_has_delay_slot")) { - skipws(); - if (_curchar == ';') { - next_char(); skipws(); - } - - pipeline->_branchHasDelaySlot = true; - continue; + parse_err(SYNERR, "Using obsolete token, branch_has_delay_slot"); + break; } if (!strcmp(ident, "max_instructions_per_bundle")) { @@ -1762,16 +1757,8 @@ void ADLParser::pipe_class_parse(PipelineForm &pipeline) { if (!strcmp(ident, "one_instruction_with_delay_slot") || !strcmp(ident, "single_instruction_with_delay_slot")) { - skipws(); - if (_curchar != ';') { - parse_err(SYNERR, "missing \";\" in latency definition\n"); - return; - } - - pipe_class->setInstructionCount(1); - pipe_class->setBranchDelay(true); - next_char(); skipws(); - continue; + parse_err(SYNERR, "Using obsolete token, %s", ident); + return; } if (!strcmp(ident, "one_instruction") || @@ -1831,15 +1818,8 @@ void ADLParser::pipe_class_parse(PipelineForm &pipeline) { } if (!strcmp(ident, "has_delay_slot")) { - skipws(); - if (_curchar != ';') { - parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n"); - return; - } - - pipe_class->setBranchDelay(true); - next_char(); skipws(); - continue; + parse_err(SYNERR, "Using obsolete token, %s", ident); + return; } if (!strcmp(ident, "force_serialization")) { diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 01fe6288c53..92489da2f5a 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -512,7 +512,6 @@ PipelineForm::PipelineForm() , _classlist () , _classcnt (0) , _variableSizeInstrs (false) - , _branchHasDelaySlot (false) , _maxInstrsPerBundle (0) , _maxBundlesPerCycle (1) , _instrUnitSize (0) @@ -546,8 +545,6 @@ void PipelineForm::output(FILE *fp) { // Write info to output files fprintf(fp," fixed-sized bundles of %d bytes", _bundleUnitSize); else fprintf(fp," fixed-sized instructions"); - if (_branchHasDelaySlot) - fprintf(fp,", branch has delay slot"); if (_maxInstrsPerBundle > 0) fprintf(fp,", max of %d instruction%s in parallel", _maxInstrsPerBundle, _maxInstrsPerBundle > 1 ? "s" : ""); @@ -637,7 +634,6 @@ PipeClassForm::PipeClassForm(const char *id, int num) , _fixed_latency(0) , _instruction_count(0) , _has_multiple_bundles(false) - , _has_branch_delay_slot(false) , _force_serialization(false) , _may_have_no_code(false) { } diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index db7b9dbd8d8..34cbc24bed0 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.hpp @@ -387,7 +387,6 @@ public: int _classcnt; // Number of classes bool _variableSizeInstrs; // Indicates if this architecture has variable sized instructions - bool _branchHasDelaySlot; // Indicates that branches have delay slot instructions int _maxInstrsPerBundle; // Indicates the maximum number of instructions for ILP int _maxBundlesPerCycle; // Indicates the maximum number of bundles for ILP int _instrUnitSize; // The minimum instruction unit size, in bytes @@ -499,7 +498,6 @@ public: int _fixed_latency; // Always takes this number of cycles int _instruction_count; // Number of instructions in first bundle bool _has_multiple_bundles; // Indicates if 1 or multiple bundles - bool _has_branch_delay_slot; // Has branch delay slot as last instruction bool _force_serialization; // This node serializes relative to surrounding nodes bool _may_have_no_code; // This node may generate no code based on register allocation @@ -518,13 +516,11 @@ public: void setInstructionCount(int i) { _instruction_count = i; } void setMultipleBundles(bool b) { _has_multiple_bundles = b; } - void setBranchDelay(bool s) { _has_branch_delay_slot = s; } void setForceSerialization(bool s) { _force_serialization = s; } void setMayHaveNoCode(bool s) { _may_have_no_code = s; } int InstructionCount() const { return _instruction_count; } bool hasMultipleBundles() const { return _has_multiple_bundles; } - bool hasBranchDelay() const { return _has_branch_delay_slot; } bool forceSerialization() const { return _force_serialization; } bool mayHaveNoCode() const { return _may_have_no_code; } diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index abebf39a2b2..caf2c9952a6 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -794,8 +794,8 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { // Create the pipeline class description - fprintf(fp_cpp, "static const Pipeline pipeline_class_Zero_Instructions(0, 0, true, 0, 0, false, false, false, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); - fprintf(fp_cpp, "static const Pipeline pipeline_class_Unknown_Instructions(0, 0, true, 0, 0, false, true, true, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); + fprintf(fp_cpp, "static const Pipeline pipeline_class_Zero_Instructions(0, 0, true, 0, 0, false, false, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); + fprintf(fp_cpp, "static const Pipeline pipeline_class_Unknown_Instructions(0, 0, true, 0, 0, true, true, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); fprintf(fp_cpp, "const Pipeline_Use_Element Pipeline_Use::elaborated_elements[%d] = {\n", _pipeline->_rescount); for (int i1 = 0; i1 < _pipeline->_rescount; i1++) { @@ -895,12 +895,11 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { fprintf(fp_cpp, "(uint)stage_%s", _pipeline->_stages.name(maxWriteStage)); else fprintf(fp_cpp, "((uint)stage_%s)+%d", _pipeline->_stages.name(maxWriteStage), maxMoreInstrs); - fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s, %s,\n", + fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s,\n", paramcount, pipeclass->hasFixedLatency() ? "true" : "false", pipeclass->fixedLatency(), pipeclass->InstructionCount(), - pipeclass->hasBranchDelay() ? "true" : "false", pipeclass->hasMultipleBundles() ? "true" : "false", pipeclass->forceSerialization() ? "true" : "false", pipeclass->mayHaveNoCode() ? "true" : "false" ); @@ -979,16 +978,6 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { fprintf(fp_cpp, "#ifndef PRODUCT\n"); fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n"); - fprintf(fp_cpp, " static const char * bundle_flags[] = {\n"); - fprintf(fp_cpp, " \"\",\n"); - fprintf(fp_cpp, " \"use nop delay\",\n"); - fprintf(fp_cpp, " \"use unconditional delay\",\n"); - fprintf(fp_cpp, " \"use conditional delay\",\n"); - fprintf(fp_cpp, " \"used in conditional delay\",\n"); - fprintf(fp_cpp, " \"used in unconditional delay\",\n"); - fprintf(fp_cpp, " \"used in all conditional delays\",\n"); - fprintf(fp_cpp, " };\n\n"); - fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount); // Don't add compound resources to the list of resource names const char* resource; @@ -1003,12 +992,8 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { // See if the same string is in the table fprintf(fp_cpp, " bool needs_comma = false;\n\n"); - fprintf(fp_cpp, " if (_flags) {\n"); - fprintf(fp_cpp, " st->print(\"%%s\", bundle_flags[_flags]);\n"); - fprintf(fp_cpp, " needs_comma = true;\n"); - fprintf(fp_cpp, " };\n"); fprintf(fp_cpp, " if (instr_count()) {\n"); - fprintf(fp_cpp, " st->print(\"%%s%%d instr%%s\", needs_comma ? \", \" : \"\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n"); + fprintf(fp_cpp, " st->print(\"%%d instr%%s\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n"); fprintf(fp_cpp, " needs_comma = true;\n"); fprintf(fp_cpp, " };\n"); fprintf(fp_cpp, " uint r = resources_used();\n"); diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index 78cf5ea7988..e3fde235443 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -935,8 +935,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { _pipeline->_variableSizeInstrs ? 1 : 0); fprintf(fp_hpp, " _fixed_size_instructions = %d,\n", _pipeline->_variableSizeInstrs ? 0 : 1); - fprintf(fp_hpp, " _branch_has_delay_slot = %d,\n", - _pipeline->_branchHasDelaySlot ? 1 : 0); fprintf(fp_hpp, " _max_instrs_per_bundle = %d,\n", _pipeline->_maxInstrsPerBundle); fprintf(fp_hpp, " _max_bundles_per_cycle = %d,\n", @@ -983,7 +981,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " const unsigned char _fixed_latency;\n"); fprintf(fp_hpp, " const unsigned char _instruction_count;\n"); fprintf(fp_hpp, " const bool _has_fixed_latency;\n"); - fprintf(fp_hpp, " const bool _has_branch_delay;\n"); fprintf(fp_hpp, " const bool _has_multiple_bundles;\n"); fprintf(fp_hpp, " const bool _force_serialization;\n"); fprintf(fp_hpp, " const bool _may_have_no_code;\n"); @@ -998,7 +995,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " bool has_fixed_latency,\n"); fprintf(fp_hpp, " uint fixed_latency,\n"); fprintf(fp_hpp, " uint instruction_count,\n"); - fprintf(fp_hpp, " bool has_branch_delay,\n"); fprintf(fp_hpp, " bool has_multiple_bundles,\n"); fprintf(fp_hpp, " bool force_serialization,\n"); fprintf(fp_hpp, " bool may_have_no_code,\n"); @@ -1011,7 +1007,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " , _fixed_latency(fixed_latency)\n"); fprintf(fp_hpp, " , _instruction_count(instruction_count)\n"); fprintf(fp_hpp, " , _has_fixed_latency(has_fixed_latency)\n"); - fprintf(fp_hpp, " , _has_branch_delay(has_branch_delay)\n"); fprintf(fp_hpp, " , _has_multiple_bundles(has_multiple_bundles)\n"); fprintf(fp_hpp, " , _force_serialization(force_serialization)\n"); fprintf(fp_hpp, " , _may_have_no_code(may_have_no_code)\n"); @@ -1046,8 +1041,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " return (_resource_use._count); }\n\n"); fprintf(fp_hpp, " uint instructionCount() const {\n"); fprintf(fp_hpp, " return (_instruction_count); }\n\n"); - fprintf(fp_hpp, " bool hasBranchDelay() const {\n"); - fprintf(fp_hpp, " return (_has_branch_delay); }\n\n"); fprintf(fp_hpp, " bool hasMultipleBundles() const {\n"); fprintf(fp_hpp, " return (_has_multiple_bundles); }\n\n"); fprintf(fp_hpp, " bool forceSerialization() const {\n"); @@ -1071,50 +1064,19 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { uint rshift = rescount; fprintf(fp_hpp, "protected:\n"); - fprintf(fp_hpp, " enum {\n"); - fprintf(fp_hpp, " _unused_delay = 0x%x,\n", 0); - fprintf(fp_hpp, " _use_nop_delay = 0x%x,\n", 1); - fprintf(fp_hpp, " _use_unconditional_delay = 0x%x,\n", 2); - fprintf(fp_hpp, " _use_conditional_delay = 0x%x,\n", 3); - fprintf(fp_hpp, " _used_in_conditional_delay = 0x%x,\n", 4); - fprintf(fp_hpp, " _used_in_unconditional_delay = 0x%x,\n", 5); - fprintf(fp_hpp, " _used_in_all_conditional_delays = 0x%x,\n", 6); - fprintf(fp_hpp, "\n"); - fprintf(fp_hpp, " _use_delay = 0x%x,\n", 3); - fprintf(fp_hpp, " _used_in_delay = 0x%x\n", 4); - fprintf(fp_hpp, " };\n\n"); - fprintf(fp_hpp, " uint _flags : 3,\n"); - fprintf(fp_hpp, " _starts_bundle : 1,\n"); + fprintf(fp_hpp, " uint _starts_bundle : 1,\n"); fprintf(fp_hpp, " _instr_count : %d,\n", mshift); fprintf(fp_hpp, " _resources_used : %d;\n", rshift); fprintf(fp_hpp, "public:\n"); - fprintf(fp_hpp, " Bundle() : _flags(_unused_delay), _starts_bundle(0), _instr_count(0), _resources_used(0) {}\n\n"); + fprintf(fp_hpp, " Bundle() : _starts_bundle(0), _instr_count(0), _resources_used(0) {}\n\n"); fprintf(fp_hpp, " void set_instr_count(uint i) { _instr_count = i; }\n"); fprintf(fp_hpp, " void set_resources_used(uint i) { _resources_used = i; }\n"); - fprintf(fp_hpp, " void clear_usage() { _flags = _unused_delay; }\n"); fprintf(fp_hpp, " void set_starts_bundle() { _starts_bundle = true; }\n"); - fprintf(fp_hpp, " uint flags() const { return (_flags); }\n"); fprintf(fp_hpp, " uint instr_count() const { return (_instr_count); }\n"); fprintf(fp_hpp, " uint resources_used() const { return (_resources_used); }\n"); fprintf(fp_hpp, " bool starts_bundle() const { return (_starts_bundle != 0); }\n"); - fprintf(fp_hpp, " void set_use_nop_delay() { _flags = _use_nop_delay; }\n"); - fprintf(fp_hpp, " void set_use_unconditional_delay() { _flags = _use_unconditional_delay; }\n"); - fprintf(fp_hpp, " void set_use_conditional_delay() { _flags = _use_conditional_delay; }\n"); - fprintf(fp_hpp, " void set_used_in_unconditional_delay() { _flags = _used_in_unconditional_delay; }\n"); - fprintf(fp_hpp, " void set_used_in_conditional_delay() { _flags = _used_in_conditional_delay; }\n"); - fprintf(fp_hpp, " void set_used_in_all_conditional_delays() { _flags = _used_in_all_conditional_delays; }\n"); - - fprintf(fp_hpp, " bool use_nop_delay() { return (_flags == _use_nop_delay); }\n"); - fprintf(fp_hpp, " bool use_unconditional_delay() { return (_flags == _use_unconditional_delay); }\n"); - fprintf(fp_hpp, " bool use_conditional_delay() { return (_flags == _use_conditional_delay); }\n"); - fprintf(fp_hpp, " bool used_in_unconditional_delay() { return (_flags == _used_in_unconditional_delay); }\n"); - fprintf(fp_hpp, " bool used_in_conditional_delay() { return (_flags == _used_in_conditional_delay); }\n"); - fprintf(fp_hpp, " bool used_in_all_conditional_delays() { return (_flags == _used_in_all_conditional_delays); }\n"); - fprintf(fp_hpp, " bool use_delay() { return ((_flags & _use_delay) != 0); }\n"); - fprintf(fp_hpp, " bool used_in_delay() { return ((_flags & _used_in_delay) != 0); }\n\n"); - fprintf(fp_hpp, "#ifndef PRODUCT\n"); fprintf(fp_hpp, " void dump(outputStream *st = tty) const;\n"); fprintf(fp_hpp, "#endif\n"); diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index 4c8ebd5a09d..f11e178bd55 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -800,15 +800,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { } -// LIR_OpDelay - case lir_delay_slot: { - assert(op->as_OpDelay() != nullptr, "must be"); - LIR_OpDelay* opDelay = (LIR_OpDelay*)op; - - visit(opDelay->delay_op()); - break; - } - // LIR_OpTypeCheck case lir_instanceof: case lir_checkcast: @@ -1073,10 +1064,6 @@ void LIR_OpAssert::emit_code(LIR_Assembler* masm) { } #endif -void LIR_OpDelay::emit_code(LIR_Assembler* masm) { - masm->emit_delay(this); -} - void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) { masm->emit_profile_call(this); } @@ -1761,8 +1748,6 @@ const char * LIR_Op::name() const { // LIR_OpLock case lir_lock: s = "lock"; break; case lir_unlock: s = "unlock"; break; - // LIR_OpDelay - case lir_delay_slot: s = "delay"; break; // LIR_OpTypeCheck case lir_instanceof: s = "instanceof"; break; case lir_checkcast: s = "checkcast"; break; @@ -2044,11 +2029,6 @@ void LIR_OpAssert::print_instr(outputStream* out) const { #endif -void LIR_OpDelay::print_instr(outputStream* out) const { - _op->print_on(out); -} - - // LIR_OpProfileCall void LIR_OpProfileCall::print_instr(outputStream* out) const { profiled_method()->name()->print_symbol_on(out); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index c7726bf5c3f..0427c868e6f 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -879,7 +879,6 @@ class LIR_OpConvert; class LIR_OpAllocObj; class LIR_OpReturn; class LIR_Op2; -class LIR_OpDelay; class LIR_Op3; class LIR_OpAllocArray; class LIR_Op4; @@ -985,9 +984,6 @@ enum LIR_Code { , lir_lock , lir_unlock , end_opLock - , begin_delay_slot - , lir_delay_slot - , end_delay_slot , begin_opTypeCheck , lir_instanceof , lir_checkcast @@ -1124,7 +1120,6 @@ class LIR_Op: public CompilationResourceObj { virtual LIR_OpCall* as_OpCall() { return nullptr; } virtual LIR_OpJavaCall* as_OpJavaCall() { return nullptr; } virtual LIR_OpLabel* as_OpLabel() { return nullptr; } - virtual LIR_OpDelay* as_OpDelay() { return nullptr; } virtual LIR_OpLock* as_OpLock() { return nullptr; } virtual LIR_OpAllocArray* as_OpAllocArray() { return nullptr; } virtual LIR_OpAllocObj* as_OpAllocObj() { return nullptr; } @@ -1886,25 +1881,6 @@ class LIR_OpLoadKlass: public LIR_Op { void print_instr(outputStream* out) const PRODUCT_RETURN; }; -class LIR_OpDelay: public LIR_Op { - friend class LIR_OpVisitState; - - private: - LIR_Op* _op; - - public: - LIR_OpDelay(LIR_Op* op, CodeEmitInfo* info): - LIR_Op(lir_delay_slot, LIR_OprFact::illegalOpr, info), - _op(op) { - assert(op->code() == lir_nop, "should be filling with nops"); - } - virtual void emit_code(LIR_Assembler* masm); - virtual LIR_OpDelay* as_OpDelay() { return this; } - void print_instr(outputStream* out) const PRODUCT_RETURN; - LIR_Op* delay_op() const { return _op; } - CodeEmitInfo* call_info() const { return info(); } -}; - #ifdef ASSERT // LIR_OpAssert class LIR_OpAssert : public LIR_Op2 { diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 7cf414ae7dc..6dbd35f054f 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -194,8 +194,7 @@ void LIR_Assembler::emit_exception_entries(ExceptionInfoList* info_list) { XHandler* handler = handlers->handler_at(j); assert(handler->lir_op_id() != -1, "handler not processed by LinearScan"); assert(handler->entry_code() == nullptr || - handler->entry_code()->instructions_list()->last()->code() == lir_branch || - handler->entry_code()->instructions_list()->last()->code() == lir_delay_slot, "last operation must be branch"); + handler->entry_code()->instructions_list()->last()->code() == lir_branch, "last operation must be branch"); if (handler->entry_pco() == -1) { // entry code not emitted yet diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index a4c5fd61d4c..4cb313af901 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 +154,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_block(BlockBegin* block); void emit_lir_list(LIR_List* list); - // any last minute peephole optimizations are performed here. In - // particular sparc uses this for delay slot filling. + // any last minute peephole optimizations are performed here. void peephole(LIR_List* list); void return_op(LIR_Opr result, C1SafepointPollStub* code_stub); @@ -204,7 +203,6 @@ class LIR_Assembler: public CompilationResourceObj { void emit_rtcall(LIR_OpRTCall* op); void emit_profile_call(LIR_OpProfileCall* op); void emit_profile_type(LIR_OpProfileType* op); - void emit_delay(LIR_OpDelay* op); void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info); void arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 714a964b28d..a6a08815d10 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -186,8 +186,7 @@ class nmethod; // relative offset. (Both n and l are relative to the call's first byte.) // // The limit l of the search is exclusive. However, if it points within -// the call (e.g., offset zero), it is adjusted to point after the call and -// any associated machine-specific delay slot. +// the call (e.g., offset zero), it is adjusted to point after the call. // // Since the offsets could be as wide as 32-bits, these conventions // put no restrictions whatever upon code reorganization. @@ -1109,7 +1108,6 @@ class virtual_call_Relocation : public CallRelocation { // data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll] // oop_limit is set to 0 if the limit falls somewhere within the call. // When unpacking, a zero oop_limit is taken to refer to the end of the call. - // (This has the effect of bringing in the call's delay slot on SPARC.) void pack_data_to(CodeSection* dest) override; void unpack_data() override; diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 9a6970ebf20..90d24b609a7 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -106,12 +106,6 @@ private: // Remember the next node Node *_next_node; - // Use this for an unconditional branch delay slot - Node *_unconditional_delay_slot; - - // Pointer to a Nop - MachNopNode *_nop; - // Length of the current bundle, in instructions uint _bundle_instr_count; @@ -128,9 +122,6 @@ private: public: Scheduling(Arena *arena, Compile &compile); - // Destructor - NOT_PRODUCT( ~Scheduling(); ) - // Step ahead "i" cycles void step(uint i); @@ -194,10 +185,7 @@ public: #ifndef PRODUCT private: // Gather information on size of nops relative to total - uint _branches, _unconditional_delays; - static uint _total_nop_size, _total_method_size; - static uint _total_branches, _total_unconditional_delays; static uint _total_instructions_per_bundle[Pipeline::_max_instrs_per_cycle+1]; public: @@ -1472,7 +1460,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } // Now fill in the code buffer - Node* delay_slot = nullptr; for (uint i = 0; i < nblocks; i++) { Block* block = C->cfg()->get_block(i); _block = block; @@ -1511,15 +1498,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { // Get the node Node* n = block->get_node(j); - // See if delay slots are supported - if (valid_bundle_info(n) && node_bundling(n)->used_in_unconditional_delay()) { - assert(delay_slot == nullptr, "no use of delay slot node"); - assert(n->size(C->regalloc()) == Pipeline::instr_unit_size(), "delay slot instruction wrong size"); - - delay_slot = n; - continue; - } - // If this starts a new instruction group, then flush the current one // (but allow split bundles) if (Pipeline::requires_bundling() && starts_bundle(n)) @@ -1538,9 +1516,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { current_offset = masm->offset(); } - // A padding may be needed again since a previous instruction - // could be moved to delay slot. - // align the instruction if necessary int padding = mach->compute_padding(current_offset); // Make sure safepoint node for polling is distinct from a call's @@ -1613,13 +1588,10 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { // This requires the TRUE branch target be in succs[0] uint block_num = block->non_connector_successor(0)->_pre_order; - // Try to replace long branch if delay slot is not used, + // Try to replace long branch, // it is mostly for back branches since forward branch's // distance is not updated yet. - bool delay_slot_is_used = valid_bundle_info(n) && - C->output()->node_bundling(n)->use_unconditional_delay(); - if (!delay_slot_is_used && mach->may_be_short_branch()) { - assert(delay_slot == nullptr, "not expecting delay slot node"); + if (mach->may_be_short_branch()) { int br_size = n->size(C->regalloc()); int offset = blk_starts[block_num] - current_offset; if (block_num >= i) { @@ -1753,44 +1725,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { last_avoid_back_to_back_offset = current_offset; } - // See if this instruction has a delay slot - if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) { - guarantee(delay_slot != nullptr, "expecting delay slot node"); - - // Back up 1 instruction - masm->code()->set_insts_end(masm->code()->insts_end() - Pipeline::instr_unit_size()); - - // Save the offset for the listing -#if defined(SUPPORT_OPTO_ASSEMBLY) - if ((node_offsets != nullptr) && (delay_slot->_idx < node_offset_limit)) { - node_offsets[delay_slot->_idx] = masm->offset(); - } -#endif - - // Support a SafePoint in the delay slot - if (delay_slot->is_MachSafePoint()) { - MachNode *mach = delay_slot->as_Mach(); - // !!!!! Stubs only need an oopmap right now, so bail out - if (!mach->is_MachCall() && mach->as_MachSafePoint()->jvms()->method() == nullptr) { - // Write the oopmap directly to the code blob??!! - delay_slot = nullptr; - continue; - } - - int adjusted_offset = current_offset - Pipeline::instr_unit_size(); - non_safepoints.observe_safepoint(mach->as_MachSafePoint()->jvms(), - adjusted_offset); - // Generate an OopMap entry - Process_OopMap_Node(mach, adjusted_offset); - } - - // Insert the delay slot instruction - delay_slot->emit(masm, C->regalloc()); - - // Don't reuse it - delay_slot = nullptr; - } - } // End for all instructions in block // If the next block is the top of a loop, pad this block out to align @@ -2031,8 +1965,6 @@ void PhaseOutput::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_s #ifndef PRODUCT uint Scheduling::_total_nop_size = 0; uint Scheduling::_total_method_size = 0; -uint Scheduling::_total_branches = 0; -uint Scheduling::_total_unconditional_delays = 0; uint Scheduling::_total_instructions_per_bundle[Pipeline::_max_instrs_per_cycle+1]; #endif @@ -2050,14 +1982,7 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) _bundle_instr_count(0), _bundle_cycle_number(0), _bundle_use(0, 0, resource_count, &_bundle_use_elements[0]) -#ifndef PRODUCT - , _branches(0) - , _unconditional_delays(0) -#endif { - // Create a MachNopNode - _nop = new MachNopNode(); - // Save the count _node_bundling_limit = compile.unique(); uint node_max = _regalloc->node_regs_max_index(); @@ -2087,14 +2012,6 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) _next_node = block->get_node(block->number_of_nodes() - 1); } -#ifndef PRODUCT -// Scheduling destructor -Scheduling::~Scheduling() { - _total_branches += _branches; - _total_unconditional_delays += _unconditional_delays; -} -#endif - // Step ahead "i" cycles void Scheduling::step(uint i) { @@ -2199,15 +2116,6 @@ void PhaseOutput::print_scheduling(outputStream* output_stream) { bool Scheduling::NodeFitsInBundle(Node *n) { uint n_idx = n->_idx; - // If this is the unconditional delay instruction, then it fits - if (n == _unconditional_delay_slot) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# NodeFitsInBundle [%4d]: TRUE; is in unconditional delay slot\n", n->_idx); -#endif - return (true); - } - // If the node cannot be scheduled this cycle, skip it if (_current_latency[n_idx] > _bundle_cycle_number) { #ifndef PRODUCT @@ -2223,8 +2131,6 @@ bool Scheduling::NodeFitsInBundle(Node *n) { uint instruction_count = node_pipeline->instructionCount(); if (node_pipeline->mayHaveNoCode() && n->size(_regalloc) == 0) instruction_count = 0; - else if (node_pipeline->hasBranchDelay() && !_unconditional_delay_slot) - instruction_count++; if (_bundle_instr_count + instruction_count > Pipeline::_max_instrs_per_cycle) { #ifndef PRODUCT @@ -2436,99 +2342,6 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { const Pipeline *node_pipeline = n->pipeline(); const Pipeline_Use& node_usage = node_pipeline->resourceUse(); - // Check for instructions to be placed in the delay slot. We - // do this before we actually schedule the current instruction, - // because the delay slot follows the current instruction. - if (Pipeline::_branch_has_delay_slot && - node_pipeline->hasBranchDelay() && - !_unconditional_delay_slot) { - - uint siz = _available.size(); - - // Conditional branches can support an instruction that - // is unconditionally executed and not dependent by the - // branch, OR a conditionally executed instruction if - // the branch is taken. In practice, this means that - // the first instruction at the branch target is - // copied to the delay slot, and the branch goes to - // the instruction after that at the branch target - if ( n->is_MachBranch() ) { - - assert( !n->is_MachNullCheck(), "should not look for delay slot for Null Check" ); - assert( !n->is_Catch(), "should not look for delay slot for Catch" ); - -#ifndef PRODUCT - _branches++; -#endif - - // At least 1 instruction is on the available list - // that is not dependent on the branch - for (uint i = 0; i < siz; i++) { - Node *d = _available[i]; - const Pipeline *avail_pipeline = d->pipeline(); - - // Don't allow safepoints in the branch shadow, that will - // cause a number of difficulties - if ( avail_pipeline->instructionCount() == 1 && - !avail_pipeline->hasMultipleBundles() && - !avail_pipeline->hasBranchDelay() && - Pipeline::instr_has_unit_size() && - d->size(_regalloc) == Pipeline::instr_unit_size() && - NodeFitsInBundle(d) && - !node_bundling(d)->used_in_delay()) { - - if (d->is_Mach() && !d->is_MachSafePoint()) { - // A node that fits in the delay slot was found, so we need to - // set the appropriate bits in the bundle pipeline information so - // that it correctly indicates resource usage. Later, when we - // attempt to add this instruction to the bundle, we will skip - // setting the resource usage. - _unconditional_delay_slot = d; - node_bundling(n)->set_use_unconditional_delay(); - node_bundling(d)->set_used_in_unconditional_delay(); - _bundle_use.add_usage(avail_pipeline->resourceUse()); - _current_latency[d->_idx] = _bundle_cycle_number; - _next_node = d; - ++_bundle_instr_count; -#ifndef PRODUCT - _unconditional_delays++; -#endif - break; - } - } - } - } - - // No delay slot, add a nop to the usage - if (!_unconditional_delay_slot) { - // See if adding an instruction in the delay slot will overflow - // the bundle. - if (!NodeFitsInBundle(_nop)) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(1 instruction for delay slot) ***\n"); -#endif - step(1); - } - - _bundle_use.add_usage(_nop->pipeline()->resourceUse()); - _next_node = _nop; - ++_bundle_instr_count; - } - - // See if the instruction in the delay slot requires a - // step of the bundles - if (!NodeFitsInBundle(n)) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(branch won't fit) ***\n"); -#endif - // Update the state information - _bundle_instr_count = 0; - _bundle_cycle_number += 1; - _bundle_use.step(1); - } - } // Get the number of instructions uint instruction_count = node_pipeline->instructionCount(); @@ -2556,47 +2369,40 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { } } - // If this was placed in the delay slot, ignore it - if (n != _unconditional_delay_slot) { - - if (delay == 0) { - if (node_pipeline->hasMultipleBundles()) { + if (delay == 0) { + if (node_pipeline->hasMultipleBundles()) { #ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(multiple instructions) ***\n"); + if (_cfg->C->trace_opto_output()) + tty->print("# *** STEP(multiple instructions) ***\n"); #endif - step(1); - } - - else if (instruction_count + _bundle_instr_count > Pipeline::_max_instrs_per_cycle) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(%d >= %d instructions) ***\n", - instruction_count + _bundle_instr_count, - Pipeline::_max_instrs_per_cycle); -#endif - step(1); - } + step(1); } - if (node_pipeline->hasBranchDelay() && !_unconditional_delay_slot) - _bundle_instr_count++; - - // Set the node's latency - _current_latency[n->_idx] = _bundle_cycle_number; - - // Now merge the functional unit information - if (instruction_count > 0 || !node_pipeline->mayHaveNoCode()) - _bundle_use.add_usage(node_usage); - - // Increment the number of instructions in this bundle - _bundle_instr_count += instruction_count; - - // Remember this node for later - if (n->is_Mach()) - _next_node = n; + else if (instruction_count + _bundle_instr_count > Pipeline::_max_instrs_per_cycle) { +#ifndef PRODUCT + if (_cfg->C->trace_opto_output()) + tty->print("# *** STEP(%d >= %d instructions) ***\n", + instruction_count + _bundle_instr_count, + Pipeline::_max_instrs_per_cycle); +#endif + step(1); + } } + // Set the node's latency + _current_latency[n->_idx] = _bundle_cycle_number; + + // Now merge the functional unit information + if (instruction_count > 0 || !node_pipeline->mayHaveNoCode()) + _bundle_use.add_usage(node_usage); + + // Increment the number of instructions in this bundle + _bundle_instr_count += instruction_count; + + // Remember this node for later + if (n->is_Mach()) + _next_node = n; + // It's possible to have a BoxLock in the graph and in the _bbs mapping but // not in the bb->_nodes array. This happens for debug-info-only BoxLocks. // 'Schedule' them (basically ignore in the schedule) but do not insert them @@ -2647,9 +2453,6 @@ void Scheduling::ComputeUseCount(const Block *bb) { _available.clear(); _scheduled.clear(); - // No delay slot specified - _unconditional_delay_slot = nullptr; - #ifdef ASSERT for( uint i=0; i < bb->number_of_nodes(); i++ ) assert( _uses[bb->get_node(i)->_idx] == 0, "_use array not clean" ); @@ -2767,11 +2570,7 @@ void Scheduling::DoScheduling() { break; // Funny loop structure to be sure... } // Compute last "interesting" instruction in block - last instruction we - // might schedule. _bb_end points just after last schedulable inst. We - // normally schedule conditional branches (despite them being forced last - // in the block), because they have delay slots we can fill. Calls all - // have their delay slots filled in the template expansions, so we don't - // bother scheduling them. + // might schedule. _bb_end points just after last schedulable inst. Node *last = bb->get_node(_bb_end); // Ignore trailing NOPs. while (_bb_end > 0 && last->is_Mach() && @@ -2837,7 +2636,7 @@ void Scheduling::DoScheduling() { Node *n = bb->get_node(j); if( valid_bundle_info(n) ) { Bundle *bundle = node_bundling(n); - if (bundle->instr_count() > 0 || bundle->flags() > 0) { + if (bundle->instr_count() > 0) { tty->print("*** Bundle: "); bundle->dump(); } @@ -3273,16 +3072,6 @@ void Scheduling::print_statistics() { ((double)_total_nop_size) / ((double) _total_method_size) * 100.0); tty->print("\n"); - // Print the number of branch shadows filled - if (Pipeline::_branch_has_delay_slot) { - tty->print("Of %d branches, %d had unconditional delay slots filled", - _total_branches, _total_unconditional_delays); - if (_total_branches > 0) - tty->print(", for %.2f%%", - ((double)_total_unconditional_delays) / ((double)_total_branches) * 100.0); - tty->print("\n"); - } - uint total_instructions = 0, total_bundles = 0; for (uint i = 1; i <= Pipeline::_max_instrs_per_cycle; i++) { @@ -3572,7 +3361,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { } // For all instructions - Node *delay = nullptr; for (uint j = 0; j < block->number_of_nodes(); j++) { if (VMThread::should_terminate()) { cut_short = true; @@ -3581,10 +3369,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { n = block->get_node(j); if (valid_bundle_info(n)) { Bundle* bundle = node_bundling(n); - if (bundle->used_in_unconditional_delay()) { - delay = n; - continue; - } if (bundle->starts_bundle()) { starts_bundle = '+'; } @@ -3617,29 +3401,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { st->cr(); } - // If we have an instruction with a delay slot, and have seen a delay, - // then back up and print it - if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) { - // Coverity finding - Explicit null dereferenced. - guarantee(delay != nullptr, "no unconditional delay instruction"); - if (WizardMode) delay->dump(); - - if (node_bundling(delay)->starts_bundle()) - starts_bundle = '+'; - if ((pcs != nullptr) && (n->_idx < pc_limit)) { - pc = pcs[n->_idx]; - st->print("%*.*x", pc_digits, pc_digits, pc); - } else { - st->fill_to(pc_digits); - } - st->print(" %c ", starts_bundle); - starts_bundle = ' '; - st->fill_to(prefix_len); - delay->format(C->regalloc(), st); - st->cr(); - delay = nullptr; - } - // Dump the exception table as well if( n->is_Catch() && (Verbose || WizardMode) ) { // Print the exception table for this offset @@ -3648,7 +3409,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { st->bol(); // Make sure we start on a new line } st->cr(); // one empty line between blocks - assert(cut_short || delay == nullptr, "no unconditional delay branch"); } // End of per-block dump if (cut_short) st->print_cr("*** disassembly is cut short ***"); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 60161643315..710d34c3ccb 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3502,8 +3502,6 @@ frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* curren if (cb != nullptr && cb->is_nmethod()) { nm = cb->as_nmethod(); method = nm->method(); - // scope_desc_near() must be used, instead of scope_desc_at() because on - // SPARC, the pcDesc can be on the delay slot after the call instruction. for (ScopeDesc *sd = nm->scope_desc_near(fr.pc()); sd != nullptr; sd = sd->sender()) { method = sd->method(); if (method != nullptr && method->has_reserved_stack_access()) { From 9e3fa3216fd4ebd73da6e003a7b767cf001a1169 Mon Sep 17 00:00:00 2001 From: Kazuhisa Takakuri Date: Wed, 10 Sep 2025 06:37:17 +0000 Subject: [PATCH 211/295] 8349288: runtime/os/windows/TestAvailableProcessors.java fails on localized Windows platform Reviewed-by: dholmes, alanb --- .../os/windows/TestAvailableProcessors.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java index 795b3d76e54..f15514d024e 100644 --- a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java +++ b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java @@ -34,6 +34,7 @@ * @run testng/othervm/native TestAvailableProcessors */ +import java.io.File; import java.io.IOException; import java.util.List; import java.util.HashSet; @@ -58,7 +59,23 @@ public class TestAvailableProcessors { private static String getWindowsVersion() throws IOException { String systeminfoPath = "systeminfo.exe"; - var processBuilder = new ProcessBuilder(systeminfoPath); + List command = new ArrayList<>(); + + String systemRoot = System.getenv("SystemRoot"); + if (systemRoot == null) { + systemRoot = System.getenv("WINDIR"); + if (systemRoot == null) { + throw new RuntimeException("SystemRoot or WINDIR environment variable is not set."); + } + } + String system32 = Path.of(systemRoot, "System32").toString(); + + // It switches the active code page to cp437, the default code page for US english. + command.addAll(List.of("cmd.exe", "/c", "set", "PATH=%PATH%;" + system32 + ";" + system32 + "\\wbem", "&&")); + command.addAll(List.of("chcp", "437", ">nul", "2>&1", "&&")); + command.add(systeminfoPath); + + var processBuilder = new ProcessBuilder(command); OutputAnalyzer outputAnalyzer = new OutputAnalyzer(processBuilder.start()); outputAnalyzer.shouldHaveExitValue(0); outputAnalyzer.shouldContain(osVersionMessage); From f3de386263e16e33c2812706cf41410da2cd58c6 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 10 Sep 2025 08:46:07 +0000 Subject: [PATCH 212/295] 8367309: Test runtime/os/windows/TestAvailableProcessors.java fails to compile after mis-merge Reviewed-by: shade, alanb --- .../jtreg/runtime/os/windows/TestAvailableProcessors.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java index f15514d024e..d5e5b1626b6 100644 --- a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java +++ b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java @@ -34,8 +34,10 @@ * @run testng/othervm/native TestAvailableProcessors */ -import java.io.File; + import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import java.util.HashSet; import java.util.Set; From 1d3364b00725f9d2afa8274e2244357a109be545 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 10 Sep 2025 09:45:05 +0000 Subject: [PATCH 213/295] 8365239: Spec Clarification - InterfaceAddress:getBroadcast() returning null for loop back address Reviewed-by: msheppar, djelinski, jpai --- src/java.base/share/classes/java/net/InterfaceAddress.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/net/InterfaceAddress.java b/src/java.base/share/classes/java/net/InterfaceAddress.java index 6df2de353e3..44b3456c6fc 100644 --- a/src/java.base/share/classes/java/net/InterfaceAddress.java +++ b/src/java.base/share/classes/java/net/InterfaceAddress.java @@ -63,8 +63,8 @@ public final class InterfaceAddress { * Only IPv4 networks have broadcast address therefore, in the case * of an IPv6 network, {@code null} will be returned. *

          - * Certain network interfaces, such as the loopback interface, do not support - * broadcasting and will also return {@code null}. + * Some network interfaces do not support broadcasting and may + * also return {@code null}. * * @return the {@code InetAddress} representing the broadcast * address or {@code null} if there is no broadcast address. From 5c9f60dc5a6e64be55819469bbf10948803d0fd5 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 10 Sep 2025 09:57:44 +0000 Subject: [PATCH 214/295] 8367259: Clean up make/scripts and bin directory Reviewed-by: erikj --- {make/scripts => bin}/generate-symbol-data.sh | 31 ++- {make/scripts => bin}/lic_check.sh | 4 +- {make/scripts => bin}/normalizer.pl | 0 bin/unshuffle_list.txt | 191 -------------- bin/unshuffle_patch.sh | 237 ------------------ .../scripts => bin}/update_copyright_year.sh | 0 {make/scripts => bin}/update_pch.sh | 12 +- make/autoconf/compare.sh.template | 2 +- make/scripts/{logger.sh => compare-logger.sh} | 0 .../hide_important_warnings_from_javac.sh | 36 --- 10 files changed, 43 insertions(+), 470 deletions(-) rename {make/scripts => bin}/generate-symbol-data.sh (83%) rename {make/scripts => bin}/lic_check.sh (98%) rename {make/scripts => bin}/normalizer.pl (100%) delete mode 100644 bin/unshuffle_list.txt delete mode 100644 bin/unshuffle_patch.sh rename {make/scripts => bin}/update_copyright_year.sh (100%) rename {make/scripts => bin}/update_pch.sh (92%) rename make/scripts/{logger.sh => compare-logger.sh} (100%) delete mode 100644 make/scripts/hide_important_warnings_from_javac.sh diff --git a/make/scripts/generate-symbol-data.sh b/bin/generate-symbol-data.sh similarity index 83% rename from make/scripts/generate-symbol-data.sh rename to bin/generate-symbol-data.sh index 6f38d873009..283757a6918 100644 --- a/make/scripts/generate-symbol-data.sh +++ b/bin/generate-symbol-data.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. # 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,12 +52,39 @@ # include the SCM state that was used to build it, which can be found in ${JDK_N_INSTALL}/release, # in property "SOURCE". +source_path="$(dirname ${0})" +this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)" +if test -z "${this_script_dir}"; then + echo "Error: Could not determine location of this script" + exit 1 +fi + +symbols_dir="$(dirname $this_script_dir)/src/jdk.compiler/share/data/symbols" +if [ ! -d $symbols_dir ] ; then + echo "Cannot locate symbols directory: $symbols_dir" >&2 + exit 1 +fi + +generator_dir="$(dirname $this_script_dir)/make/langtools/src/classes/build/tools/symbolgenerator" + if [ "$1x" = "x" ] ; then echo "Must provide the target JDK as a parameter:" >&2 echo "$0 " >&2 exit 1 fi; +if [ ! -d $1 ] ; then + echo "Target JDK argument is not a directory:" $1 >&2 + exit 1 +fi; + +if [ ! -x $1/bin/java ] ; then + echo "Target JDK argument is not a valid JDK: $1" >&2 + exit 1 +fi; + +cd $symbols_dir + if [ ! -f symbols ] ; then echo "Must run inside the src/jdk.compiler/share/data/symbols directory" >&2 exit 1 @@ -72,5 +99,5 @@ $1/bin/java --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ --add-modules jdk.jdeps \ - ../../../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ + $generator_dir/CreateSymbols.java \ build-description-incremental symbols include.list diff --git a/make/scripts/lic_check.sh b/bin/lic_check.sh similarity index 98% rename from make/scripts/lic_check.sh rename to bin/lic_check.sh index d70d8914181..2fc6abf4d82 100644 --- a/make/scripts/lic_check.sh +++ b/bin/lic_check.sh @@ -1,6 +1,6 @@ #! /bin/sh -f # -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. # 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 @@ B=`basename "${script_directory}"` script_dir="`cd \"${D}\" 2>/dev/null && pwd || echo \"${D}\"`/${B}" # set up a variable for the template directory -template_dir=${script_dir}/../data/license-templates +template_dir=${script_dir}/../make/data/license-templates # Check existence of the template directory. if [ ! -d ${template_dir} ] ; then diff --git a/make/scripts/normalizer.pl b/bin/normalizer.pl similarity index 100% rename from make/scripts/normalizer.pl rename to bin/normalizer.pl diff --git a/bin/unshuffle_list.txt b/bin/unshuffle_list.txt deleted file mode 100644 index a910f6b4621..00000000000 --- a/bin/unshuffle_list.txt +++ /dev/null @@ -1,191 +0,0 @@ -# -# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. -# 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. -# - -src/bsd : jdk/src/bsd -src/demo : jdk/src/demo -src/java.activation : jaxws/src/java.activation -src/java.base : jdk/src/java.base -src/java.compiler : langtools/src/java.compiler -src/java.corba : corba/src/java.corba -src/java.datatransfer : jdk/src/java.datatransfer -src/java.desktop : jdk/src/java.desktop -src/java.instrument : jdk/src/java.instrument -src/java.logging : jdk/src/java.logging -src/java.management : jdk/src/java.management -src/java.management.rmi : jdk/src/java.management.rmi -src/java.naming : jdk/src/java.naming -src/java.prefs : jdk/src/java.prefs -src/java.rmi : jdk/src/java.rmi -src/java.scripting : jdk/src/java.scripting -src/java.se : jdk/src/java.se -src/java.security.jgss : jdk/src/java.security.jgss -src/java.security.sasl : jdk/src/java.security.sasl -src/java.se.ee : jdk/src/java.se.ee -src/java.smartcardio : jdk/src/java.smartcardio -src/java.sql : jdk/src/java.sql -src/java.sql.rowset : jdk/src/java.sql.rowset -src/java.transaction : jdk/src/java.transaction -src/java.xml : jaxp/src/java.xml -src/java.xml.bind : jaxws/src/java.xml.bind -src/java.xml.crypto : jdk/src/java.xml.crypto -src/java.xml.ws : jaxws/src/java.xml.ws -src/java.xml.ws.annotation : jaxws/src/java.xml.ws.annotation -src/jdk.accessibility : jdk/src/jdk.accessibility -src/jdk.aot : hotspot/src/jdk.aot -src/jdk.attach : jdk/src/jdk.attach -src/jdk.charsets : jdk/src/jdk.charsets -src/jdk.compiler : jdk/src/jdk.compiler langtools/src/jdk.compiler -src/jdk.crypto.cryptoki : jdk/src/jdk.crypto.cryptoki -src/jdk.crypto.ec : jdk/src/jdk.crypto.ec -src/jdk.crypto.mscapi : jdk/src/jdk.crypto.mscapi -src/jdk.dynalink : nashorn/src/jdk.dynalink -src/jdk.editpad : jdk/src/jdk.editpad -src/jdk.hotspot.agent : hotspot/src/jdk.hotspot.agent -src/jdk.httpserver : jdk/src/jdk.httpserver -src/jdk.incubator.httpclient : jdk/src/jdk.incubator.httpclient -src/jdk.internal.ed : jdk/src/jdk.internal.ed -src/jdk.internal.jvmstat : jdk/src/jdk.internal.jvmstat -src/jdk.internal.le : jdk/src/jdk.internal.le -src/jdk.internal.opt : jdk/src/jdk.internal.opt -src/jdk.internal.vm.ci : hotspot/src/jdk.internal.vm.ci -src/jdk.internal.vm.compiler : hotspot/src/jdk.internal.vm.compiler -src/jdk.jartool : jdk/src/jdk.jartool -src/jdk.javadoc : langtools/src/jdk.javadoc -src/jdk.jcmd : jdk/src/jdk.jcmd -src/jdk.jconsole : jdk/src/jdk.jconsole -src/jdk.jdeps : langtools/src/jdk.jdeps -src/jdk.jdi : jdk/src/jdk.jdi -src/jdk.jdwp.agent : jdk/src/jdk.jdwp.agent -src/jdk.jlink : jdk/src/jdk.jlink -src/jdk.jshell : langtools/src/jdk.jshell -src/jdk.jstatd : jdk/src/jdk.jstatd -src/jdk.localedata : jdk/src/jdk.localedata -src/jdk.management : jdk/src/jdk.management -src/jdk.management.agent : jdk/src/jdk.management.agent -src/jdk.naming.dns : jdk/src/jdk.naming.dns -src/jdk.naming.rmi : jdk/src/jdk.naming.rmi -src/jdk.net : jdk/src/jdk.net -src/jdk.pack : jdk/src/jdk.pack -src/jdk.scripting.nashorn : nashorn/src/jdk.scripting.nashorn -src/jdk.scripting.nashorn.shell : nashorn/src/jdk.scripting.nashorn.shell -src/jdk.sctp : jdk/src/jdk.sctp -src/jdk.security.auth : jdk/src/jdk.security.auth -src/jdk.security.jgss : jdk/src/jdk.security.jgss -src/jdk.unsupported : jdk/src/jdk.unsupported -src/jdk.xml.bind : jaxws/src/jdk.xml.bind -src/jdk.xml.dom : jaxp/src/jdk.xml.dom -src/jdk.xml.ws : jaxws/src/jdk.xml.ws -src/jdk.zipfs : jdk/src/jdk.zipfs -src/langtools/sample : langtools/src/sample -src/linux : jdk/src/linux -src/sample : jdk/src/sample -src/hotspot/share : hotspot/src/share/vm -src/hotspot/cpu/aarch64 : hotspot/src/cpu/aarch64/vm -src/hotspot/cpu/arm : hotspot/src/cpu/arm/vm -src/hotspot/cpu/ppc : hotspot/src/cpu/ppc/vm -src/hotspot/cpu/s390 : hotspot/src/cpu/s390/vm -src/hotspot/cpu/x86 : hotspot/src/cpu/x86/vm -src/hotspot/cpu/zero : hotspot/src/cpu/zero/vm -src/hotspot/os/aix : hotspot/src/os/aix/vm -src/hotspot/os/bsd : hotspot/src/os/bsd/vm -src/hotspot/os/linux : hotspot/src/os/linux/vm -src/hotspot/os/posix/dtrace : hotspot/src/os/posix/dtrace -src/hotspot/os/posix : hotspot/src/os/posix/vm -src/hotspot/os/windows : hotspot/src/os/windows/vm -src/hotspot/os_cpu/aix_ppc : hotspot/src/os_cpu/aix_ppc/vm -src/hotspot/os_cpu/bsd_x86 : hotspot/src/os_cpu/bsd_x86/vm -src/hotspot/os_cpu/bsd_zero : hotspot/src/os_cpu/bsd_zero/vm -src/hotspot/os_cpu/linux_aarch64 : hotspot/src/os_cpu/linux_aarch64/vm -src/hotspot/os_cpu/linux_arm : hotspot/src/os_cpu/linux_arm/vm -src/hotspot/os_cpu/linux_ppc : hotspot/src/os_cpu/linux_ppc/vm -src/hotspot/os_cpu/linux_s390 : hotspot/src/os_cpu/linux_s390/vm -src/hotspot/os_cpu/linux_x86 : hotspot/src/os_cpu/linux_x86/vm -src/hotspot/os_cpu/linux_zero : hotspot/src/os_cpu/linux_zero/vm -src/hotspot/os_cpu/windows_x86 : hotspot/src/os_cpu/windows_x86/vm -src/hotspot : hotspot/src -src/utils/IdealGraphVisualizer : hotspot/src/share/tools/IdealGraphVisualizer -src/utils/LogCompilation : hotspot/src/share/tools/LogCompilation -src/utils/hsdis : hotspot/src/share/tools/hsdis -src/utils/reorder : jdk/make/non-build-utils/reorder -src/utils/src/build : jdk/make/non-build-utils/src/build -make/BuildNashorn.gmk : nashorn/make/BuildNashorn.gmk -make/CompileDemos.gmk : jdk/make/CompileDemos.gmk -make/CompileInterimLangtools.gmk : langtools/make/CompileInterim.gmk -make/CompileModuleTools.gmk : jdk/make/CompileModuleTools.gmk -make/CompileToolsHotspot.gmk : hotspot/make/CompileTools.gmk -make/CompileToolsJdk.gmk : jdk/make/CompileTools.gmk -make/CopyInterimCLDRConverter.gmk : jdk/make/CopyInterimCLDRConverter.gmk -make/GenerateModuleSummary.gmk : jdk/make/GenerateModuleSummary.gmk -make/ModuleTools.gmk : jdk/make/ModuleTools.gmk -make/ToolsJdk.gmk : jdk/make/Tools.gmk -make/ToolsLangtools.gmk : langtools/make/Tools.gmk -make/UnpackSecurity.gmk : jdk/make/UnpackSecurity.gmk -make/autoconf : common/autoconf -make/conf : common/conf -make/copy : jdk/make/copy -make/copy/Copy-java.corba.gmk : corba/make/copy/Copy-java.corba.gmk -make/corba : corba/make -make/data : jdk/make/data -make/gendata : jdk/make/gendata -make/gendata/Gendata-jdk.compiler.gmk : langtools/make/gendata/Gendata-jdk.compiler.gmk -make/gensrc : jdk/make/gensrc -make/gensrc/Gensrc-java.corba.gmk : corba/make/gensrc/Gensrc-java.corba.gmk -make/gensrc/Gensrc-jdk.compiler.gmk : langtools/make/gensrc/Gensrc-jdk.compiler.gmk -make/gensrc/Gensrc-jdk.hotspot.agent.gmk : hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk -make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk : hotspot/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk -make/gensrc/Gensrc-jdk.javadoc.gmk : langtools/make/gensrc/Gensrc-jdk.javadoc.gmk -make/gensrc/Gensrc-jdk.jdeps.gmk : langtools/make/gensrc/Gensrc-jdk.jdeps.gmk -make/gensrc/Gensrc-jdk.jshell.gmk : langtools/make/gensrc/Gensrc-jdk.jshell.gmk -make/gensrc/GensrcCommonLangtools.gmk : langtools/make/gensrc/GensrcCommon.gmk -make/hotspot : hotspot/make -make/jdk : jdk/make -make/langtools : langtools/make -make/launcher : jdk/make/launcher -make/lib : jdk/make/lib -make/lib/Lib-jdk.hotspot.agent.gmk : hotspot/make/lib/Lib-jdk.hotspot.agent.gmk -make/mapfiles : jdk/make/mapfiles -make/mapfiles/libjsig : hotspot/make/mapfiles/libjsig -make/mapfiles/libjvm_db : hotspot/make/mapfiles/libjvm_db -make/mapfiles/libjvm_dtrace : hotspot/make/mapfiles/libjvm_dtrace -make/mapfiles/libsaproc : hotspot/make/mapfiles/libsaproc -make/nashorn : nashorn/make -make/nb_native : common/nb_native -make/scripts/addNotices.sh : jdk/make/scripts/addNotices.sh -make/scripts/compare.sh : common/bin/compare.sh -make/scripts/compare_exceptions.sh.incl : common/bin/compare_exceptions.sh.incl -make/scripts/genExceptions.sh : jdk/make/scripts/genExceptions.sh -make/scripts/hide_important_warnings_from_javac.sh : common/bin/hide_important_warnings_from_javac.sh -make/scripts/logger.sh : common/bin/logger.sh -make/src/native/fixpath.c : common/src/fixpath.c -make/test/JtregNativeHotspot.gmk : hotspot/make/test/JtregNative.gmk -make/test/JtregNativeJdk.gmk : jdk/make/test/JtregNative.gmk -test/jdk : jdk/test -test/langtools : langtools/test -test/nashorn : nashorn/test -test/jaxp : jaxp/test -test/hotspot/gtest : hotspot/test/native -test/hotspot/jtreg : hotspot/test -bin : common/bin -bin/nashorn : nashorn/bin -doc : common/doc -doc/nashorn : nashorn/docs diff --git a/bin/unshuffle_patch.sh b/bin/unshuffle_patch.sh deleted file mode 100644 index c5cdc3851c3..00000000000 --- a/bin/unshuffle_patch.sh +++ /dev/null @@ -1,237 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. -# 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. -# - -# Script for updating a patch file as per the shuffled/unshuffled source location. - -usage() { - echo "Usage: $0 [-h|--help] [-v|--verbose] [-to9|-to10] [-r ] " - echo "where:" - echo " -to9 create patches appropriate for a JDK 9 source tree" - echo " When going to 9, the output patches will be suffixed with the" - echo " repo name" - echo " -to10 create patches appropriate for a JDK 10 source tree" - echo " -r specify repo for source patch, set to 'top' for top repo" - echo " is the input patch file, that needs shuffling/unshuffling" - echo " is the updated patch file " - echo " " - exit 1 -} - -SCRIPT_DIR=`dirname $0` -UNSHUFFLE_LIST=$SCRIPT_DIR"/unshuffle_list.txt" - -if [ ! -f "$UNSHUFFLE_LIST" ] ; then - echo "FATAL: cannot find $UNSHUFFLE_LIST" >&2 - exit 1 -fi - -vflag="false" -while [ $# -gt 0 ] -do - case $1 in - -h | --help ) - usage - ;; - - -v | --verbose ) - vflag="true" - ;; - - -r) - repo="$2" - shift - ;; - - -to9) - shuffle_to=9 - ;; - - -to10) - shuffle_to=10 - ;; - - -*) # bad option - usage - ;; - - * ) # non option - break - ;; - esac - shift -done - -# Make sure we have the right number of arguments -if [ ! $# -eq 2 ] ; then - echo "ERROR: Invalid number of arguments." >&2 - usage -fi - -# Check the given repo -repos="top corba jaxp jaxws jdk langtools nashorn hotspot" -found="false" -if [ -n "$repo" ]; then - for r in $repos ; do - if [ $repo = "$r" ] ; then - found="true" - break; - fi - done - if [ $found = "false" ] ; then - echo "ERROR: Unknown repo: $repo. Should be one of [$repos]." >&2 - usage - fi -fi - -if [ "$shuffle_to" != "9" -a "$shuffle_to" != "10" ]; then - echo "ERROR: Must pick either -to9 or -to10" - exit 1 -fi - -# When going to 10, a repo must be specified for the source patch -if [ "$shuffle_to" = "10" -a -z "$repo" ]; then - echo "ERROR: Must specify src repo for JDK 9 patch" - exit 1 -fi - -# Check given input/output files -input="$1" -if [ "x$input" = "x-" ] ; then - input="/dev/stdin" -fi - -if [ ! -f $input -a "x$input" != "x/dev/stdin" ] ; then - echo "ERROR: Cannot find input patch file: $input" >&2 - exit 1 -fi - -output="$2" -if [ "x$output" = "x-" ] ; then - output="/dev/stdout" -fi -base_output="$output" - -if [ "$shuffle_to" = "10" ]; then - if [ -f $output -a "x$output" != "x/dev/stdout" ] ; then - echo "ERROR: Output patch already exists: $output" >&2 - exit 1 - fi -else - for r in $repos; do - if [ -f "$output.$r" ]; then - echo "ERROR: Output patch already exists: $output.$r" >&2 - exit 1 - fi - done -fi - -verbose() { - if [ ${vflag} = "true" ] ; then - echo "$@" >&2 - fi -} - -unshuffle() { - line=$@ - verbose "Attempting to rewrite: \"$line\"" - - # Retrieve the file name - path= - if echo "$line" | egrep '^diff' > /dev/null ; then - if ! echo "$line" | egrep '\-\-git' > /dev/null ; then - echo "ERROR: Only git patches supported. Please use 'hg export --git ...'." >&2 - exit 1 - fi - path="`echo "$line" | sed -e s@'diff --git a/'@@ -e s@' b/.*$'@@`" - elif echo "$line" | egrep '^\-\-\-' > /dev/null ; then - path="`echo "$line" | sed -e s@'--- a/'@@`" - elif echo "$line" | egrep '^\+\+\+' > /dev/null ; then - path="`echo "$line" | sed s@'+++ b/'@@`" - fi - verbose "Extracted path: \"$path\"" - - # Find the most specific matches in the shuffle list - matches= - if [ -n "$repo" -a "$repo" != "top" ]; then - matchpath="$repo"/"$path"/x - else - matchpath="$path"/x - fi - while [ "$matchpath" != "" ] ; do - matchpath="`echo $matchpath | sed s@'\(.*\)/.*$'@'\1'@`" - - if [ "$shuffle_to" = "10" ] ; then - pattern=": $matchpath$" - else - pattern="^$matchpath :" - fi - verbose "Attempting to find \"$matchpath\"" - matches=`egrep "$pattern" "$UNSHUFFLE_LIST"` - if ! [ "x${matches}" = "x" ] ; then - verbose "Got matches: [$matches]" - break; - fi - - if ! echo "$matchpath" | egrep '.*/.*' > /dev/null ; then - break; - fi - done - - # Rewrite the line, if we have a match - if ! [ "x${matches}" = "x" ] ; then - shuffled="${matches%% : *}" - unshuffled="${matches#* : }" - patch_suffix_9="" - for r in $repos; do - if [ "$unshuffled" != "${unshuffled#$r}" ]; then - unshuffled="${unshuffled#$r\/}" - patch_suffix_9=".$r" - fi - done - verbose "shuffled: $shuffled" - verbose "unshuffled: $unshuffled" - verbose "patch_suffix_9: $patch_suffix_9" - if [ "$shuffle_to" = "10" ] ; then - newline="`echo "$line" | sed -e s@"$unshuffled"@"$shuffled"@g`" - else - newline="`echo "$line" | sed -e s@"$shuffled"@"$unshuffled"@g`" - output=$base_output$patch_suffix_9 - verbose "Writing to $output" - fi - verbose "Rewriting to \"$newline\"" - echo "$newline" >> $output - else - echo "WARNING: no match found for $path" - echo "$line" >> $output - fi -} - -while IFS= read -r line -do - if echo "$line" | egrep '^diff|^\-\-\-|^\+\+\+' > /dev/null ; then - unshuffle "$line" - else - printf "%s\n" "$line" >> $output - fi -done < "$input" diff --git a/make/scripts/update_copyright_year.sh b/bin/update_copyright_year.sh similarity index 100% rename from make/scripts/update_copyright_year.sh rename to bin/update_copyright_year.sh diff --git a/make/scripts/update_pch.sh b/bin/update_pch.sh similarity index 92% rename from make/scripts/update_pch.sh rename to bin/update_pch.sh index 534525353fd..d7871fdd753 100644 --- a/make/scripts/update_pch.sh +++ b/bin/update_pch.sh @@ -23,9 +23,19 @@ # The output of this script may require some degree of human curation: # - Redundant headers, e.g. both x.hpp, x.inline.hpp are included; # - Headers relative to a non-default feature should be protected by an -# appropriate 'if' clause to make sure all variants can build without +# appropriate 'if' clause to make sure all variants can build without # errors. +source_path="$(dirname ${0})" +this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)" +if test -z "${this_script_dir}"; then + echo "Error: Could not determine location of this script" + exit 1 +fi + +# Work in top directory +cd $this_script_dir/.. + # Time threshold for header compilation, if the time exceeds the # threshold the header will be precompiled. if [ -z "$MIN_MS" ]; then diff --git a/make/autoconf/compare.sh.template b/make/autoconf/compare.sh.template index bcb5608855a..84421035ab9 100644 --- a/make/autoconf/compare.sh.template +++ b/make/autoconf/compare.sh.template @@ -110,4 +110,4 @@ $MV $OUTPUTDIR/compare.log $OUTPUTDIR/compare.log.old 2> /dev/null export SCRIPT_DIR="$( cd "$( dirname "$0" )" > /dev/null && pwd )" -$BASH $TOPDIR/make/scripts/logger.sh $OUTPUTDIR/compare.log $BASH "$REAL_COMPARE_SCRIPT" "$@" +$BASH $TOPDIR/make/scripts/compare-logger.sh $OUTPUTDIR/compare.log $BASH "$REAL_COMPARE_SCRIPT" "$@" diff --git a/make/scripts/logger.sh b/make/scripts/compare-logger.sh similarity index 100% rename from make/scripts/logger.sh rename to make/scripts/compare-logger.sh diff --git a/make/scripts/hide_important_warnings_from_javac.sh b/make/scripts/hide_important_warnings_from_javac.sh deleted file mode 100644 index 392ed33247a..00000000000 --- a/make/scripts/hide_important_warnings_from_javac.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. -# 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. -# - -GREP=grep - -# -EXP="Note: Some input files use or override a deprecated API." -EXP="${EXP}|Note: Recompile with -Xlint:deprecation for details." -EXP="${EXP}|Note: Some input files use unchecked or unsafe operations." -EXP="${EXP}|Note: Recompile with -Xlint:unchecked for details." -EXP="${EXP}| warning" -EXP="${EXP}|uses or overrides a deprecated API." -EXP="${EXP}|uses unchecked or unsafe operations." -# -${GREP} --line-buffered -v -E "${EXP}" From 33244c82445994131a9168451275216916ce635c Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 10 Sep 2025 10:00:15 +0000 Subject: [PATCH 215/295] 8344030: Improved handling of TOOLCHAIN_PATH Reviewed-by: erikj --- make/autoconf/basic.m4 | 24 ++++-------------------- make/autoconf/basic_tools.m4 | 19 ++----------------- make/autoconf/build-performance.m4 | 7 +------ make/autoconf/flags-ldflags.m4 | 2 +- make/autoconf/toolchain.m4 | 17 ++++------------- make/autoconf/util_paths.m4 | 12 ++++++------ 6 files changed, 18 insertions(+), 63 deletions(-) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 2d3e071dd52..316bfc5037d 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -210,17 +210,8 @@ AC_DEFUN([BASIC_SETUP_XCODE_SYSROOT], if test $? -ne 0; then AC_MSG_ERROR([The xcodebuild tool in the devkit reports an error: $XCODEBUILD_OUTPUT]) fi - elif test "x$TOOLCHAIN_PATH" != x; then - UTIL_LOOKUP_PROGS(XCODEBUILD, xcodebuild, $TOOLCHAIN_PATH) - if test "x$XCODEBUILD" != x; then - XCODEBUILD_OUTPUT=`"$XCODEBUILD" -version 2>&1` - if test $? -ne 0; then - AC_MSG_WARN([Ignoring the located xcodebuild tool $XCODEBUILD due to an error: $XCODEBUILD_OUTPUT]) - XCODEBUILD= - fi - fi else - UTIL_LOOKUP_PROGS(XCODEBUILD, xcodebuild) + UTIL_LOOKUP_TOOLCHAIN_PROGS(XCODEBUILD, xcodebuild) if test "x$XCODEBUILD" != x; then XCODEBUILD_OUTPUT=`"$XCODEBUILD" -version 2>&1` if test $? -ne 0; then @@ -348,21 +339,11 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], # You can force the sysroot if the sysroot encoded into the compiler tools # is not correct. - AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root], - [alias for --with-sysroot for backwards compatibility])], - [SYSROOT=$with_sys_root] - ) - AC_ARG_WITH(sysroot, [AS_HELP_STRING([--with-sysroot], [use this directory as sysroot])], [SYSROOT=$with_sysroot] ) - AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], - [alias for --with-toolchain-path for backwards compatibility])], - [UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_tools_dir)] - ) - AC_ARG_WITH([toolchain-path], [AS_HELP_STRING([--with-toolchain-path], [prepend these directories when searching for toolchain binaries (compilers etc)])], [UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_toolchain_path)] @@ -371,6 +352,9 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], AC_ARG_WITH([xcode-path], [AS_HELP_STRING([--with-xcode-path], [set up toolchain on Mac OS using a path to an Xcode installation])]) + UTIL_DEPRECATED_ARG_WITH(sys-root) + UTIL_DEPRECATED_ARG_WITH(tools-dir) + if test "x$with_xcode_path" != x; then if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH], diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index 5815c55c962..5367db46679 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -207,29 +207,14 @@ AC_DEFUN([BASIC_CHECK_GNU_MAKE], UTIL_SETUP_TOOL(MAKE, [ # Try our hardest to locate a correct version of GNU make - UTIL_LOOKUP_PROGS(CHECK_GMAKE, gmake) + UTIL_LOOKUP_TOOLCHAIN_PROGS(CHECK_GMAKE, gmake) BASIC_CHECK_MAKE_VERSION("$CHECK_GMAKE", [gmake in PATH]) if test "x$FOUND_MAKE" = x; then - UTIL_LOOKUP_PROGS(CHECK_MAKE, make) + UTIL_LOOKUP_TOOLCHAIN_PROGS(CHECK_MAKE, make) BASIC_CHECK_MAKE_VERSION("$CHECK_MAKE", [make in PATH]) fi - if test "x$FOUND_MAKE" = x; then - if test "x$TOOLCHAIN_PATH" != x; then - # We have a toolchain path, check that as well before giving up. - OLD_PATH=$PATH - PATH=$TOOLCHAIN_PATH:$PATH - UTIL_LOOKUP_PROGS(CHECK_TOOLSDIR_GMAKE, gmake) - BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_GMAKE", [gmake in tools-dir]) - if test "x$FOUND_MAKE" = x; then - UTIL_LOOKUP_PROGS(CHECK_TOOLSDIR_MAKE, make) - BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_MAKE", [make in tools-dir]) - fi - PATH=$OLD_PATH - fi - fi - if test "x$FOUND_MAKE" = x; then AC_MSG_ERROR([Cannot find GNU make $MAKE_REQUIRED_VERSION or newer! Please put it in the path, or add e.g. MAKE=/opt/gmake3.81/make as argument to configure.]) fi diff --git a/make/autoconf/build-performance.m4 b/make/autoconf/build-performance.m4 index 10e86e75199..dfc9e979d2f 100644 --- a/make/autoconf/build-performance.m4 +++ b/make/autoconf/build-performance.m4 @@ -162,12 +162,7 @@ AC_DEFUN([BPERF_SETUP_CCACHE], # Check if ccache is available CCACHE_AVAILABLE=true - OLD_PATH="$PATH" - if test "x$TOOLCHAIN_PATH" != x; then - PATH=$TOOLCHAIN_PATH:$PATH - fi - UTIL_LOOKUP_PROGS(CCACHE, ccache) - PATH="$OLD_PATH" + UTIL_LOOKUP_TOOLCHAIN_PROGS(CCACHE, ccache) AC_MSG_CHECKING([if ccache is available]) if test "x$TOOLCHAIN_TYPE" != "xgcc" && test "x$TOOLCHAIN_TYPE" != "xclang"; then diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 509e0dd825f..a12a6e7f9a6 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -74,7 +74,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # Clang needs the lld linker to work correctly BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL" if test "x$CXX_IS_USER_SUPPLIED" = xfalse && test "x$CC_IS_USER_SUPPLIED" = xfalse; then - UTIL_REQUIRE_PROGS(LLD, lld, $TOOLCHAIN_PATH:$PATH) + UTIL_REQUIRE_TOOLCHAIN_PROGS(LLD, lld) fi fi if test "x$OPENJDK_TARGET_OS" = xaix; then diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index f3ef44d382b..4662c62d901 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -276,9 +276,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], ORG_CFLAGS="$CFLAGS" ORG_CXXFLAGS="$CXXFLAGS" - # autoconf magic only relies on PATH, so update it if tools dir is specified - OLD_PATH="$PATH" - if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then if test "x$XCODEBUILD" != x; then XCODE_VERSION_OUTPUT=`"$XCODEBUILD" -version 2> /dev/null | $HEAD -n 1` @@ -300,9 +297,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], fi AC_SUBST(TOOLCHAIN_VERSION) - # Finally prepend TOOLCHAIN_PATH to the PATH, to allow --with-tools-dir to - # override all other locations. - if test "x$TOOLCHAIN_PATH" != x; then + # For the microsoft toolchain the toolchain path needs to be added to the + # normal path, or the compiler will not work in some situations in later + # configure checks. + if test "x$TOOLCHAIN_TYPE" = "xmicrosoft" && test "x$TOOLCHAIN_PATH" != x; then export PATH=$TOOLCHAIN_PATH:$PATH fi ]) @@ -310,13 +308,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], # Restore path, etc AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], [ - # Restore old path, except for the microsoft toolchain, which requires the - # toolchain path to remain in place. Otherwise the compiler will not work in - # some situations in later configure checks. - if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then - PATH="$OLD_PATH" - fi - # Restore the flags to the user specified values. # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" diff --git a/make/autoconf/util_paths.m4 b/make/autoconf/util_paths.m4 index 40864680aad..abe79c40fb6 100644 --- a/make/autoconf/util_paths.m4 +++ b/make/autoconf/util_paths.m4 @@ -458,17 +458,18 @@ AC_DEFUN([UTIL_LOOKUP_PROGS], ################################################################################ # Call UTIL_SETUP_TOOL with AC_CHECK_TOOLS to locate the tool. This will look -# first for cross-compilation tools. +# first for tools using the cross-compilation prefix, and then for tools without +# this prefix. For each of these name variants, it will look first in the +# toolchain path, and then in the normal path. # $1: variable to set # $2: executable name (or list of names) to look for -# $3: [path] AC_DEFUN([UTIL_LOOKUP_TOOLCHAIN_PROGS], [ if test "x$ac_tool_prefix" = x; then - UTIL_LOOKUP_PROGS($1, $2, $3) + UTIL_LOOKUP_PROGS($1, $2, [$TOOLCHAIN_PATH:$PATH]) else prefixed_names=$(for name in $2; do echo ${ac_tool_prefix}${name} $name; done) - UTIL_LOOKUP_PROGS($1, $prefixed_names, $3) + UTIL_LOOKUP_PROGS($1, $prefixed_names, [$TOOLCHAIN_PATH:$PATH]) fi ]) @@ -497,10 +498,9 @@ AC_DEFUN([UTIL_REQUIRE_PROGS], # Like UTIL_LOOKUP_PROGS but fails if no tool was found. # $1: variable to set # $2: executable name (or list of names) to look for -# $3: [path] AC_DEFUN([UTIL_REQUIRE_TOOLCHAIN_PROGS], [ - UTIL_LOOKUP_TOOLCHAIN_PROGS($1, $2, $3) + UTIL_LOOKUP_TOOLCHAIN_PROGS($1, $2) UTIL_CHECK_NONEMPTY($1) ]) From edae355e95f23294eda092dbedcb7f6cf165b0f8 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 10 Sep 2025 10:27:38 +0000 Subject: [PATCH 216/295] 8246325: Add DRYRUN facility to SetupExecute Reviewed-by: erikj --- make/Bundles.gmk | 4 ++-- make/autoconf/spec.gmk.template | 10 ++++++---- make/common/Execute.gmk | 20 ++++++++++++++++---- test/make/TestExecute.gmk | 24 ++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/make/Bundles.gmk b/make/Bundles.gmk index ba8ec0c864b..cf3b77e4e52 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -301,7 +301,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) $(call LogWarn, Signing $(JDK_BUNDLE_NAME)) $(CODESIGN) -s "$(MACOSX_CODESIGN_IDENTITY)" \ --timestamp --options runtime --deep --force \ - $(JDK_MACOSX_BUNDLE_DIR_SIGNED)/$(JDK_MACOSX_BUNDLE_TOP_DIR) $(LOG_DEBUG) + $(JDK_MACOSX_BUNDLE_DIR_SIGNED)/$(JDK_MACOSX_BUNDLE_TOP_SUBDIR) $(LOG_DEBUG) $(TOUCH) $@ $(eval $(call SetupBundleFile, BUILD_JDK_BUNDLE, \ @@ -330,7 +330,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) $(call LogWarn, Signing $(JRE_BUNDLE_NAME)) $(CODESIGN) -s "$(MACOSX_CODESIGN_IDENTITY)" \ --timestamp --options runtime --deep --force \ - $(JRE_MACOSX_BUNDLE_DIR_SIGNED)/$(JRE_MACOSX_BUNDLE_TOP_DIR) $(LOG_DEBUG) + $(JRE_MACOSX_BUNDLE_DIR_SIGNED)/$(JRE_MACOSX_BUNDLE_TOP_SUBDIR) $(LOG_DEBUG) $(TOUCH) $@ $(eval $(call SetupBundleFile, BUILD_JRE_BUNDLE, \ diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index e3345940101..ab6bb51c27e 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -898,12 +898,14 @@ JDK_MACOSX_BUNDLE_DIR = $(IMAGES_OUTPUTDIR)/$(JDK_MACOSX_BUNDLE_SUBDIR) JRE_MACOSX_BUNDLE_DIR = $(IMAGES_OUTPUTDIR)/$(JRE_MACOSX_BUNDLE_SUBDIR) JDK_MACOSX_BUNDLE_DIR_SIGNED = $(IMAGES_OUTPUTDIR)/$(JDK_MACOSX_BUNDLE_SUBDIR_SIGNED) JRE_MACOSX_BUNDLE_DIR_SIGNED = $(IMAGES_OUTPUTDIR)/$(JRE_MACOSX_BUNDLE_SUBDIR_SIGNED) -JDK_MACOSX_BUNDLE_TOP_DIR = jdk-$(VERSION_NUMBER).jdk -JRE_MACOSX_BUNDLE_TOP_DIR = jre-$(VERSION_NUMBER).jre -JDK_MACOSX_CONTENTS_SUBDIR = $(JDK_MACOSX_BUNDLE_TOP_DIR)/Contents -JRE_MACOSX_CONTENTS_SUBDIR = $(JRE_MACOSX_BUNDLE_TOP_DIR)/Contents +JDK_MACOSX_BUNDLE_TOP_SUBDIR = jdk-$(VERSION_NUMBER).jdk +JRE_MACOSX_BUNDLE_TOP_SUBDIR = jre-$(VERSION_NUMBER).jre +JDK_MACOSX_CONTENTS_SUBDIR = $(JDK_MACOSX_BUNDLE_TOP_SUBDIR)/Contents +JRE_MACOSX_CONTENTS_SUBDIR = $(JRE_MACOSX_BUNDLE_TOP_SUBDIR)/Contents JDK_MACOSX_CONTENTS_DIR = $(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_CONTENTS_SUBDIR) JRE_MACOSX_CONTENTS_DIR = $(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_CONTENTS_SUBDIR) +JDK_MACOSX_BUNDLE_TOP_DIR = $(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_BUNDLE_TOP_SUBDIR) +JRE_MACOSX_BUNDLE_TOP_DIR = $(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_BUNDLE_TOP_SUBDIR) # Bundle names ifneq ($(VERSION_BUILD), ) diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk index 1ee3c28261b..4199e8f13b7 100644 --- a/make/common/Execute.gmk +++ b/make/common/Execute.gmk @@ -82,6 +82,8 @@ ifeq ($(INCLUDE), true) # INFO : Message to display at LOG=info level when running command (optional) # WARN : Message to display at LOG=warn level when running command (optional) # DEPS : Dependencies for the execution to take place +# DRYRUN : Set to true to perform everything but executing the command \ +# (defaults to false, primarily intended for debugging) # # Setup make rules for copying files, with an option to do more complex @@ -161,8 +163,13 @@ define SetupExecuteBody $$(TOUCH) $$@ $$($1_EXEC_RESULT): $$($1_PRE_MARKER) - $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + ifneq ($$($1_DRYRUN), true) + $$(call ExecuteWithLog, $$($1_BASE)_exec, \ + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + else + $$(call LogWarn, DRYRUN enabled for $1, not actually running command) + $$(TOUCH) $$@ + endif ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif @@ -177,8 +184,13 @@ define SetupExecuteBody $$(call LogInfo, $$($1_INFO)) endif $$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) - $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + ifneq ($$($1_DRYRUN), true) + $$(call ExecuteWithLog, $$($1_BASE)_exec, \ + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + else + $$(call LogWarn, DRYRUN enabled for $1, not actually running command) + $$(TOUCH) $$@ + endif ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif diff --git a/test/make/TestExecute.gmk b/test/make/TestExecute.gmk index f71a402502e..5d57d244c39 100644 --- a/test/make/TestExecute.gmk +++ b/test/make/TestExecute.gmk @@ -60,10 +60,30 @@ $(eval $(call SetupExecute, EXEC_2, \ run-test2: $(EXEC_2) test -f $(OUTPUT_DIR)/exec_2/special/specialfile +$(eval $(call SetupExecute, EXEC_3, \ + INFO := Testing that SetupExecute with DRYRUN does nothing, \ + OUTPUT_DIR := $(OUTPUT_DIR)/exec_3, \ + DRYRUN := true, \ + COMMAND := $(ECHO) "This should not happen" > $(OUTPUT_DIR)/exec_3/dryrunfile, \ +)) -TEST_TARGETS += run-test1 run-test2 +run-test3: $(EXEC_3) + test ! -f $(OUTPUT_DIR)/exec_3/dryrunfile -.PHONY: run-test1 run-test2 +$(eval $(call SetupExecute, EXEC_4, \ + INFO := Testing that SetupExecute with DRYRUN does nothing but touches output file, \ + OUTPUT_FILE := $(OUTPUT_DIR)/exec_4/output, \ + DRYRUN := true, \ + COMMAND := $(ECHO) "This should not happen" > $(OUTPUT_DIR)/exec_4/dryrunfile, \ +)) + +run-test4: $(EXEC_4) + test ! -f $(OUTPUT_DIR)/exec_4/dryrunfile + test -f $(OUTPUT_DIR)/exec_4/output + +TEST_TARGETS += run-test1 run-test2 run-test3 run-test4 + +.PHONY: run-test1 run-test2 run-test3 run-test4 ################################################################################ From 4d4e51c41fed79427fb621fd9fcc8e5e23bfb287 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Wed, 10 Sep 2025 11:49:02 +0000 Subject: [PATCH 217/295] 8365483: Test sun/rmi/runtime/Log/6409194/NoConsoleOutput.java sometimes fails Reviewed-by: dfuchs, jpai --- .../java/util/logging/StreamHandler.java | 13 +- .../logging/StreamHandlerRacyCloseTest.java | 137 ++++++++++++++++++ 2 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java diff --git a/src/java.logging/share/classes/java/util/logging/StreamHandler.java b/src/java.logging/share/classes/java/util/logging/StreamHandler.java index ddfea9674dc..3b9af54814d 100644 --- a/src/java.logging/share/classes/java/util/logging/StreamHandler.java +++ b/src/java.logging/share/classes/java/util/logging/StreamHandler.java @@ -214,13 +214,16 @@ public class StreamHandler extends Handler { try { synchronized (this) { + // Re-check writer between isLoggable() and here. Writer writer = this.writer; - if (!doneHeader) { - writer.write(formatter.getHead(this)); - doneHeader = true; + if (writer != null) { + if (!doneHeader) { + writer.write(formatter.getHead(this)); + doneHeader = true; + } + writer.write(msg); + synchronousPostWriteHook(); } - writer.write(msg); - synchronousPostWriteHook(); } } catch (Exception ex) { // We don't want to throw an exception here, but we diff --git a/test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java b/test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java new file mode 100644 index 00000000000..5bb465088e5 --- /dev/null +++ b/test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; +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.concurrent.atomic.AtomicReference; +import java.util.logging.ErrorManager; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; +import java.util.logging.StreamHandler; + +import org.junit.jupiter.api.Test; + +/* + * @test + * @bug 8365483 + * @summary verify that concurrent calls to publish() and close() on a + * StreamHandler do not cause unexpected exceptions + * @run junit StreamHandlerRacyCloseTest + */ +public class StreamHandlerRacyCloseTest { + + private static final class ExceptionTrackingErrorManager extends ErrorManager { + private final AtomicReference firstError = new AtomicReference<>(); + + @Override + public void error(String msg, Exception ex, int code) { + // just track one/first exception, that's good enough for this test + this.firstError.compareAndSet(null, new RuntimeException(msg, ex)); + } + } + + @Test + void testRacyClose() throws Exception { + final int numTimes = 100; + try (ExecutorService executor = Executors.newFixedThreadPool(numTimes)) { + final List> tasks = new ArrayList<>(); + for (int i = 1; i <= numTimes; i++) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // construct a StreamHandler with an ErrorManager which propagates + // any errors that happen during publish() + final StreamHandler handler = new StreamHandler(baos, new SimpleFormatter()); + handler.setErrorManager(new ExceptionTrackingErrorManager()); + + final CountDownLatch latch = new CountDownLatch(2); + // create a publisher and closer task which will run concurrently + tasks.add(new Publisher(handler, latch)); + tasks.add(new Closer(handler, latch)); + } + // submit the tasks and expect successful completion of each + final List> completed = executor.invokeAll(tasks); + for (var f : completed) { + f.get(); + } + } + } + + private static final class Closer implements Callable { + private final StreamHandler handler; + private final CountDownLatch startLatch; + + private Closer(final StreamHandler handler, final CountDownLatch startLatch) { + this.handler = handler; + this.startLatch = startLatch; + } + + @Override + public Void call() throws Exception { + // notify the other task of our readiness + this.startLatch.countDown(); + // wait for the other task to arrive + this.startLatch.await(); + // close the handler + this.handler.close(); + // propagate any exception that may have been caught by the error manager + final var errMgr = (ExceptionTrackingErrorManager) this.handler.getErrorManager(); + if (errMgr.firstError.get() != null) { + throw errMgr.firstError.get(); + } + return null; + } + } + + private static final class Publisher implements Callable { + private final StreamHandler handler; + private final CountDownLatch startLatch; + + private Publisher(final StreamHandler handler, final CountDownLatch startLatch) { + this.handler = handler; + this.startLatch = startLatch; + } + + @Override + public Void call() throws Exception { + final LogRecord record = new LogRecord(Level.WARNING, "hello world"); + // notify the other task of our readiness + this.startLatch.countDown(); + // wait for the other task to arrive + this.startLatch.await(); + // publish the record + this.handler.publish(record); + // propagate any exception that may have been caught by the error manager + final var errMgr = (ExceptionTrackingErrorManager) this.handler.getErrorManager(); + if (errMgr.firstError.get() != null) { + throw errMgr.firstError.get(); + } + return null; + } + } +} From 703d930e4d52a6f9741cf9affee8caade550e67b Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 10 Sep 2025 11:55:31 +0000 Subject: [PATCH 218/295] 8366980: TestTransparentHugePagesHeap.java fails when run with -UseCompressedOops Reviewed-by: aboldtch, tschatzl --- .../gc/TestTransparentHugePagesHeap.java | 81 +++++++++++++------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java index 25044d2c3e4..2c2e19b87c4 100644 --- a/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java +++ b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java @@ -49,6 +49,7 @@ * @run driver TestTransparentHugePagesHeap Serial */ +import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -98,47 +99,76 @@ public class TestTransparentHugePagesHeap { class VerifyTHPEnabledForHeap { public static void main(String args[]) throws Exception { - String heapAddress = readHeapAddressInLog(); + // Extract the heap start from pagesize logging + BigInteger heapStart = extractHeapStartFromLog(); + Path smaps = makeSmapsCopy(); - final Pattern heapSection = Pattern.compile("^" + heapAddress + ".*"); - final Pattern thpEligible = Pattern.compile("THPeligible:\\s+(\\d)\\s*"); + final Pattern addressRangePattern = Pattern.compile("([0-9a-f]*?)-([0-9a-f]*?) .*"); + final Pattern thpEligiblePattern = Pattern.compile("THPeligible:\\s+(\\d)\\s*"); Scanner smapsFile = new Scanner(smaps); while (smapsFile.hasNextLine()) { - Matcher heapMatcher = heapSection.matcher(smapsFile.nextLine()); - - if (heapMatcher.matches()) { - // Found the first heap section, verify that it is THP eligible - while (smapsFile.hasNextLine()) { - Matcher m = thpEligible.matcher(smapsFile.nextLine()); - if (m.matches()) { - if (Integer.parseInt(m.group(1)) == 1) { - // THPeligible is 1, heap can be backed by huge pages - return; - } - - throw new RuntimeException("First heap section at 0x" + heapAddress + " is not THPeligible"); - } - } + Matcher addressRangeMatcher = addressRangePattern.matcher(smapsFile.nextLine()); + if (!addressRangeMatcher.matches()) { + continue; } + + // Found an address range line in the smaps file + + BigInteger addressStart = new BigInteger(addressRangeMatcher.group(1), 16); + BigInteger addressEnd = new BigInteger(addressRangeMatcher.group(2), 16); + + // Linux sometimes merges adjacent VMAs so we can't search for a range that + // exactly matches the heap range. Instead we look for the first range that + // contains the start of the heap and verify that that range is THP eligible. + + if (addressStart.compareTo(heapStart) > 0 || heapStart.compareTo(addressEnd) >= 0) { + continue; + } + + // Found a range that contains the start of the heap, verify that it is THP eligible. + + while (smapsFile.hasNextLine()) { + Matcher m = thpEligiblePattern.matcher(smapsFile.nextLine()); + if (!m.matches()) { + continue; + } + + // Found the THPeligible line + + if (m.group(1).equals("1")) { + // Success - THPeligible is 1, heap can be backed by huge pages + return; + } + + throw new RuntimeException("The address range 0x" + addressStart.toString(16) + + "-0x" + addressEnd.toString(16) + + " that contains the heap start" + heapStart + + " is not THPeligible"); + } + + throw new RuntimeException("Couldn't find THPeligible in the smaps file"); } - // Failed to verify THP for heap - throw new RuntimeException("Could not find heap section in smaps file"); + throw new RuntimeException("Could not find an address range containing the heap start " + heapStart + " in the smaps file"); } - private static String readHeapAddressInLog() throws Exception { - final Pattern heapAddress = Pattern.compile(".* Heap: .*base=(0x[0-9A-Fa-f]*).*"); + private static BigInteger extractHeapStartFromLog() throws Exception { + // [0.041s][info][pagesize] Heap: min=128M max=128M base=0x0000ffff5c600000 size=128M page_size=2M + final Pattern heapAddress = Pattern.compile(".* Heap: .*base=0x([0-9A-Fa-f]*).*"); Scanner logFile = new Scanner(Paths.get("thp-" + ProcessHandle.current().pid() + ".log")); while (logFile.hasNextLine()) { - Matcher m = heapAddress.matcher(logFile.nextLine()); + String line = logFile.nextLine(); + + Matcher m = heapAddress.matcher(line); if (m.matches()) { - return Long.toHexString(Long.decode(m.group(1))); + return new BigInteger(m.group(1), 16); } } - throw new RuntimeException("Failed to parse heap address, failing test"); + + throw new RuntimeException("Failed to find heap start"); } private static Path makeSmapsCopy() throws Exception { @@ -149,4 +179,3 @@ public class TestTransparentHugePagesHeap { } } } - From 46ae1ee87152742082e6047d0556944d7ae4567d Mon Sep 17 00:00:00 2001 From: Evgeny Astigeevich Date: Wed, 10 Sep 2025 12:33:06 +0000 Subject: [PATCH 219/295] 8277444: Data race between JvmtiClassFileReconstituter::copy_bytecodes and class linking Reviewed-by: dholmes, amenkov, coleenp --- .../prims/jvmtiClassFileReconstituter.cpp | 5 + src/hotspot/share/prims/jvmtiEnv.cpp | 22 ++- .../instrument/RetransformBigClassTest.java | 161 ++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/lang/instrument/RetransformBigClassTest.java diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 831f407e7ec..a441d405f8d 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -996,6 +996,11 @@ void JvmtiClassFileReconstituter::write_u8(u8 x) { void JvmtiClassFileReconstituter::copy_bytecodes(const methodHandle& mh, unsigned char* bytecodes) { + // We must copy bytecodes only from linked classes. + // Being linked guarantees we are not getting bytecodes at + // the same time the linking process is rewriting them. + guarantee(mh->method_holder()->is_linked(), "Bytecodes must be copied from a linked class"); + // use a BytecodeStream to iterate over the bytecodes. JVM/fast bytecodes // and the breakpoint bytecode are converted to their original bytecodes. diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 30dd1f77d23..3eb507ba5e3 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -450,6 +450,18 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) { InstanceKlass* ik = InstanceKlass::cast(klass); if (ik->get_cached_class_file_bytes() == nullptr) { + // Link the class to avoid races with the rewriter. This will call the verifier also + // on the class. Linking is also done in VM_RedefineClasses below, but we need + // to keep that for other VM_RedefineClasses callers. + JavaThread* THREAD = current_thread; + ik->link_class(THREAD); + if (HAS_PENDING_EXCEPTION) { + // Retransform/JVMTI swallows error messages. Using this class will rerun the verifier in a context + // that propagates the VerifyError, if thrown. + CLEAR_PENDING_EXCEPTION; + return JVMTI_ERROR_INVALID_CLASS; + } + // Not cached, we need to reconstitute the class file from the // VM representation. We don't attach the reconstituted class // bytes to the InstanceKlass here because they have not been @@ -3407,7 +3419,8 @@ jvmtiError JvmtiEnv::GetBytecodes(Method* method, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) { NULL_CHECK(method, JVMTI_ERROR_INVALID_METHODID); - methodHandle mh(Thread::current(), method); + JavaThread* current_thread = JavaThread::current(); + methodHandle mh(current_thread, method); jint size = (jint)mh->code_size(); jvmtiError err = allocate(size, bytecodes_ptr); if (err != JVMTI_ERROR_NONE) { @@ -3416,6 +3429,13 @@ JvmtiEnv::GetBytecodes(Method* method, jint* bytecode_count_ptr, unsigned char** (*bytecode_count_ptr) = size; // get byte codes + // Make sure the class is verified and rewritten first. + JavaThread* THREAD = current_thread; + mh->method_holder()->link_class(THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + return JVMTI_ERROR_INVALID_CLASS; + } JvmtiClassFileReconstituter::copy_bytecodes(mh, *bytecodes_ptr); return JVMTI_ERROR_NONE; diff --git a/test/jdk/java/lang/instrument/RetransformBigClassTest.java b/test/jdk/java/lang/instrument/RetransformBigClassTest.java new file mode 100644 index 00000000000..c4788217be1 --- /dev/null +++ b/test/jdk/java/lang/instrument/RetransformBigClassTest.java @@ -0,0 +1,161 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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 8277444 + * + * @library /test/lib + * @compile SimpleIdentityTransformer.java + * @run shell MakeJAR.sh retransformAgent + * @run main/othervm -javaagent:retransformAgent.jar RetransformBigClassTest + */ + +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +/* + * JvmtiClassFileReconstituter::copy_bytecodes restores bytecodes rewritten + * by the linking process. It is used by RetransformClasses. + * JDK-8277444 is a data race between copy_bytecodes and the linking process. + * This test puts the linking process in one thread and the retransforming process + * in another thread. The test uses Class.forName("BigClass", false, classLoader) + * which does not link the class. When the class is used, the linking process starts. + * In another thread retransforming of the class is happening. + * We generate a class with big methods. A number of methods and their size are + * chosen to make the linking and retransforming processes run concurrently. + * We delay the retransforming process to follow the linking process. + * If there is no synchronization between the processes, a data race will happen. + */ +public class RetransformBigClassTest extends AInstrumentationTestCase { + + private static final Object LOCK = new Object(); + private static final int COUNTER_INC_COUNT = 2000; // A number of 'c+=1;' statements in methods of a class. + private static final int MIN_LINK_TIME_MS = 60; // Large enough so the linking and retransforming processes run in parallel. + private static final int RETRANSFORM_CLASSES_DELAY_MS = 37; // We manage to create a data race when a delay is in the range 0.52x - 0.62x of MIN_LINK_TIME_MS. + + private static Class bigClass; + private static byte[] bigClassBytecode; + + private Thread retransformThread; + + RetransformBigClassTest() { + super("RetransformBigClassTest"); + } + + public static void main(String[] args) throws Throwable { + new RetransformBigClassTest().runTest(); + } + + protected final void doRunTest() throws Throwable { + ClassLoader classLoader = new ClassLoader() { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals("BigClass")) { + return defineClass(name, bigClassBytecode, 0, bigClassBytecode.length); + } + + return super.findClass(name); + } + }; + synchronized (LOCK) { + bigClass = Class.forName("BigClass", false, classLoader); + LOCK.notify(); + } + // Make a use of the BigClass + assertTrue(bigClass.getConstructor().newInstance().hashCode() != 0); + retransformThread.join(); + } + + private byte[] createClassBytecode(String className, int methodCount) throws Exception { + String methodBody = ""; + for (int j = 0; j < COUNTER_INC_COUNT; j++) { + methodBody += "c+=1;"; + } + + String classSrc = "public class " + className + " { int c;"; + + for (int i = 0; i < methodCount; i++) { + classSrc += "\npublic void m" + i + "(){"; + classSrc += methodBody; + classSrc += "\n}"; + } + classSrc += "\n}"; + + return InMemoryJavaCompiler.compile(className, classSrc); + } + + // We need a number of methods such that the linking time is greater than + // or equal to MIN_LINK_TIME_MS. + // We create a class having 5 methods and trigger the linking process. + // We measure the time taken and use it to calculate the needed number. + private int findMethodCount() throws Exception { + int methodCount = 5; + final String className = "BigClass" + methodCount; + final byte[] bytecode = createClassBytecode(className, methodCount); + ClassLoader classLoader = new ClassLoader() { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(className)) { + return defineClass(name, bytecode, 0, bytecode.length); + } + + return super.findClass(name); + } + }; + var bigClass = Class.forName(className, false, classLoader); + long startTime = System.nanoTime(); + assertTrue(bigClass.getConstructor().newInstance().hashCode() != 0); + double linkTimeMs = (System.nanoTime() - startTime) / 1000000.0; + System.out.println("Link time for a class with " + methodCount + " methods each having " + COUNTER_INC_COUNT + " counter increments: " + Math.round(linkTimeMs)); + if (linkTimeMs < MIN_LINK_TIME_MS) { + methodCount = (int)Math.round((MIN_LINK_TIME_MS * methodCount) / linkTimeMs); + } + System.out.println("The number of methods to exceed " + MIN_LINK_TIME_MS + " ms linking time: " + methodCount); + return methodCount; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + bigClassBytecode = createClassBytecode("BigClass", findMethodCount()); + fInst.addTransformer(new SimpleIdentityTransformer()); + retransformThread = new Thread(() -> { + try { + synchronized (LOCK) { + while (bigClass == null) { + System.out.println("[retransformThread]: Waiting for bigClass"); + LOCK.wait(); + } + } + Thread.sleep(RETRANSFORM_CLASSES_DELAY_MS); + fInst.retransformClasses(bigClass); + } catch (Exception e) { + e.printStackTrace(); + } + }); + retransformThread.start(); + Thread.sleep(100); + } +} From 385c13298932f1de16e6161652be35d966d822ec Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Sep 2025 12:49:38 +0000 Subject: [PATCH 220/295] 8367240: Parallel: Refactor PSScavengeCLDClosure Reviewed-by: stefank --- .../share/gc/parallel/psClosure.inline.hpp | 57 ++++++++----------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psClosure.inline.hpp b/src/hotspot/share/gc/parallel/psClosure.inline.hpp index 5cc059a09f5..914a16e77a6 100644 --- a/src/hotspot/share/gc/parallel/psClosure.inline.hpp +++ b/src/hotspot/share/gc/parallel/psClosure.inline.hpp @@ -78,16 +78,17 @@ typedef PSRootsClosure PSScavengeRootsClosure; typedef PSRootsClosure PSPromoteRootsClosure; // Scavenges a single oop in a ClassLoaderData. -class PSScavengeFromCLDClosure: public OopClosure { -private: +class PSScavengeCLDOopClosure : public OopClosure { PSPromotionManager* _pm; - // Used to redirty a scanned cld if it has oops - // pointing to the young generation after being scanned. - ClassLoaderData* _scanned_cld; + public: - PSScavengeFromCLDClosure(PSPromotionManager* pm) : _pm(pm), _scanned_cld(nullptr) { } + // Records whether this CLD contains oops pointing into young-gen after scavenging. + bool _has_oops_into_young_gen; + + PSScavengeCLDOopClosure(PSPromotionManager* pm) : _pm(pm), _has_oops_into_young_gen(false) {} + void do_oop(narrowOop* p) { ShouldNotReachHere(); } - void do_oop(oop* p) { + void do_oop(oop* p) { ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); assert(!psh->is_in_reserved(p), "GC barrier needed"); if (PSScavenge::should_scavenge(p)) { @@ -97,43 +98,33 @@ public: oop new_obj = _pm->copy_to_survivor_space(o); RawAccess::oop_store(p, new_obj); - if (PSScavenge::is_obj_in_young(new_obj)) { - do_cld_barrier(); + if (PSScavenge::is_obj_in_young(new_obj) && !_has_oops_into_young_gen) { + _has_oops_into_young_gen = true; } } } - - void set_scanned_cld(ClassLoaderData* cld) { - assert(_scanned_cld == nullptr || cld == nullptr, "Should always only handling one cld at a time"); - _scanned_cld = cld; - } - -private: - void do_cld_barrier() { - assert(_scanned_cld != nullptr, "Should not be called without having a scanned cld"); - _scanned_cld->record_modified_oops(); - } }; // Scavenges the oop in a ClassLoaderData. class PSScavengeCLDClosure: public CLDClosure { -private: - PSScavengeFromCLDClosure _oop_closure; + PSPromotionManager* _pm; + public: - PSScavengeCLDClosure(PSPromotionManager* pm) : _oop_closure(pm) { } + PSScavengeCLDClosure(PSPromotionManager* pm) : _pm(pm) { } + void do_cld(ClassLoaderData* cld) { - // If the cld has not been dirtied we know that there's - // no references into the young gen and we can skip it. + // If the cld has not been dirtied we know that there are + // no references into the young gen, so we can skip it. + if (!cld->has_modified_oops()) { + return; + } - if (cld->has_modified_oops()) { - // Setup the promotion manager to redirty this cld - // if references are left in the young gen. - _oop_closure.set_scanned_cld(cld); + PSScavengeCLDOopClosure oop_closure{_pm}; + // Clean the cld since we're going to scavenge all the metadata. + cld->oops_do(&oop_closure, ClassLoaderData::_claim_none, /*clear_modified_oops*/true); - // Clean the cld since we're going to scavenge all the metadata. - cld->oops_do(&_oop_closure, ClassLoaderData::_claim_none, /*clear_modified_oops*/true); - - _oop_closure.set_scanned_cld(nullptr); + if (oop_closure._has_oops_into_young_gen) { + cld->record_modified_oops(); } } }; From c968a672c034fe533ea5f4ac5efe37ffb76c93e2 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 10 Sep 2025 13:45:06 +0000 Subject: [PATCH 221/295] 8362282: runtime/logging/StressAsyncUL.java failed with exitValue = 134 Reviewed-by: jsjolen, dholmes --- src/hotspot/share/logging/logAsyncWriter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/logging/logAsyncWriter.cpp b/src/hotspot/share/logging/logAsyncWriter.cpp index cfb6a991c4c..d184827f582 100644 --- a/src/hotspot/share/logging/logAsyncWriter.cpp +++ b/src/hotspot/share/logging/logAsyncWriter.cpp @@ -318,13 +318,13 @@ void AsyncLogWriter::initialize() { AsyncLogWriter* self = new AsyncLogWriter(); if (self->_initialized) { - Atomic::release_store_fence(&AsyncLogWriter::_instance, self); - // All readers of _instance after the fence see non-null. // We use LogOutputList's RCU counters to ensure all synchronous logsites have completed. - // After that, we start AsyncLog Thread and it exclusively takes over all logging I/O. + // After that, we publish the initalized _instance to readers. + // Then we start the AsyncLog Thread and it exclusively takes over all logging I/O. for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { ts->wait_until_no_readers(); } + Atomic::release_store_fence(&AsyncLogWriter::_instance, self); os::start_thread(self); log_debug(logging, thread)("Async logging thread started."); } else { From 5cd7721ad448cc4bdac37b0456252335f6b9d9f5 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 10 Sep 2025 14:36:11 +0000 Subject: [PATCH 222/295] 8366154: Validate thread type requirements in debug commands Reviewed-by: dholmes, simonis, kevinw --- src/hotspot/share/utilities/debug.cpp | 87 ++++++++++++++++++++------- 1 file changed, 64 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 2865dbc5991..bd82336020a 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -63,6 +63,7 @@ #include "utilities/unsigned5.hpp" #include "utilities/vmError.hpp" +#include #include #include @@ -296,20 +297,40 @@ void report_java_out_of_memory(const char* message) { class Command : public StackObj { private: - ResourceMark _rm; - DebuggingContext _debugging; - public: static int level; - Command(const char* str) { - if (level++ > 0) return; - tty->cr(); - tty->print_cr("\"Executing %s\"", str); + DebuggingContext _debugging; + bool _has_rm; + // Union members of class type are implicitly allocated but not constructed automatically. + // We therefore have to explicitly construct _rm with a placement new call (see 'onThread()') and + // clean it up afterwards with an explicit destructor call (see '~Command()'). + union { ResourceMark _rm; }; + public: + Command(const char* str) : _has_rm(false) { + if (level++ == 0) { + tty->cr(); + tty->print_cr("\"Executing %s\"", str); + } + tty->flush(); } - ~Command() { + if (_has_rm) _rm.~ResourceMark(); tty->flush(); level--; } + + bool onThread() { + Thread* thread = Thread::current_or_null(); + if (thread == nullptr) { + tty->print_cr("Failed: Current thread is not attached"); + return false; + } + + if (!_has_rm) { + ::new (&_rm) ResourceMark(); + _has_rm = true; + } + return true; + } }; int Command::level = 0; @@ -370,6 +391,7 @@ extern "C" DEBUGEXPORT void printnm(intptr_t p) { extern "C" DEBUGEXPORT void universe() { Command c("universe"); + if (!c.onThread()) return; Universe::print_on(tty); } @@ -379,6 +401,7 @@ extern "C" DEBUGEXPORT void verify() { // note: this may not be safe if we're not at a safepoint; for debugging, // this manipulates the safepoint settings to avoid assertion failures Command c("universe verify"); + if (!c.onThread()) return; bool safe = SafepointSynchronize::is_at_safepoint(); if (!safe) { tty->print_cr("warning: not at safepoint -- verify may fail"); @@ -393,6 +416,7 @@ extern "C" DEBUGEXPORT void verify() { extern "C" DEBUGEXPORT void pp(void* p) { Command c("pp"); + if (!c.onThread()) return; FlagSetting fl(DisplayVMOutput, true); if (p == nullptr) { tty->print_cr("null"); @@ -416,14 +440,15 @@ extern "C" DEBUGEXPORT void pp(void* p) { } -extern "C" DEBUGEXPORT void findpc(intptr_t x); - extern "C" DEBUGEXPORT void ps() { // print stack - if (Thread::current_or_null() == nullptr) return; - Command c("ps"); - // Prints the stack of the current Java thread + Command c("ps"); + if (!c.onThread()) return; JavaThread* p = JavaThread::active(); + if (p == nullptr) { + tty->print_cr("Failed: JavaThread::active is null"); + return; + } tty->print(" for thread: "); p->print(); tty->cr(); @@ -450,7 +475,12 @@ extern "C" DEBUGEXPORT void ps() { // print stack extern "C" DEBUGEXPORT void pfl() { // print frame layout Command c("pfl"); + if (!c.onThread()) return; JavaThread* p = JavaThread::active(); + if (p == nullptr) { + tty->print_cr("Failed: JavaThread::active is null"); + return; + } tty->print(" for thread: "); p->print(); tty->cr(); @@ -460,34 +490,39 @@ extern "C" DEBUGEXPORT void pfl() { } extern "C" DEBUGEXPORT void psf() { // print stack frames - { - Command c("psf"); - JavaThread* p = JavaThread::active(); - tty->print(" for thread: "); - p->print(); - tty->cr(); - if (p->has_last_Java_frame()) { - p->trace_frames(); - } + Command c("psf"); + if (!c.onThread()) return; + JavaThread* p = JavaThread::active(); + if (p == nullptr) { + tty->print_cr("Failed: JavaThread::active is null"); + return; + } + tty->print(" for thread: "); + p->print(); + tty->cr(); + if (p->has_last_Java_frame()) { + p->trace_frames(); } } extern "C" DEBUGEXPORT void threads() { Command c("threads"); + if (!c.onThread()) return; Threads::print(false, true); } extern "C" DEBUGEXPORT void psd() { Command c("psd"); + if (!c.onThread()) return; SystemDictionary::print(); } extern "C" DEBUGEXPORT void pss() { // print all stacks - if (Thread::current_or_null() == nullptr) return; Command c("pss"); + if (!c.onThread()) return; Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true)); } @@ -534,12 +569,14 @@ extern "C" DEBUGEXPORT nmethod* findnm(intptr_t addr) { extern "C" DEBUGEXPORT void find(intptr_t x) { Command c("find"); + if (!c.onThread()) return; os::print_location(tty, x, false); } extern "C" DEBUGEXPORT void findpc(intptr_t x) { Command c("findpc"); + if (!c.onThread()) return; os::print_location(tty, x, true); } @@ -551,6 +588,7 @@ extern "C" DEBUGEXPORT void findpc(intptr_t x) { // call findmethod("*ang/Object*", "wait:(*J*)V", 0x1) -> list all "wait" methods in j.l.Object that have a long parameter extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) { Command c("findclass"); + if (!c.onThread()) return; ClassPrinter::print_flags_help(tty); ClassPrinter::print_classes(class_name_pattern, flags, tty); } @@ -558,6 +596,7 @@ extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) extern "C" DEBUGEXPORT void findmethod(const char* class_name_pattern, const char* method_pattern, int flags) { Command c("findmethod"); + if (!c.onThread()) return; ClassPrinter::print_flags_help(tty); ClassPrinter::print_methods(class_name_pattern, method_pattern, flags, tty); } @@ -644,6 +683,7 @@ void help() { #ifndef PRODUCT extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack Command c("pns"); + if (!c.onThread()) return; static char buf[O_BUFLEN]; // Call generic frame constructor (certain arguments may be ignored) frame fr(sp, fp, pc); @@ -662,6 +702,7 @@ extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native // extern "C" DEBUGEXPORT void pns2() { // print native stack Command c("pns2"); + if (!c.onThread()) return; static char buf[O_BUFLEN]; address lastpc = nullptr; NativeStackPrinter nsp(Thread::current_or_null()); From 34c3ac0316dbd29ae670db51bd9230a1e77382d9 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 10 Sep 2025 16:00:28 +0000 Subject: [PATCH 223/295] 8162380: [TEST_BUG] MouseEvent/.../AltGraphModifierTest.java has only "Fail" button Reviewed-by: azvegint, aivanov --- test/jdk/ProblemList.txt | 1 - .../AltGraphModifierTest.java | 256 +++--------------- 2 files changed, 44 insertions(+), 213 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 475704f7e95..70e912d7e93 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -794,7 +794,6 @@ java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java 7131438,802 java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java 7187741 linux-all,macosx-all java/awt/xembed/server/TestXEmbedServerJava.java 8001150,8004031 generic-all 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/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all diff --git a/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java b/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java index 47d808f336d..c8730b28964 100644 --- a/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java +++ b/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,51 +22,57 @@ */ /* - @test - @bug 8041928 8158616 - @requires (os.family != "mac") - @summary Confirm that the Alt-Gr Modifier bit is set correctly. - @run main/manual AltGraphModifierTest + * @test + * @bug 8041928 8158616 + * @requires (os.family != "mac") + * @summary Confirm that the Alt-Gr Modifier bit is set correctly. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AltGraphModifierTest */ -import java.awt.Button; -import java.awt.Dialog; import java.awt.Frame; -import java.awt.Panel; -import java.awt.TextArea; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class AltGraphModifierTest { - private static void init() throws Exception { - String[] instructions - = { - "This test is for verifying Alt-Gr modifier of an event.", - "Linux :-", - "1. Please check if Alt-Gr key is present on keyboard.", - "2. If present, press the Alt-Gr key and perform", - " mouse click on the TestWindow.", - "3. Navigate to System Settings-> Keyboard-> Shortcuts->", - " Typing.", - "4. Select an option for the Alternative Characters Key", - " For example. Right Alt", - "5. Close the settings and navigate to test", - "6. Press Right Alt Key & perform mouse click on the", - " TestWindow", - "7. Test will exit by itself with appropriate result.", - " ", - }; - Sysout.createDialog(); - Sysout.printInstructions(instructions); + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is for verifying Alt-Gr modifier of an event. + Please check if Alt-Gr key is present on keyboard. + If not present, press Pass. + On Windows: + Press Alt-Gr or Right Alt key and simultaneously + perform mouse click on the "TestWindow". + On Linux: + Navigate to + System Settings-> Keyboard-> Special Character Entry + Select "Right Alt" option for the "Alternate Characters Key" + Close the settings and navigate to test + Press Right Alt Key & simultaneously + perform mouse click on the "TestWindow". + + If the system does not have such setting, press Pass. + After the test, change the Setting of "Alternate Characters Key" + back to "Layout default". + + If "Alt-Gr Modifier bit is set" message is displayed in logArea, + press Pass else press Fail. + """; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(AltGraphModifierTest::initTestWindow) + .logArea() + .build() + .awaitAndCheck(); } - static Frame mainFrame; - public static void initTestWindow() { - mainFrame = new Frame(); + public static Frame initTestWindow() { + Frame mainFrame = new Frame(); mainFrame.setTitle("TestWindow"); mainFrame.setBounds(700, 10, 300, 300); mainFrame.addMouseListener(new MouseAdapter() { @@ -74,186 +80,12 @@ public class AltGraphModifierTest { public void mousePressed(MouseEvent e) { int ex = e.getModifiersEx(); if ((ex & InputEvent.ALT_GRAPH_DOWN_MASK) == 0) { - AltGraphModifierTest.fail("Alt-Gr Modifier bit is not set."); + PassFailJFrame.log("Alt-Gr Modifier bit is not set."); } else { - AltGraphModifierTest.pass(); + PassFailJFrame.log("Alt-Gr Modifier bit is set"); } } }); - mainFrame.setVisible(true); - } - - public static void dispose() { - Sysout.dispose(); - mainFrame.dispose(); - } - - /** - * *************************************************** - * Standard Test Machinery Section DO NOT modify anything in this section -- - * it's a standard chunk of code which has all of the synchronisation - * necessary for the test harness. By keeping it the same in all tests, it - * is easier to read and understand someone else's test, as well as insuring - * that all tests behave correctly with the test harness. There is a section - * following this for test-defined classes - * **************************************************** - */ - private static boolean theTestPassed = false; - private static boolean testGeneratedInterrupt = false; - private static String failureMessage = ""; - private static Thread mainThread = null; - final private static int sleepTime = 300000; - - public static void main(String args[]) throws Exception { - mainThread = Thread.currentThread(); - try { - init(); - initTestWindow(); - } catch (Exception e) { - e.printStackTrace(); - } - try { - mainThread.sleep(sleepTime); - } catch (InterruptedException e) { - dispose(); - if (testGeneratedInterrupt && !theTestPassed) { - throw new Exception(failureMessage); - } - } - if (!testGeneratedInterrupt) { - dispose(); - throw new RuntimeException("Timed out after " + sleepTime / 1000 - + " seconds"); - } - } - - public static synchronized void pass() { - theTestPassed = true; - testGeneratedInterrupt = true; - mainThread.interrupt(); - } - - public static synchronized void fail(String whyFailed) { - theTestPassed = false; - testGeneratedInterrupt = true; - failureMessage = whyFailed; - mainThread.interrupt(); - } -} - -// *********** End Standard Test Machinery Section ********** -/** - * ************************************************** - * Standard Test Machinery DO NOT modify anything below -- it's a standard chunk - * of code whose purpose is to make user interaction uniform, and thereby make - * it simpler to read and understand someone else's test. - * ************************************************** - */ -/** - * This is part of the standard test machinery. It creates a dialog (with the - * instructions), and is the interface for sending text messages to the user. To - * print the instructions, send an array of strings to Sysout.createDialog - * WithInstructions method. Put one line of instructions per array entry. To - * display a message for the tester to see, simply call Sysout.println with the - * string to be displayed. This mimics System.out.println but works within the - * test harness as well as standalone. - */ -class Sysout { - private static TestDialog dialog; - private static Frame frame; - - public static void createDialog() { - frame = new Frame(); - dialog = new TestDialog(frame, "Instructions"); - String[] defInstr = {"Instructions will appear here. ", ""}; - dialog.printInstructions(defInstr); - dialog.show(); - println("Any messages for the tester will display here."); - } - - public static void printInstructions(String[] instructions) { - dialog.printInstructions(instructions); - } - - public static void println(String messageIn) { - dialog.displayMessage(messageIn); - } - - public static void dispose() { - dialog.dispose(); - frame.dispose(); - } -} - -/** - * This is part of the standard test machinery. It provides a place for the test - * instructions to be displayed, and a place for interactive messages to the - * user to be displayed. To have the test instructions displayed, see Sysout. To - * have a message to the user be displayed, see Sysout. Do not call anything in - * this dialog directly. - */ -class TestDialog extends Dialog implements ActionListener { - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - Panel buttonP; - Button failB; - - // DO NOT call this directly, go through Sysout - public TestDialog(Frame frame, String name) { - super(frame, name); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); - add("North", instructionsText); - - messageText = new TextArea("", 5, maxStringLength, scrollBoth); - add("Center", messageText); - - buttonP = new Panel(); - failB = new Button("Fail"); - failB.setActionCommand("fail"); - failB.addActionListener(this); - buttonP.add("Center", failB); - - add("South", buttonP); - pack(); - setVisible(true); - } - - // DO NOT call this directly, go through Sysout - public void printInstructions(String[] instructions) { - instructionsText.setText(""); - String printStr, remainingStr; - for (int i = 0; i < instructions.length; i++) { - remainingStr = instructions[i]; - while (remainingStr.length() > 0) { - if (remainingStr.length() >= maxStringLength) { - int posOfSpace = remainingStr. - lastIndexOf(' ', maxStringLength - 1); - - if (posOfSpace <= 0) { - posOfSpace = maxStringLength - 1; - } - - printStr = remainingStr.substring(0, posOfSpace + 1); - remainingStr = remainingStr.substring(posOfSpace + 1); - } - else { - printStr = remainingStr; - remainingStr = ""; - } - instructionsText.append(printStr + "\n"); - } - } - } - - public void displayMessage(String messageIn) { - messageText.append(messageIn + "\n"); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand() == "fail") { - AltGraphModifierTest.fail("User Clicked Fail"); - } + return mainFrame; } } From af18ff8d7c8fdd6437304839caa2e49eb34b6caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 10 Sep 2025 16:43:40 +0000 Subject: [PATCH 224/295] 8367007: javadoc generation of JavaFX docs fails after fix for JDK-8350920 Reviewed-by: liach, nbenalla --- .../formats/html/AbstractMemberWriter.java | 2 +- .../doclets/formats/html/ClassWriter.java | 2 +- .../doclets/toolkit/PropertyUtils.java | 96 ++++++++++--------- .../javadoc/doclet/testJavaFX/TestJavaFX.java | 36 ++++++- .../jdk/javadoc/doclet/testJavaFX/pkg1/B.java | 27 ++++++ 5 files changed, 115 insertions(+), 48 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index e2e286d5856..fabca0a894d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -319,7 +319,7 @@ public abstract class AbstractMemberWriter { inheritedHeader.add(links); if (utils.isIncluded(inheritedClass)) { - var pHelper = writer.getPropertyHelper(); + var pHelper = configuration.propertyUtils.getPropertyHelper(inheritedClass); Table table = createInheritedSummaryTable(inheritedClass); for (Element member : inheritedMembers) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index d301dd6e283..f5a5a48222c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -96,7 +96,7 @@ public class ClassWriter extends SubWriterHolderWriter { this.typeElement = typeElement; this.classTree = classTree; - pHelper = new PropertyUtils.PropertyHelper(configuration, typeElement); + pHelper = configuration.propertyUtils.getPropertyHelper(typeElement); switch (typeElement.getKind()) { case ENUM -> setEnumDocumentation(typeElement); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java index 823f172b360..8913be5b301 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,8 @@ import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind. */ public class PropertyUtils { + final BaseConfiguration configuration; + final TypeMirror jbObservableType; final Pattern fxMethodPatterns; @@ -62,7 +64,10 @@ public class PropertyUtils { final Types typeUtils; + final Map propertyHelpers = new HashMap<>(); + PropertyUtils(BaseConfiguration configuration) { + this.configuration = configuration; BaseOptions options = configuration.getOptions(); javafx = options.javafx(); @@ -82,30 +87,37 @@ public class PropertyUtils { : null; } + /** + * Returns a property helper for the given type element. + * @param typeElement a type element + * @return the property helper + */ + public PropertyHelper getPropertyHelper(TypeElement typeElement) { + return propertyHelpers.computeIfAbsent(typeElement, te -> new PropertyHelper(configuration, te)); + } + /** * Returns a base name for a property method. Supposing we * have {@code BooleanProperty acmeProperty()}, then "acme" * will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the base name of a property method. */ public String getBaseName(ExecutableElement propertyMethod) { String name = propertyMethod.getSimpleName().toString(); - String baseName = name.substring(0, name.indexOf("Property")); - return baseName; + return name.substring(0, name.indexOf("Property")); } /** * Returns a property getter's name. Supposing we have a property * method {@code DoubleProperty acmeProperty()}, then "getAcme" * will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the property getter's name. */ public String getGetName(ExecutableElement propertyMethod) { String baseName = getBaseName(propertyMethod); - String fnUppercased = "" + - Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + String fnUppercased = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); return "get" + fnUppercased; } @@ -113,20 +125,19 @@ public class PropertyUtils { * Returns an "is" method's name for a property method. Supposing * we have a property method {@code BooleanProperty acmeProperty()}, * then "isAcme" will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the property is getter's name. */ public String getIsName(ExecutableElement propertyMethod) { String baseName = getBaseName(propertyMethod); - String fnUppercased = "" + - Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + String fnUppercased = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); return "is" + fnUppercased; } /** * Returns true if a property method could have an "is" method, meaning * {@code isAcme} could exist for a property method. - * @param propertyMethod + * @param propertyMethod a property method * @return true if the property could have an "is" method, false otherwise. */ public boolean hasIsMethod(ExecutableElement propertyMethod) { @@ -139,20 +150,19 @@ public class PropertyUtils { * Returns a property setter's name. Supposing we have a property * method {@code DoubleProperty acmeProperty()}, then "setAcme" * will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the property setter's method name. */ public String getSetName(ExecutableElement propertyMethod) { String baseName = getBaseName(propertyMethod); - String fnUppercased = "" + - Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + String fnUppercased = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); return "set" + fnUppercased; } /** * Returns true if the given setter method is a valid property setter * method. - * @param setterMethod + * @param setterMethod a setter method * @return true if setter method, false otherwise. */ public boolean isValidSetterMethod(ExecutableElement setterMethod) { @@ -161,28 +171,28 @@ public class PropertyUtils { /** * Returns true if the method is a property method. - * @param propertyMethod + * @param method a method * @return true if the method is a property method, false otherwise. */ - public boolean isPropertyMethod(ExecutableElement propertyMethod) { + public boolean isPropertyMethod(ExecutableElement method) { if (!javafx || - !propertyMethod.getParameters().isEmpty() || - !propertyMethod.getTypeParameters().isEmpty()) { + !method.getParameters().isEmpty() || + !method.getTypeParameters().isEmpty()) { return false; } - String methodName = propertyMethod.getSimpleName().toString(); + String methodName = method.getSimpleName().toString(); if (!methodName.endsWith("Property") || fxMethodPatterns.matcher(methodName).matches()) { return false; } - TypeMirror returnType = propertyMethod.getReturnType(); + TypeMirror returnType = method.getReturnType(); if (jbObservableType == null) { // JavaFX references missing, make a lazy backward compatible check. return returnType.getKind() != TypeKind.VOID; } else { // Apply strict checks since JavaFX references are available - returnType = typeUtils.erasure(propertyMethod.getReturnType()); + returnType = typeUtils.erasure(method.getReturnType()); return typeUtils.isAssignable(returnType, jbObservableType); } } @@ -202,20 +212,13 @@ public class PropertyUtils { * method. If any method does not have a comment, one will be provided. */ public static class PropertyHelper { - private final BaseConfiguration configuration; - private final Utils utils; - private final TypeElement typeElement; + private Map classPropertiesMap = null; - private final Map classPropertiesMap = new HashMap<>(); - - public PropertyHelper(BaseConfiguration configuration, TypeElement typeElement) { - this.configuration = configuration; - this.utils = configuration.utils; - this.typeElement = typeElement; - computeProperties(); + private PropertyHelper(BaseConfiguration configuration, TypeElement typeElement) { + computeProperties(configuration, typeElement); } - private void computeProperties() { + private void computeProperties(BaseConfiguration configuration, TypeElement typeElement) { VisibleMemberTable vmt = configuration.getVisibleMemberTable(typeElement); List props = ElementFilter.methodsIn(vmt.getVisibleMembers(PROPERTIES)); for (ExecutableElement propertyMethod : props) { @@ -223,37 +226,42 @@ public class PropertyUtils { ExecutableElement setter = vmt.getPropertySetter(propertyMethod); VariableElement field = vmt.getPropertyField(propertyMethod); - addToPropertiesMap(propertyMethod, field, getter, setter); + addToPropertiesMap(configuration, propertyMethod, field, getter, setter); } } - private void addToPropertiesMap(ExecutableElement propertyMethod, + private void addToPropertiesMap(BaseConfiguration configuration, + ExecutableElement propertyMethod, VariableElement field, ExecutableElement getter, ExecutableElement setter) { // determine the preferred element from which to derive the property description - Element e = field == null || !utils.hasDocCommentTree(field) + Element e = field == null || !configuration.utils.hasDocCommentTree(field) ? propertyMethod : field; - if (e == field && utils.hasDocCommentTree(propertyMethod)) { + if (e == field && configuration.utils.hasDocCommentTree(propertyMethod)) { configuration.getReporter().print(Diagnostic.Kind.WARNING, propertyMethod, configuration.getDocResources().getText("doclet.duplicate.comment.for.property")); } - addToPropertiesMap(propertyMethod, e); - addToPropertiesMap(getter, e); - addToPropertiesMap(setter, e); + if (classPropertiesMap == null) { + classPropertiesMap = new HashMap<>(); + } + addToPropertiesMap(configuration, propertyMethod, e); + addToPropertiesMap(configuration, getter, e); + addToPropertiesMap(configuration, setter, e); } - private void addToPropertiesMap(Element propertyMethod, + private void addToPropertiesMap(BaseConfiguration configuration, + Element propertyMethod, Element commentSource) { Objects.requireNonNull(commentSource); if (propertyMethod == null) { return; } - DocCommentTree docTree = utils.hasDocCommentTree(propertyMethod) - ? utils.getDocCommentTree(propertyMethod) + DocCommentTree docTree = configuration.utils.hasDocCommentTree(propertyMethod) + ? configuration.utils.getDocCommentTree(propertyMethod) : null; /* The second condition is required for the property buckets. In @@ -271,7 +279,7 @@ public class PropertyUtils { * @return the element for the property documentation, null if there is none. */ public Element getPropertyElement(Element element) { - return classPropertiesMap.get(element); + return classPropertiesMap == null ? null : classPropertiesMap.get(element); } } } diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index 4fa89ee0ead..04e032dbe05 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -25,7 +25,7 @@ * @test * @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363 * 8167967 8172528 8175200 8178830 8182257 8186332 8182765 8025091 - * 8203791 8184205 8249633 8261976 8350920 + * 8203791 8184205 8249633 8261976 8350920 8367007 * @summary Test of the JavaFX doclet features. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -54,11 +54,18 @@ public class TestJavaFX extends JavadocTester { "-sourcepath", testSrc, "-javafx", "--disable-javafx-strict-checks", - "-Xdoclint:all,-missing", "-package", "pkg1"); checkExit(Exit.OK); + checkOutput(Output.OUT, true, + "C.java:78: warning: no comment"); + checkOutput(Output.OUT, false, + "C.java:59: warning: no comment", + "C.java:61: warning: no comment", + "C.java:63: warning: no comment", + "C.java:67: warning: no comment"); + checkOutput("pkg1/C.html", true, """

          See Also:
          @@ -266,6 +273,31 @@ public class TestJavaFX extends JavadocTester { """); checkOutput("pkg1/D.html", false, "shouldNotAppear"); + + // Test for inherited properties and property methods. + checkOrder("pkg1/B.html", + """ + Properties inherited from class C""", + """ +
          Defines if paused.
          """, + """ +
          Defines the direction/speed at which the Timeline is expected to + be played.
          """, + """ + Methods inherited from class C""", + """ +
          Gets the value of the rate property.
          """, + """ +
          Gets the value of the paused property.
          """, + """ +
          Defines if paused.
          """, + """ +
          Defines the direction/speed at which the Timeline is expected to + be played.
          """, + """ +
          Sets the value of the paused property.
          """, + """ +
          Sets the value of the rate property.
          """); } /* diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java new file mode 100644 index 00000000000..2ec6f77833a --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 pkg1; + +public class B extends C { +} From 7a3025e3d7d33ed02db34c1485aa3c7b44b2d8ee Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 10 Sep 2025 17:24:53 +0000 Subject: [PATCH 225/295] 8367348: Enhance PassFailJFrame to support links in HTML Reviewed-by: aivanov --- .../awt/regtesthelpers/PassFailJFrame.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index c0a483056df..49e56493488 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -72,6 +72,7 @@ import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; import javax.swing.border.Border; +import javax.swing.event.HyperlinkListener; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; @@ -98,7 +99,8 @@ import static javax.swing.SwingUtilities.isEventDispatchThread; * tester. The instructions can be either plain text or HTML. If the * text of the instructions starts with {@code ""}, the * instructions are displayed as HTML, as supported by Swing, which - * provides richer formatting options. + * provides richer formatting options. To handle navigating links in the + * instructions, call {@link Builder#hyperlinkListener} to install a listener. *

          * The instructions are displayed in a text component with word-wrapping * so that there's no horizontal scroll bar. If the text doesn't fit, a @@ -592,6 +594,7 @@ public final class PassFailJFrame { frame.add(createInstructionUIPanel(instructions, testTimeOut, rows, columns, + null, false, false, 0), BorderLayout.CENTER); @@ -610,6 +613,7 @@ public final class PassFailJFrame { createInstructionUIPanel(builder.instructions, builder.testTimeOut, builder.rows, builder.columns, + builder.hyperlinkListener, builder.screenCapture, builder.addLogArea, builder.logAreaRows); @@ -631,6 +635,7 @@ public final class PassFailJFrame { private static JComponent createInstructionUIPanel(String instructions, long testTimeOut, int rows, int columns, + HyperlinkListener hyperlinkListener, boolean enableScreenCapture, boolean addLogArea, int logAreaRows) { @@ -643,6 +648,9 @@ public final class PassFailJFrame { JTextComponent text = instructions.startsWith("") ? configureHTML(instructions, rows, columns) : configurePlainText(instructions, rows, columns); + if (hyperlinkListener != null && text instanceof JEditorPane ep) { + ep.addHyperlinkListener(hyperlinkListener); + } text.setEditable(false); text.setBorder(createTextBorder()); text.setCaretPosition(0); @@ -716,7 +724,7 @@ public final class PassFailJFrame { // Reduce the list default margins styles.addRule("ol, ul { margin-left-ltr: 30; margin-left-rtl: 30 }"); // Make the size of code (and other elements) the same as other text - styles.addRule("code, kbd, samp, pre { font-size: inherit }"); + styles.addRule("code, kbd, samp, pre { font-size: inherit; background: #DDD; }"); return text; } @@ -1398,6 +1406,7 @@ public final class PassFailJFrame { private int rows; private int columns; private boolean screenCapture; + private HyperlinkListener hyperlinkListener; private boolean addLogArea; private int logAreaRows = 10; @@ -1478,6 +1487,18 @@ public final class PassFailJFrame { return this; } + /** + * Sets a {@link HyperlinkListener} for navigating links inside + * the instructions pane. + * + * @param hyperlinkListener the listener + * @return this builder + */ + public Builder hyperlinkListener(HyperlinkListener hyperlinkListener) { + this.hyperlinkListener = hyperlinkListener; + return this; + } + public Builder screenCapture() { this.screenCapture = true; return this; From 4e2a85f7500876d65c36aeaf54f5361a1549e7f5 Mon Sep 17 00:00:00 2001 From: Man Cao Date: Wed, 10 Sep 2025 17:42:15 +0000 Subject: [PATCH 226/295] 8366118: DontCompileHugeMethods is not respected with -XX:-TieredCompilation Co-authored-by: Chuck Rasbold Co-authored-by: Justin King Reviewed-by: rasbold, iveresov, jiangli --- .../share/compiler/compilationPolicy.cpp | 39 +++--- .../runtime/TestDontCompileHugeMethods.java | 122 ++++++++++++++++++ 2 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 5db6cb1b0cc..36b597b6e37 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -922,28 +922,29 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level return; } - if (!CompilationModeFlag::disable_intermediate()) { - // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling - // in the interpreter and then compile with C2 (the transition function will request that, - // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with - // pure C1. - if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) { - if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { - compile(mh, bci, CompLevel_simple, THREAD); - } - return; + // Check if the method can be compiled. Additional logic for TieredCompilation: + // If it cannot be compiled with C1, continue profiling in the interpreter + // and then compile with C2 (the transition function will request that, + // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with + // pure C1. + if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) { + if (!CompilationModeFlag::disable_intermediate() && + level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { + compile(mh, bci, CompLevel_simple, THREAD); } - if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) { - if (level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) { - nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); - if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) { - // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. - osr_nm->make_not_entrant(nmethod::InvalidationReason::OSR_INVALIDATION_FOR_COMPILING_WITH_C1); - } - compile(mh, bci, CompLevel_simple, THREAD); + return; + } + if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) { + if (!CompilationModeFlag::disable_intermediate() && + level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) { + nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); + if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) { + // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. + osr_nm->make_not_entrant(nmethod::InvalidationReason::OSR_INVALIDATION_FOR_COMPILING_WITH_C1); } - return; + compile(mh, bci, CompLevel_simple, THREAD); } + return; } if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) { return; diff --git a/test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java b/test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java new file mode 100644 index 00000000000..c5e035edbd0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025, Google LLC. All rights reserved. + * 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 8366118 + * @summary Check that a huge method is not compiled under -XX:+DontCompileHugeMethods. + * @library /test/lib + * @run main compiler.runtime.TestDontCompileHugeMethods + */ +package compiler.runtime; + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class TestDontCompileHugeMethods { + + private static final String HUGE_SWITCH_CLASS_NAME = "HugeSwitch"; + + private static void generateClass(Writer writer) throws IOException { + writer.write(""" + public class HugeSwitch { + private static int hugeSwitch(int x) { + switch (x) { + """); + for (int i = 0; i < 2000; i++) { + writer.write(" case " + i + ": return " + i + " + 1;\n"); + } + writer.write(""" + default: + return 0; + } + } + private static int shortMethod(int x) { + if (x % 3 == 0) { + return x - 1; + } + return x + 1; + } + public static void main(String[] args) { + int val = 0; + for (int i = 0; i < 100000; i++) { + val += hugeSwitch(shortMethod(i)); + } + System.out.println(val); + } + } + """); + } + + private static void compileClass(Path workDir, Path sourceFile) throws Exception { + JDKToolLauncher javac = JDKToolLauncher.create("javac").addToolArg("-d") + .addToolArg(workDir.toAbsolutePath().toString()).addToolArg("-cp") + .addToolArg(Utils.TEST_CLASS_PATH).addToolArg(sourceFile.toAbsolutePath().toString()); + + OutputAnalyzer output = ProcessTools.executeProcess(javac.getCommand()); + output.shouldHaveExitValue(0); + } + + private static void generateAndCompileClass(Path workDir) throws Exception { + Path sourceFile = workDir.resolve(HUGE_SWITCH_CLASS_NAME + ".java"); + try (Writer writer = Files.newBufferedWriter(sourceFile)) { + generateClass(writer); + } catch (IOException e) { + throw new RuntimeException(e); + } + compileClass(workDir, sourceFile); + } + + private static void runTest(Path workDir, List jvmArgs) throws Exception { + ArrayList command = new ArrayList<>(); + command.add("-XX:+PrintCompilation"); + command.add("-Xbatch"); + command.addAll(jvmArgs); + command.add("-cp"); + command.add(workDir.toAbsolutePath().toString()); + command.add(HUGE_SWITCH_CLASS_NAME); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(command); + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + analyzer.shouldHaveExitValue(0); + analyzer.shouldContain(" HugeSwitch::shortMethod ("); + analyzer.shouldNotContain(" HugeSwitch::hugeSwitch ("); + } + + public static void main(String[] args) throws Exception { + Path workDir = Paths.get(""); + generateAndCompileClass(workDir); + + runTest(workDir, List.of()); + runTest(workDir, List.of("-XX:-TieredCompilation")); + } +} From fdc11a1569248c9b671b66d547b4616aeb953ecf Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 10 Sep 2025 18:41:42 +0000 Subject: [PATCH 227/295] 8367131: Test com/sun/jdi/ThreadMemoryLeakTest.java fails on 32 bits Reviewed-by: lmesnik, cjplummer, shade --- test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java index 59168a4de7e..5431b8835a2 100644 --- a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java +++ b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java @@ -28,7 +28,7 @@ * * @comment Don't allow -Xcomp or -Xint as they impact memory useage and number of iterations. * Require compressed oops because not doing so increases memory usage. - * @requires (vm.compMode == "Xmixed") & vm.opt.final.UseCompressedOops + * @requires (vm.compMode == "Xmixed") & (vm.bits == 32 | vm.opt.final.UseCompressedOops) * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g ThreadMemoryLeakTest.java * @comment run with -Xmx7m so any leak will quickly produce OOME From 85715e1050fa774c3267dbbe2f749717aeeec8ff Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 10 Sep 2025 19:21:00 +0000 Subject: [PATCH 228/295] 8317269: Store old classes in linked state in AOT cache Reviewed-by: coleenp, matsaave --- src/hotspot/share/cds/aotMetaspace.cpp | 20 +- src/hotspot/share/cds/aotMetaspace.hpp | 1 + src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/cds/cdsConfig.cpp | 30 ++ src/hotspot/share/cds/cdsConfig.hpp | 9 + src/hotspot/share/cds/dumpTimeClassInfo.cpp | 13 +- src/hotspot/share/cds/dumpTimeClassInfo.hpp | 15 +- src/hotspot/share/cds/dynamicArchive.cpp | 6 + .../share/cds/lambdaProxyClassDictionary.cpp | 6 +- src/hotspot/share/cds/runTimeClassInfo.cpp | 10 +- src/hotspot/share/cds/runTimeClassInfo.hpp | 4 +- .../classfile/systemDictionaryShared.cpp | 316 +++++++++++++++--- .../classfile/systemDictionaryShared.hpp | 21 +- src/hotspot/share/oops/instanceKlass.cpp | 14 +- src/hotspot/share/oops/methodData.cpp | 5 +- src/hotspot/share/oops/trainingData.cpp | 9 +- src/hotspot/share/prims/jvm.cpp | 7 + src/hotspot/share/runtime/mutexLocker.cpp | 4 +- test/hotspot/jtreg/TEST.groups | 6 +- .../cds/appcds/aotCache/ExcludedClasses.java | 12 +- .../runtime/cds/appcds/aotCache/OldA.jasm | 38 +++ .../cds/appcds/aotCache/OldClassSupport.java | 162 +++++++++ ...dClassWithExcludedVerifierConstraints.jasm | 50 +++ .../OldClassWithVerifierConstraints.jasm | 50 +++ .../AOTClassLinkingVerification.java | 294 ++++++++++++++++ .../appcds/aotClassLinking/BadNewClass.jasm | 52 +++ .../appcds/aotClassLinking/BadNewClass2.jasm | 52 +++ .../appcds/aotClassLinking/BadNewClass3.jasm | 53 +++ .../appcds/aotClassLinking/BadNewClass4.jasm | 53 +++ .../appcds/aotClassLinking/BadOldClass.jasm | 52 +++ .../appcds/aotClassLinking/BadOldClass2.jasm | 52 +++ .../appcds/aotClassLinking/BadOldClass3.jasm | 53 +++ .../appcds/aotClassLinking/BadOldClass4.jasm | 53 +++ .../aotClassLinking/BulkLoaderTest.java | 2 +- .../appcds/aotClassLinking/GoodOldClass.jasm | 49 +++ 35 files changed, 1485 insertions(+), 90 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index c2d9d0193f5..cca82bed4f1 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -652,6 +652,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& } void VM_PopulateDumpSharedSpace::doit() { + CDSConfig::set_is_at_aot_safepoint(true); + if (!CDSConfig::is_dumping_final_static_archive()) { guarantee(!CDSConfig::is_using_archive(), "We should not be using an archive when we dump"); } @@ -717,6 +719,8 @@ void VM_PopulateDumpSharedSpace::doit() { _map_info->set_serialized_data(serialized_data); _map_info->set_cloned_vtables(CppVtables::vtables_serialized_base()); _map_info->header()->set_class_location_config(cl_config); + + CDSConfig::set_is_at_aot_safepoint(false); } class CollectClassesForLinking : public KlassClosure { @@ -773,12 +777,9 @@ bool AOTMetaspace::may_be_eagerly_linked(InstanceKlass* ik) { return true; } -void AOTMetaspace::link_shared_classes(TRAPS) { - AOTClassLinker::initialize(); - AOTClassInitializer::init_test_class(CHECK); - +void AOTMetaspace::link_all_loaded_classes(JavaThread* current) { while (true) { - ResourceMark rm(THREAD); + ResourceMark rm(current); CollectClassesForLinking collect_classes; bool has_linked = false; const GrowableArray* mirrors = collect_classes.mirrors(); @@ -786,7 +787,7 @@ void AOTMetaspace::link_shared_classes(TRAPS) { OopHandle mirror = mirrors->at(i); InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); if (may_be_eagerly_linked(ik)) { - has_linked |= try_link_class(THREAD, ik); + has_linked |= try_link_class(current, ik); } } @@ -796,6 +797,13 @@ void AOTMetaspace::link_shared_classes(TRAPS) { // Class linking includes verification which may load more classes. // Keep scanning until we have linked no more classes. } +} + +void AOTMetaspace::link_shared_classes(TRAPS) { + AOTClassLinker::initialize(); + AOTClassInitializer::init_test_class(CHECK); + + link_all_loaded_classes(THREAD); // Eargerly resolve all string constants in constant pools { diff --git a/src/hotspot/share/cds/aotMetaspace.hpp b/src/hotspot/share/cds/aotMetaspace.hpp index 6c0ad37dbf7..1803199766d 100644 --- a/src/hotspot/share/cds/aotMetaspace.hpp +++ b/src/hotspot/share/cds/aotMetaspace.hpp @@ -135,6 +135,7 @@ public: } static bool try_link_class(JavaThread* current, InstanceKlass* ik); + static void link_all_loaded_classes(JavaThread* current); static void link_shared_classes(TRAPS) NOT_CDS_RETURN; static bool may_be_eagerly_linked(InstanceKlass* ik) NOT_CDS_RETURN_(false); diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 42d575a012f..77f51443bb2 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -937,7 +937,7 @@ void ArchiveBuilder::make_klasses_shareable() { ADD_COUNT(num_enum_klasses); } - if (!ik->can_be_verified_at_dumptime()) { + if (CDSConfig::is_old_class_for_verifier(ik)) { ADD_COUNT(num_old_klasses); old = " old"; } diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 90b802731f0..d3048b9ee7a 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -56,6 +56,7 @@ bool CDSConfig::_has_temp_aot_config_file = false; bool CDSConfig::_old_cds_flags_used = false; bool CDSConfig::_new_aot_flags_used = false; bool CDSConfig::_disable_heap_dumping = false; +bool CDSConfig::_is_at_aot_safepoint = false; const char* CDSConfig::_default_archive_path = nullptr; const char* CDSConfig::_input_static_archive_path = nullptr; @@ -922,6 +923,35 @@ bool CDSConfig::is_dumping_lambdas_in_legacy_mode() { return !is_dumping_method_handles(); } +bool CDSConfig::is_preserving_verification_constraints() { + // Verification dependencies are classes used in assignability checks by the + // bytecode verifier. In the following example, the verification dependencies + // for X are A and B. + // + // class X { + // A getA() { return new B(); } + // } + // + // With the AOT cache, we can ensure that all the verification dependencies + // (A and B in the above example) are unconditionally loaded during the bootstrap + // of the production run. This means that if a class was successfully verified + // in the assembly phase, all of the verifier's assignability checks will remain + // valid in the production run, so we don't need to verify aot-linked classes again. + + if (is_dumping_preimage_static_archive()) { // writing AOT config + return AOTClassLinking; + } else if (is_dumping_final_static_archive()) { // writing AOT cache + return is_dumping_aot_linked_classes(); + } else { + // For simplicity, we don't support this optimization with the old CDS workflow. + return false; + } +} + +bool CDSConfig::is_old_class_for_verifier(const InstanceKlass* ik) { + return ik->major_version() < 50 /*JAVA_6_VERSION*/; +} + #if INCLUDE_CDS_JAVA_HEAP bool CDSConfig::are_vm_options_incompatible_with_dumping_heap() { return check_options_incompatible_with_dumping_heap() != nullptr; diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index 1fd229ff34f..8361cf052db 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -30,6 +30,7 @@ #include "utilities/macros.hpp" class JavaThread; +class InstanceKlass; class CDSConfig : public AllStatic { #if INCLUDE_CDS @@ -43,6 +44,7 @@ class CDSConfig : public AllStatic { static bool _has_aot_linked_classes; static bool _is_single_command_training; static bool _has_temp_aot_config_file; + static bool _is_at_aot_safepoint; const static char* _default_archive_path; const static char* _input_static_archive_path; @@ -99,6 +101,9 @@ public: static const char* type_of_archive_being_written(); static void prepare_for_dumping(); + static bool is_at_aot_safepoint() { return CDS_ONLY(_is_at_aot_safepoint) NOT_CDS(false); } + static void set_is_at_aot_safepoint(bool value) { CDS_ONLY(_is_at_aot_safepoint = value); } + // --- Basic CDS features // archive(s) in general @@ -161,6 +166,10 @@ public: static bool is_using_aot_linked_classes() NOT_CDS_JAVA_HEAP_RETURN_(false); static void set_has_aot_linked_classes(bool has_aot_linked_classes) NOT_CDS_JAVA_HEAP_RETURN; + // Bytecode verification + static bool is_preserving_verification_constraints(); + static bool is_old_class_for_verifier(const InstanceKlass* ik); + // archive_path // Points to the classes.jsa in $JAVA_HOME (could be input or output) diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.cpp b/src/hotspot/share/cds/dumpTimeClassInfo.cpp index 8af762dba4d..0f5773a2729 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -47,7 +47,7 @@ size_t DumpTimeClassInfo::runtime_info_bytesize() const { num_enum_klass_static_fields()); } -void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name, +void DumpTimeClassInfo::add_verification_constraint(Symbol* name, Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) { if (_verifier_constraints == nullptr) { _verifier_constraints = new (mtClass) GrowableArray(4, mtClass); @@ -73,9 +73,14 @@ void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* na if (log_is_enabled(Trace, aot, verification)) { ResourceMark rm; - log_trace(aot, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x] array len %d flags len %d", - k->external_name(), from_name->as_klass_external_name(), - name->as_klass_external_name(), c, vc_array->length(), vcflags_array->length()); + if (from_name != nullptr) { + log_trace(aot, verification)("add verification constraint: %s: %s must be subclass of %s [0x%x]", + _klass->external_name(), from_name->as_klass_external_name(), + name->as_klass_external_name(), c); + } else { + log_trace(aot, verification)("added old verification constraint: %s: %s", _klass->external_name(), + name->as_klass_external_name()); + } } } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 0bc0f8bedda..c2f83b22337 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -88,7 +88,7 @@ class DumpTimeClassInfo: public CHeapObj { Symbol* _from_name; public: DTVerifierConstraint() : _name(nullptr), _from_name(nullptr) {} - DTVerifierConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) { + DTVerifierConstraint(Symbol* n, Symbol* fn = nullptr) : _name(n), _from_name(fn) { Symbol::maybe_increment_refcount(_name); Symbol::maybe_increment_refcount(_from_name); } @@ -152,8 +152,9 @@ public: DumpTimeClassInfo& operator=(const DumpTimeClassInfo&) = delete; ~DumpTimeClassInfo(); - void add_verification_constraint(InstanceKlass* k, Symbol* name, - Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object); + // For old verifier: only name is saved; all other fields are null/false. + void add_verification_constraint(Symbol* name, + Symbol* from_name = nullptr, bool from_field_is_protected = false, bool from_is_array = false, bool from_is_object = false); void record_linking_constraint(Symbol* name, Handle loader1, Handle loader2); void add_enum_klass_static_field(int archived_heap_root_index); int enum_klass_static_field(int which_field); @@ -175,6 +176,14 @@ public: return array_length_or_zero(_verifier_constraint_flags); } + Symbol* verifier_constraint_name_at(int i) const { + return _verifier_constraints->at(i).name(); + } + + Symbol* verifier_constraint_from_name_at(int i) const { + return _verifier_constraints->at(i).from_name(); + } + int num_loader_constraints() const { return array_length_or_zero(_loader_constraints); } diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index d628a4e991f..58b354b9240 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -110,6 +110,12 @@ public: } void doit() { + CDSConfig::set_is_at_aot_safepoint(true); + doit_inner(); + CDSConfig::set_is_at_aot_safepoint(false); + } + + void doit_inner() { verify_universe("Before CDS dynamic dump"); DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index c8281ef497c..62b1b8c05f1 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -471,12 +471,12 @@ class LambdaProxyClassDictionary::CleanupDumpTimeLambdaProxyClassTable: StackObj // If the caller class and/or nest_host are excluded, the associated lambda proxy // must also be excluded. - bool always_exclude = SystemDictionaryShared::check_for_exclusion(caller_ik, nullptr) || - SystemDictionaryShared::check_for_exclusion(nest_host, nullptr); + bool always_exclude = SystemDictionaryShared::should_be_excluded(caller_ik) || + SystemDictionaryShared::should_be_excluded(nest_host); for (int i = info._proxy_klasses->length() - 1; i >= 0; i--) { InstanceKlass* ik = info._proxy_klasses->at(i); - if (always_exclude || SystemDictionaryShared::check_for_exclusion(ik, nullptr)) { + if (always_exclude || SystemDictionaryShared::should_be_excluded(ik)) { LambdaProxyClassDictionary::reset_registered_lambda_proxy_class(ik); info._proxy_klasses->remove_at(i); } diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index d93ef5e9c1d..832b0ce8932 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -40,12 +40,18 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { _num_verifier_constraints = info.num_verifier_constraints(); _num_loader_constraints = info.num_loader_constraints(); int i; + + if (CDSConfig::is_preserving_verification_constraints() && CDSConfig::is_dumping_final_static_archive()) { + // The production run doesn't need the verifier constraints, as we can guarantee that all classes checked by + // the verifier during AOT training/assembly phases cannot be replaced in the production run. + _num_verifier_constraints = 0; + } if (_num_verifier_constraints > 0) { RTVerifierConstraint* vf_constraints = verifier_constraints(); char* flags = verifier_constraint_flags(); for (i = 0; i < _num_verifier_constraints; i++) { - vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i).name()); - vf_constraints[i]._from_name = builder->any_to_offset_u4(info._verifier_constraints->at(i).from_name()); + vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i).name()); + vf_constraints[i]._from_name = builder->any_or_null_to_offset_u4(info._verifier_constraints->at(i).from_name()); } for (i = 0; i < _num_verifier_constraints; i++) { flags[i] = info._verifier_constraint_flags->at(i); diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index 29670f5ec51..371924f9065 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -59,7 +59,9 @@ class RunTimeClassInfo { u4 _name; u4 _from_name; Symbol* name() { return ArchiveUtils::offset_to_archived_address(_name); } - Symbol* from_name() { return ArchiveUtils::offset_to_archived_address(_from_name); } + Symbol* from_name() { + return (_from_name == 0) ? nullptr : ArchiveUtils::offset_to_archived_address(_from_name); + } }; struct RTLoaderConstraint { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 45a5dc2328c..eda823704ca 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -204,28 +204,156 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { return info; } -bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { - // We have reached a super type that's already in the base archive. Treat it - // as "not excluded". - return false; - } - - if (info == nullptr) { - info = _dumptime_table->get(k); - assert(info != nullptr, "supertypes of any classes in _dumptime_table must either be shared, or must also be in _dumptime_table"); - } +bool SystemDictionaryShared::should_be_excluded_impl(InstanceKlass* k, DumpTimeClassInfo* info) { + assert_lock_strong(DumpTimeTable_lock); if (!info->has_checked_exclusion()) { - if (check_for_exclusion_impl(k)) { - info->set_excluded(); - } - info->set_has_checked_exclusion(); + check_exclusion_for_self_and_dependencies(k); + assert(info->has_checked_exclusion(), "must be"); } return info->is_excluded(); } +// returns bool and takes a single parameter of Symbol* +// The return value indicates whether we want to keep on iterating or not. +template +void SystemDictionaryShared::iterate_verification_constraint_names(InstanceKlass* k, DumpTimeClassInfo* info, Function func) { + int n = info->num_verifier_constraints(); + bool cont; // continue iterating? + for (int i = 0; i < n; i++) { + cont = func(info->verifier_constraint_name_at(i)); + if (!cont) { + return; // early termination + } + Symbol* from_name = info->verifier_constraint_from_name_at(i); + if (from_name != nullptr) { + cont = func(from_name); + if (!cont) { + return; // early termination + } + } + } +} + +// This is a table of classes that need to be checked for exclusion. +class SystemDictionaryShared::ExclusionCheckCandidates + : public HashTable { + void add_candidate(InstanceKlass* k) { + if (contains(k)) { + return; + } + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { + return; + } + + DumpTimeClassInfo* info = SystemDictionaryShared::get_info_locked(k); + if (info->has_checked_exclusion()) { + // We have check exclusion of k and all of its dependencies, so there's no need to check again. + return; + } + + put(k, info); + + if (!k->is_loaded()) { + // super types are not yet initialized for k. + return; + } + + InstanceKlass* super = k->java_super(); + if (super != nullptr) { + add_candidate(super); + } + + Array* interfaces = k->local_interfaces(); + int len = interfaces->length(); + for (int i = 0; i < len; i++) { + add_candidate(interfaces->at(i)); + } + + InstanceKlass* nest_host = k->nest_host_or_null(); + if (nest_host != nullptr && nest_host != k) { + add_candidate(nest_host); + } + + if (CDSConfig::is_preserving_verification_constraints()) { + SystemDictionaryShared::iterate_verification_constraint_names(k, info, [&] (Symbol* constraint_class_name) { + Klass* constraint_bottom_class = find_verification_constraint_bottom_class(k, constraint_class_name); + if (constraint_bottom_class != nullptr && constraint_bottom_class->is_instance_klass()) { + add_candidate(InstanceKlass::cast(constraint_bottom_class)); + } + return true; // Keep iterating. + }); + } + } + +public: + ExclusionCheckCandidates(InstanceKlass* k) { + add_candidate(k); + } +}; + +// A class X is excluded if check_self_exclusion() returns true for X or any of +// X's "exclusion dependency" classes, which include: +// - ik's super types +// - ik's nest host (if any) +// +// plus, if CDSConfig::is_preserving_verification_constraints()==true: +// - ik's verification constraints. These are the classes used in assignability checks +// when verifying ik's bytecodes. +// +// This method ensure that exclusion check is performed on X and all of its exclusion dependencies. +void SystemDictionaryShared::check_exclusion_for_self_and_dependencies(InstanceKlass* ik) { + assert_lock_strong(DumpTimeTable_lock); + ResourceMark rm; + + // This will recursively find ik and all of its exclusion dependencies that have not yet been checked. + ExclusionCheckCandidates candidates(ik); + + // (1) Check each class to see if it should be excluded due to its own problems + candidates.iterate_all([&] (InstanceKlass* k, DumpTimeClassInfo* info) { + if (check_self_exclusion(k)) { + info->set_excluded(); + } + }); + + // (2) Check each class to see if it should be excluded because of problems in a depeendency class + while (true) { + bool found_new_exclusion = false; + + candidates.iterate_all([&] (InstanceKlass* k, DumpTimeClassInfo* info) { + if (!info->is_excluded() && check_dependencies_exclusion(k, info)) { + info->set_excluded(); + found_new_exclusion = true; + } + }); + + // Algorithm notes: + // + // The dependencies form a directed graph, possibly cyclic. Class X is excluded + // if it has at least one directed path that reaches class Y, where + // check_self_exclusion(Y) returns true. + // + // Because of the possibility of cycles in the graph, we cannot use simple + // recursion. Otherwise we will either never terminate, or will miss some paths. + // + // Hence, we keep doing a linear scan of the candidates until we stop finding + // new exclusions. + // + // In the worst case, we find one exclusion per iteration of the while loop, + // so the while loop gets executed O(N^2) times. However, in reality we have + // very few exclusions, so in most cases the while loop executes only once, and we + // walk each edge in the dependencies graph exactly once. + if (!found_new_exclusion) { + break; + } + } + candidates.iterate_all([&] (InstanceKlass* k, DumpTimeClassInfo* info) { + // All candidates have been fully checked, so we don't need to check them again. + info->set_has_checked_exclusion(); + }); +} + // Returns true so the caller can do: return warn_excluded("....."); bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) { ResourceMark rm; @@ -248,7 +376,8 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { return (info != nullptr) ? info->is_early_klass() : false; } -bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { +bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { + assert_lock_strong(DumpTimeTable_lock); if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() && k->in_aot_cache()) { return false; // Do not exclude: unregistered classes are passed from preimage to final image. @@ -301,9 +430,8 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return warn_excluded(k, "Failed verification"); } else if (CDSConfig::is_dumping_aot_linked_classes()) { // Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds(). - // However, we do not speculatively link old classes, as they are not recorded by - // SystemDictionaryShared::record_linking_constraint(). As a result, such an unlinked - // class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), + // Old classes may not be linked if CDSConfig::is_preserving_verification_constraints()==false. + // An unlinked class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), // causing the JVM to fail at bootstrap. return warn_excluded(k, "Unlinked class not supported by AOTClassLinking"); } else if (CDSConfig::is_dumping_preimage_static_archive()) { @@ -329,10 +457,13 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return true; } - InstanceKlass* super = k->super(); - if (super != nullptr && check_for_exclusion(super, nullptr)) { - ResourceMark rm; - aot_log_warning(aot)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); + return false; +} + +// Returns true if DumpTimeClassInfo::is_excluded() is true for at least one of k's exclusion dependencies. +bool SystemDictionaryShared::check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { + InstanceKlass* super = k->java_super(); + if (super != nullptr && is_dependency_excluded(k, super, "super")) { return true; } @@ -340,21 +471,87 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { int len = interfaces->length(); for (int i = 0; i < len; i++) { InstanceKlass* intf = interfaces->at(i); - if (check_for_exclusion(intf, nullptr)) { - ResourceMark rm; - aot_log_warning(aot)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string()); + if (is_dependency_excluded(k, intf, "interface")) { return true; } } InstanceKlass* nest_host = k->nest_host_or_null(); - if (nest_host != nullptr && nest_host != k && check_for_exclusion(nest_host, nullptr)) { - ResourceMark rm; - aot_log_warning(aot)("Skipping %s: nest_host class %s is excluded", k->name()->as_C_string(), nest_host->name()->as_C_string()); + if (nest_host != nullptr && nest_host != k && is_dependency_excluded(k, nest_host, "nest host class")) { return true; } - return false; // false == k should NOT be excluded + if (CDSConfig::is_preserving_verification_constraints()) { + bool excluded = false; + + iterate_verification_constraint_names(k, info, [&] (Symbol* constraint_class_name) { + if (check_verification_constraint_exclusion(k, constraint_class_name)) { + // If one of the verification constraint class has been excluded, the assignability checks + // by the verifier may no longer be valid in the production run. For safety, exclude this class. + excluded = true; + return false; // terminate iteration; k will be excluded + } else { + return true; // keep iterating + } + }); + + if (excluded) { + // At least one verification constraint class has been excluded + return true; + } + } + + return false; +} + +bool SystemDictionaryShared::is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(dependency)) { + return false; + } + DumpTimeClassInfo* dependency_info = get_info_locked(dependency); + if (dependency_info->is_excluded()) { + ResourceMark rm; + aot_log_warning(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string()); + return true; + } + return false; +} + +bool SystemDictionaryShared::check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name) { + Klass* constraint_bottom_class = find_verification_constraint_bottom_class(k, constraint_class_name); + if (constraint_bottom_class == nullptr) { + // We don't have a bottom class (constraint_class_name is a type array), or constraint_class_name + // has not been loaded. The latter case happens when the new verifier was checking + // if constraint_class_name is assignable to an interface, and found the answer without resolving + // constraint_class_name. + // + // Since this class is not even loaded, it surely cannot be excluded. + return false; + } else if (constraint_bottom_class->is_instance_klass()) { + if (is_dependency_excluded(k, InstanceKlass::cast(constraint_bottom_class), "verification constraint")) { + return true; + } + } else { + assert(constraint_bottom_class->is_typeArray_klass(), "must be"); + } + + return false; +} + +Klass* SystemDictionaryShared::find_verification_constraint_bottom_class(InstanceKlass* k, Symbol* constraint_class_name) { + Thread* current = Thread::current(); + Handle loader(current, k->class_loader()); + Klass* constraint_class = SystemDictionary::find_instance_or_array_klass(current, constraint_class_name, loader); + if (constraint_class == nullptr) { + return nullptr; + } + + if (constraint_class->is_objArray_klass()) { + constraint_class = ObjArrayKlass::cast(constraint_class)->bottom_klass(); + } + + precond(constraint_class->is_typeArray_klass() || constraint_class->is_instance_klass()); + return constraint_class; } bool SystemDictionaryShared::is_builtin_loader(ClassLoaderData* loader_data) { @@ -556,7 +753,7 @@ void SystemDictionaryShared::handle_class_unloading(InstanceKlass* klass) { void SystemDictionaryShared::init_dumptime_info_from_preimage(InstanceKlass* k) { init_dumptime_info(k); - copy_verification_constraints_from_preimage(k); + copy_verification_info_from_preimage(k); copy_linking_constraints_from_preimage(k); if (SystemDictionary::is_platform_class_loader(k->class_loader())) { @@ -651,16 +848,21 @@ public: // Returns true if the class should be excluded. This can be called by // AOTConstantPoolResolver before or after we enter the CDS safepoint. // When called before the safepoint, we need to link the class so that -// it can be checked by check_for_exclusion(). +// it can be checked by should_be_excluded_impl(). bool SystemDictionaryShared::should_be_excluded(Klass* k) { assert(CDSConfig::is_dumping_archive(), "sanity"); assert(CDSConfig::current_thread_is_vm_or_dumper(), "sanity"); - if (k->is_objArray_klass()) { - return should_be_excluded(ObjArrayKlass::cast(k)->bottom_klass()); + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { + // We have reached a super type that's already in the base archive. Treat it + // as "not excluded". + return false; } - if (!k->is_instance_klass()) { + if (k->is_objArray_klass()) { + return should_be_excluded(ObjArrayKlass::cast(k)->bottom_klass()); + } else if (!k->is_instance_klass()) { + assert(k->is_typeArray_klass(), "must be"); return false; } else { InstanceKlass* ik = InstanceKlass::cast(k); @@ -672,7 +874,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { if (!SafepointSynchronize::is_at_safepoint()) { if (!ik->is_linked()) { - // check_for_exclusion() below doesn't link unlinked classes. We come + // should_be_excluded_impl() below doesn't link unlinked classes. We come // here only when we are trying to aot-link constant pool entries, so // we'd better link the class. JavaThread* THREAD = JavaThread::current(); @@ -681,6 +883,10 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { CLEAR_PENDING_EXCEPTION; return true; // linking failed -- let's exclude it } + + // Also link any classes that were loaded for the verification of ik or its supertypes. + // Otherwise we might miss the verification constraints of those classes. + AOTMetaspace::link_all_loaded_classes(THREAD); } MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); @@ -688,8 +894,17 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { if (p->is_excluded()) { return true; } - return check_for_exclusion(ik, p); + return should_be_excluded_impl(ik, p); } else { + // When called within the CDS safepoint, the correctness of this function + // relies on the call to AOTMetaspace::link_all_loaded_classes() + // that happened right before we enter the CDS safepoint. + // + // Do not call this function in other types of safepoints. For example, if this + // is called in a GC safepoint, a klass may be improperly excluded because some + // of its verification constraints have not yet been linked. + assert(CDSConfig::is_at_aot_safepoint(), "Do not call this function in any other safepoint"); + // No need to check for is_linked() as all eligible classes should have // already been linked in AOTMetaspace::link_class_for_cds(). // Can't take the lock as we are in safepoint. @@ -697,12 +912,13 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { if (p->is_excluded()) { return true; } - return check_for_exclusion(ik, p); + return should_be_excluded_impl(ik, p); } } } void SystemDictionaryShared::finish_exclusion_checks() { + assert_at_safepoint(); if (CDSConfig::is_dumping_dynamic_archive() || CDSConfig::is_dumping_preimage_static_archive()) { // Do this first -- if a base class is excluded due to duplication, // all of its subclasses will also be excluded. @@ -713,7 +929,7 @@ void SystemDictionaryShared::finish_exclusion_checks() { } _dumptime_table->iterate_all_live_classes([&] (InstanceKlass* k, DumpTimeClassInfo& info) { - SystemDictionaryShared::check_for_exclusion(k, &info); + SystemDictionaryShared::should_be_excluded_impl(k, &info); }); _dumptime_table->update_counts(); @@ -793,7 +1009,7 @@ void SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbo bool* skip_assignability_check) { assert(CDSConfig::is_dumping_archive(), "sanity"); DumpTimeClassInfo* info = get_info(k); - info->add_verification_constraint(k, name, from_name, from_field_is_protected, + info->add_verification_constraint(name, from_name, from_field_is_protected, from_is_array, from_is_object); if (CDSConfig::is_dumping_classic_static_archive() && !is_builtin(k)) { @@ -818,6 +1034,15 @@ void SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbo } } +// When the old verifier is verifying the class at dump time, it tries to resolve a +// class with the given . For the verification result to be valid at run time, we must +// ensure that resolves to the exact same Klass as in dump time. +void SystemDictionaryShared::add_old_verification_constraint(Thread* current, InstanceKlass* ik, Symbol* name) { + precond(CDSConfig::is_preserving_verification_constraints()); + DumpTimeClassInfo* info = get_info(ik); + info->add_verification_constraint(name); +} + void SystemDictionaryShared::add_enum_klass_static_field(InstanceKlass* ik, int root_index) { assert(CDSConfig::is_dumping_heap(), "sanity"); DumpTimeClassInfo* info = get_info_locked(ik); @@ -836,6 +1061,13 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass Symbol* name = vc->name(); Symbol* from_name = vc->from_name(); + if (from_name == nullptr) { + // This is for old verifier. No need to check, as we can guarantee that all classes checked by + // the old verifier during AOT training phase cannot be replaced in the asembly phase. + precond(CDSConfig::is_dumping_final_static_archive()); + continue; + } + if (log_is_enabled(Trace, aot, verification)) { ResourceMark rm(THREAD); log_trace(aot, verification)("check_verification_constraint: %s: %s must be subclass of %s [0x%x]", @@ -860,7 +1092,7 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass } } -void SystemDictionaryShared::copy_verification_constraints_from_preimage(InstanceKlass* klass) { +void SystemDictionaryShared::copy_verification_info_from_preimage(InstanceKlass* klass) { assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); DumpTimeClassInfo* dt_info = get_info(klass); RunTimeClassInfo* rt_info = RunTimeClassInfo::get_for(klass); // from preimage @@ -872,7 +1104,7 @@ void SystemDictionaryShared::copy_verification_constraints_from_preimage(Instanc Symbol* name = vc->name(); Symbol* from_name = vc->from_name(); - dt_info->add_verification_constraint(klass, name, from_name, + dt_info->add_verification_constraint(name, from_name, rt_info->from_field_is_protected(i), rt_info->from_is_array(i), rt_info->from_is_object(i)); } } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 30b38a5aa59..baad020cb61 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -146,7 +146,7 @@ class SystemDictionaryShared: public SystemDictionary { }; private: - + class ExclusionCheckCandidates; static DumpTimeSharedClassTable* _dumptime_table; static ArchiveInfo _static_archive; @@ -175,14 +175,27 @@ private: static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin); static bool is_jfr_event_class(InstanceKlass *k); - static bool check_for_exclusion_impl(InstanceKlass* k); + static bool should_be_excluded_impl(InstanceKlass* k, DumpTimeClassInfo* info); + + // exclusion checks + static void check_exclusion_for_self_and_dependencies(InstanceKlass *k); + static bool check_self_exclusion(InstanceKlass* k); + static bool check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info); + static bool check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name); + static bool is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type); + static bool is_excluded_verification_constraint(InstanceKlass* k, Symbol* constraint_class_name); + static Klass* find_verification_constraint_bottom_class(InstanceKlass* k, Symbol* constraint_class_name); + static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN; static bool has_been_redefined(InstanceKlass* k); DEBUG_ONLY(static bool _class_loading_may_happen;) - static void copy_verification_constraints_from_preimage(InstanceKlass* klass); + static void copy_verification_info_from_preimage(InstanceKlass* klass); static void copy_linking_constraints_from_preimage(InstanceKlass* klass); + template + static void iterate_verification_constraint_names(InstanceKlass* k, DumpTimeClassInfo* info, Function func); + public: static bool is_early_klass(InstanceKlass* k); // Was k loaded while JvmtiExport::is_early_phase()==true static bool has_archived_enum_objs(InstanceKlass* ik); @@ -239,6 +252,7 @@ public: Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, bool* skip_assignability_check); + static void add_old_verification_constraint(Thread* current, InstanceKlass* k, Symbol* name); static void check_verification_constraints(InstanceKlass* klass, TRAPS) NOT_CDS_RETURN; static void add_enum_klass_static_field(InstanceKlass* ik, int root_index); @@ -258,7 +272,6 @@ public: static DumpTimeSharedClassTable* dumptime_table() { return _dumptime_table; } static bool should_be_excluded(Klass* k); - static bool check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info); static void validate_before_archiving(InstanceKlass* k); static bool is_excluded_class(InstanceKlass* k); static void set_excluded(InstanceKlass* k); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 1afc59d8da1..e0ebb92c7ae 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2839,18 +2839,20 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl DEBUG_ONLY(FieldInfoStream::validate_search_table(_constants, _fieldinfo_stream, _fieldinfo_search_table)); } -// Check if a class or any of its supertypes has a version older than 50. -// CDS will not perform verification of old classes during dump time because -// without changing the old verifier, the verification constraint cannot be -// retrieved during dump time. -// Verification of archived old classes will be performed during run time. bool InstanceKlass::can_be_verified_at_dumptime() const { if (AOTMetaspace::in_aot_cache(this)) { // This is a class that was dumped into the base archive, so we know // it was verified at dump time. return true; } - if (major_version() < 50 /*JAVA_6_VERSION*/) { + + if (CDSConfig::is_preserving_verification_constraints()) { + return true; + } + + if (CDSConfig::is_old_class_for_verifier(this)) { + // The old verifier does not save verification constraints, so at run time + // SystemDictionaryShared::check_verification_constraints() will not work for this class. return false; } if (super() != nullptr && !super()->can_be_verified_at_dumptime()) { diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 4c027e0839a..0463d8d9a81 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -323,9 +323,8 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md static bool is_excluded(Klass* k) { #if INCLUDE_CDS - if (SafepointSynchronize::is_at_safepoint() && - CDSConfig::is_dumping_archive() && - CDSConfig::current_thread_is_vm_or_dumper()) { + if (CDSConfig::is_at_aot_safepoint()) { + // Check for CDS exclusion only at CDS safe point. if (k->is_instance_klass() && !InstanceKlass::cast(k)->is_loaded()) { log_debug(aot, training)("Purged %s from MDO: unloaded class", k->name()->as_C_string()); return true; diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 845dc20c0d0..8f906ae3d37 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -554,7 +554,11 @@ void KlassTrainingData::cleanup(Visitor& visitor) { } visitor.visit(this); if (has_holder()) { - bool is_excluded = !holder()->is_loaded() || SystemDictionaryShared::check_for_exclusion(holder(), nullptr); + bool is_excluded = !holder()->is_loaded(); + if (CDSConfig::is_at_aot_safepoint()) { + // Check for AOT exclusion only at AOT safe point. + is_excluded |= SystemDictionaryShared::should_be_excluded(holder()); + } if (is_excluded) { ResourceMark rm; log_debug(aot, training)("Cleanup KTD %s", name()->as_klass_external_name()); @@ -573,7 +577,8 @@ void MethodTrainingData::cleanup(Visitor& visitor) { } visitor.visit(this); if (has_holder()) { - if (SystemDictionaryShared::check_for_exclusion(holder()->method_holder(), nullptr)) { + if (CDSConfig::is_at_aot_safepoint() && SystemDictionaryShared::should_be_excluded(holder()->method_holder())) { + // Check for AOT exclusion only at AOT safe point. log_debug(aot, training)("Cleanup MTD %s::%s", name()->as_klass_external_name(), signature()->as_utf8()); if (_final_profile != nullptr && _final_profile->method() != _holder) { log_warning(aot, training)("Stale MDO for %s::%s", name()->as_klass_external_name(), signature()->as_utf8()); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 99c8a56c727..0651c173e7b 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -850,6 +850,13 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, log_debug(class, resolve)("%s %s (verification)", from_name, to); } +#if INCLUDE_CDS + if (CDSConfig::is_preserving_verification_constraints() && from_class->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(from_class); + SystemDictionaryShared::add_old_verification_constraint(THREAD, ik, h_name); + } +#endif + return result; JVM_END diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 0c604205939..e0eafbc416b 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -303,11 +303,11 @@ void mutex_init() { #endif MUTEX_DEFN(DumpTimeTable_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(CDSLambda_lock , PaddedMutex , nosafepoint); - MUTEX_DEFN(DumpRegion_lock , PaddedMutex , nosafepoint); + MUTEX_DEFL(DumpRegion_lock , PaddedMutex , DumpTimeTable_lock); MUTEX_DEFN(ClassListFile_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(UnregisteredClassesTable_lock , PaddedMutex , nosafepoint-1); MUTEX_DEFN(LambdaFormInvokers_lock , PaddedMutex , safepoint); - MUTEX_DEFN(ScratchObjects_lock , PaddedMutex , nosafepoint-1); // Holds DumpTimeTable_lock + MUTEX_DEFL(ScratchObjects_lock , PaddedMutex , DumpTimeTable_lock); MUTEX_DEFN(FinalImageRecipes_lock , PaddedMutex , nosafepoint); #endif // INCLUDE_CDS MUTEX_DEFN(Bootclasspath_lock , PaddedMutex , nosafepoint); diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index eeb5110b077..3af6548fe33 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -526,6 +526,7 @@ hotspot_aot_classlinking = \ -runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java \ -runtime/cds/appcds/cacheObject/ArchivedModuleCompareTest.java \ -runtime/cds/appcds/CDSandJFR.java \ + -runtime/cds/appcds/LambdaContainsOldInf.java \ -runtime/cds/appcds/customLoader/CustomClassListDump.java \ -runtime/cds/appcds/customLoader/HelloCustom_JFR.java \ -runtime/cds/appcds/customLoader/OldClassAndInf.java \ @@ -533,14 +534,17 @@ hotspot_aot_classlinking = \ -runtime/cds/appcds/customLoader/ParallelTestSingleFP.java \ -runtime/cds/appcds/customLoader/SameNameInTwoLoadersTest.java \ -runtime/cds/appcds/DumpClassListWithLF.java \ - -runtime/cds/appcds/dynamicArchive/ModulePath.java \ + -runtime/cds/appcds/dynamicArchive/LambdaContainsOldInf.java \ -runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java \ -runtime/cds/appcds/dynamicArchive/LambdaForOldInfInBaseArchive.java \ -runtime/cds/appcds/dynamicArchive/LambdaInBaseArchive.java \ -runtime/cds/appcds/dynamicArchive/LambdasInTwoArchives.java \ + -runtime/cds/appcds/dynamicArchive/ModulePath.java \ + -runtime/cds/appcds/dynamicArchive/NestHostOldInf.java \ -runtime/cds/appcds/dynamicArchive/OldClassAndInf.java \ -runtime/cds/appcds/dynamicArchive/OldClassInBaseArchive.java \ -runtime/cds/appcds/dynamicArchive/OldClassVerifierTrouble.java \ + -runtime/cds/appcds/dynamicArchive/RedefineCallerClassTest.java \ -runtime/cds/appcds/HelloExtTest.java \ -runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \ -runtime/cds/appcds/javaldr/GCDuringDump.java \ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java index f50a2d1f905..9a9524eb2f1 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java @@ -99,7 +99,6 @@ public class ExcludedClasses { if (runMode == RunMode.ASSEMBLY) { out.shouldNotMatch("aot,resolve.*archived field.*TestApp.Foo => TestApp.Foo.ShouldBeExcluded.f:I"); } else if (runMode == RunMode.PRODUCTION) { - out.shouldContain("check_verification_constraint: TestApp$Foo$Taz: TestApp$Foo$ShouldBeExcludedChild must be subclass of TestApp$Foo$ShouldBeExcluded"); out.shouldContain("jdk.jfr.Event source: jrt:/jdk.jfr"); out.shouldMatch("TestApp[$]Foo[$]ShouldBeExcluded source: .*/app.jar"); out.shouldMatch("TestApp[$]Foo[$]ShouldBeExcludedChild source: .*/app.jar"); @@ -259,14 +258,9 @@ class TestApp { static class Taz { static ShouldBeExcluded m() { - // When verifying this method, we need to check the constraint that - // ShouldBeExcluded must be a supertype of ShouldBeExcludedChild. This information - // is checked by SystemDictionaryShared::check_verification_constraints() when the Taz - // class is linked during the production run. - // - // Because ShouldBeExcluded is excluded from the AOT archive, it must be loaded - // dynamically from app.jar inside SystemDictionaryShared::check_verification_constraints(). - // This must happen after the app class loader has been fully restored from the AOT cache. + // Taz should be excluded from the AOT cache because it has a verification constraint that + // "ShouldBeExcludedChild must be a subtype of ShouldBeExcluded", but ShouldBeExcluded is + // excluded from the AOT cache. return new ShouldBeExcludedChild(); } static void hotSpot4() { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm new file mode 100644 index 00000000000..e0362eb0649 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class OldA + version 49:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java new file mode 100644 index 00000000000..42161b469bf --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 Store old classes linked state in AOT cache as long as their verification constraints are not excluded. + * @bug 8317269 + * @requires vm.cds.supports.aot.class.linking + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build OldClass OldA OldClassWithVerifierConstraints OldClassWithExcludedVerifierConstraints + * @build OldClassSupport + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * AppUsesOldClass MyIntf OldClass OldA NewB MyEvent MyEvent2 + * OldClassWithVerifierConstraints + * OldClassWithExcludedVerifierConstraints + * NewClassWithExcludedVerifierConstraints + * @run driver OldClassSupport + */ + +import jdk.jfr.Event; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class OldClassSupport { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "AppUsesOldClass"; + + public static void main(String[] args) throws Exception { + Tester tester = new Tester(); + tester.run(new String[] {"AOT", "--two-step-training"} ); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + return new String[] { + "-Xlog:aot+class=debug", + "-Xlog:aot+resolve=trace", + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] {"-Xlog:cds+class=debug", mainClass}; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) { + Class[] included = { + OldClass.class, + OldA.class, + NewB.class, + OldClassWithVerifierConstraints.class, + }; + + Class[] excluded = { + OldClassWithExcludedVerifierConstraints.class, + NewClassWithExcludedVerifierConstraints.class, + }; + + + if (runMode == RunMode.TRAINING) { + shouldInclude(out, false, included); + shouldNotInclude(out, excluded); + shouldSkip(out, excluded); + } else if (runMode == RunMode.ASSEMBLY) { + shouldInclude(out, true, included); + shouldNotInclude(out, excluded); + } + } + } + + static void shouldInclude(OutputAnalyzer out, boolean linked, Class[] classes) { + for (Class c : classes) { + out.shouldMatch("aot,class.* = 0x.* app *" + c.getName() + (linked ? " .*aot-linked" : "")); + } + } + + static void shouldNotInclude(OutputAnalyzer out, Class[] classes) { + for (Class c : classes) { + out.shouldNotMatch("aot,class.* = 0x.* app *" + c.getName()); + } + } + + static void shouldSkip(OutputAnalyzer out, Class[] classes) { + for (Class c : classes) { + out.shouldMatch("Skipping " + c.getName() + ": verification constraint .* is excluded"); + } + } +} + +class AppUsesOldClass { + public static void main(String args[]) { + System.out.println("Old Class Instance: " + new OldClass()); + + System.out.println(get_OldA_from_NewB()); + System.out.println(OldClassWithVerifierConstraints.get_OldA_from_NewB()); + System.out.println(OldClassWithExcludedVerifierConstraints.get_Event_from_MyEvent()); + System.out.println(NewClassWithExcludedVerifierConstraints.get_MyEvent_from_MyEvent2()); + System.out.println(new MyEvent()); + + // OldClassWithExcludedVerifierConstraints should still be excluded even it has been used + // in a lambda expression during the training run. + run((OldClassWithExcludedVerifierConstraints x) -> { + System.out.println(x); + }); + } + + static OldA get_OldA_from_NewB() { + return new NewB(); + } + + static void run(MyIntf intf) { + intf.function(new OldClassWithExcludedVerifierConstraints()); + } +} + +interface MyIntf { + public void function(OldClassWithExcludedVerifierConstraints x); +} + +class NewB extends OldA {} + +class MyEvent extends Event {} +class MyEvent2 extends MyEvent {} + +class NewClassWithExcludedVerifierConstraints { + static MyEvent get_MyEvent_from_MyEvent2() { + return new MyEvent2(); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm new file mode 100644 index 00000000000..0c0556bf122 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This old class has a verification constraint that "MyEvent must be a subtype of Event". However, +// Event and all of its subtypes are excluded from the AOT cache, so this class must also be excluded. + +super public class OldClassWithExcludedVerifierConstraints + version 49:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +static Method get_Event_from_MyEvent:"()Ljdk/jfr/Event;" + stack 2 locals 0 +{ + new class MyEvent; + dup; + invokespecial Method MyEvent."":"()V"; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm new file mode 100644 index 00000000000..946c51050a3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This old class as a verification constraint that "NewB must be a subtype of OldA". Since both +// OldA and NewB are not excluded, then this class should be cached in aot-linked state. + +super public class OldClassWithVerifierConstraints + version 49:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +static Method get_OldA_from_NewB:"()LOldA;" + stack 2 locals 0 +{ + new class NewB; + dup; + invokespecial Method NewB."":"()V"; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java new file mode 100644 index 00000000000..050f7d28585 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8317269 + * @requires vm.cds + * @requires vm.cds.supports.aot.class.linking + * @summary Test for verification of classes that are aot-linked + * @library /test/jdk/lib/testlibrary + * /test/lib + * /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build GoodOldClass + * BadOldClass BadOldClass2 BadOldClass3 BadOldClass4 + * BadNewClass BadNewClass2 BadNewClass3 BadNewClass4 + * @build AOTClassLinkingVerification + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app1.jar + * AOTClassLinkingVerificationApp + * Unlinked UnlinkedSuper + * BadOldClass + * BadOldClass2 + * BadOldClass3 + * BadOldClass4 + * BadNewClass + * BadNewClass2 + * BadNewClass3 + * BadNewClass4 + * GoodOldClass Vehicle Car + * Util + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app2.jar + * Foo NotFoo + * UnlinkedSub + * @run driver AOTClassLinkingVerification + */ + +import java.io.File; +import java.lang.invoke.MethodHandles; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.whitebox.WhiteBox; + +public class AOTClassLinkingVerification { + static final String app1Jar = ClassFileInstaller.getJarPath("app1.jar"); + static final String app2Jar = ClassFileInstaller.getJarPath("app2.jar"); + static final String wbJar = TestCommon.getTestJar("WhiteBox.jar"); + static final String bootAppendWhiteBox = "-Xbootclasspath/a:" + wbJar; + static final String mainClass = AOTClassLinkingVerificationApp.class.getName(); + + static class Tester extends CDSAppTester { + public Tester(String testName) { + super(testName); + } + + @Override + public String[] vmArgs(RunMode runMode) { + if (runMode == RunMode.TRAINING || + runMode == RunMode.ASSEMBLY) { + return new String[] { + "-XX:+AOTClassLinking", "-Xlog:cds+class=debug", bootAppendWhiteBox, + }; + } else { + return new String[] { + "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", bootAppendWhiteBox, + }; + } + } + + @Override + public String classpath(RunMode runMode) { + if (runMode == RunMode.TRAINING || + runMode == RunMode.ASSEMBLY) { + return app1Jar; + } else { + return app1Jar + File.pathSeparator + app2Jar; + } + } + + @Override + public String[] appCommandLine(RunMode runMode) { + if (runMode == RunMode.TRAINING || + runMode == RunMode.ASSEMBLY) { + return new String[] { + "AOTClassLinkingVerificationApp", app1Jar, "ASSEMBLY" + }; + } else { + return new String[] { + "AOTClassLinkingVerificationApp", app1Jar, "PRODUCTION" + }; + } + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.TRAINING) { + out.shouldContain("Preload Warning: Verification failed for BadNewClass"); + out.shouldContain("Preload Warning: Verification failed for BadNewClass2"); + out.shouldContain("Preload Warning: Verification failed for BadNewClass3"); + out.shouldContain("Preload Warning: Verification failed for BadNewClass4"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass2"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass3"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass4"); + out.shouldContain("Preload Warning: Verification failed for Unlinked"); + } + } + } + + public static void main(String[] args) throws Exception { + // Dump without app2.jar so: + // - Unlinked can be resolved, but UnlinkedSuper UnlinkedSub cannot be resolved, + // so Unlinked cannot be verified at dump time. + // - BadOldClass2 can be resolved, but Foo and NotFoo cannot be resolved, + // so BadOldClass2 cannot be verified at dump time. + // - BadNewClass2 can be resolved, but Foo and NotFoo cannot be resolved, + // so BadNewClass2 cannot be verified at dump time. + Tester t1 = new Tester("verification-aot-linked-classes"); + t1.run("AOT"); + } +} + +class AOTClassLinkingVerificationApp { + static WhiteBox wb = WhiteBox.getWhiteBox(); + static ClassLoader classLoader = AOTClassLinkingVerificationApp.class.getClassLoader(); + static File app1Jar; + static boolean isProduction; + public static void main(String[] args) throws Exception { + app1Jar = new File(args[0]); + isProduction = args[1].equals("PRODUCTION"); + if (isProduction) { + assertNotShared(UnlinkedSub.class); + assertShared(UnlinkedSuper.class); + assertNotShared(Unlinked.class); // failed verification during dump time + assertNotShared(Foo.class); + assertNotShared(NotFoo.class); + } + String s = null; + try { + s = Unlinked.doit(); + } catch (NoClassDefFoundError ncdfe) { + // UnlinkedSub is in app2Jar but only app1Jar is used during training + // and assembly phases. So NoClassDefFoundError is expected during + // during training and assembly phases. + if (isProduction) { + throw ncdfe; + } + } + if (isProduction && !s.equals("heyhey")) { + throw new RuntimeException("Unlinked.doit() returns wrong result: " + s); + } + + // =============================================================================== + + checkSimpleBadClass("BadOldClass"); + + Class cls_BadOldClass2 = Class.forName("BadOldClass2", false, classLoader); + if (isProduction) { + assertNotShared(cls_BadOldClass2); // failed verification during dump time + } + try { + cls_BadOldClass2.newInstance(); + throw new RuntimeException("BadOldClass2 cannot be verified"); + } catch (NoClassDefFoundError ncdfe) { + // BadOldClass2 loads Foo and NotFoo which is in app2Jar which is used + // only in production run. + if (isProduction) { + throw ncdfe; + } + } catch (VerifyError expected) {} + + checkSimpleBadClass("BadOldClass3"); + checkSimpleBadClass("BadOldClass4"); + + // =============================================================================== + + checkSimpleBadClass("BadNewClass"); + + Class cls_BadNewClass2 = Class.forName("BadNewClass2", false, classLoader); + if (isProduction) { + assertNotShared(cls_BadNewClass2); // failed verification during dump time + } + try { + cls_BadNewClass2.newInstance(); + throw new RuntimeException("BadNewClass2 cannot be verified"); + } catch (NoClassDefFoundError ncdfe) { + // BadNewClass2 loads Foo and NotFoo which is in app2Jar which is used + // only in production run. + if (isProduction) { + throw ncdfe; + } + } catch (VerifyError expected) {} + + checkSimpleBadClass("BadNewClass3"); + checkSimpleBadClass("BadNewClass4"); + + // =============================================================================== + + if (isProduction) { + assertAlreadyLoaded("Vehicle"); + assertAlreadyLoaded("Car"); + assertAlreadyLoaded("GoodOldClass"); + + assertShared(GoodOldClass.class); + assertShared(Vehicle.class); + assertShared(Car.class); + } + + GoodOldClass.doit(); // Should not fail + } + + static void checkSimpleBadClass(String className) throws Exception { + Class cls = Class.forName(className, false, classLoader); + if (isProduction) { + assertNotShared(cls); // failed verification during dump time + } + try { + cls.newInstance(); + throw new RuntimeException(className + " should not pass verification"); + } catch (VerifyError expected) {} + } + + static void assertShared(Class c) { + if (!wb.isSharedClass(c)) { + throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be true"); + } + } + + static void assertNotShared(Class c) { + if (wb.isSharedClass(c)) { + throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be false"); + } + } + + static void assertAlreadyLoaded(String className) throws Exception { + byte[] data = Util.getClassFileFromJar(app1Jar, className); + try { + MethodHandles.lookup().defineClass(data); + } catch (LinkageError e) { + if (e.getMessage().contains("duplicate class definition for " + className)) { + return; + } else { + throw e; + } + } + throw new RuntimeException(className + " must have already been loaded"); + } +} + + +class Unlinked { + static String doit() { + UnlinkedSuper sup = new UnlinkedSub(); + return sup.doit(); + } +} + +abstract class UnlinkedSuper { + abstract String doit(); +} + +class UnlinkedSub extends UnlinkedSuper { + String doit() { + return "heyhey"; + } +} + +class Foo {} +class NotFoo {} + +class Vehicle {} +class Car extends Vehicle {} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm new file mode 100644 index 00000000000..cf71d209819 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadNewClass + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return an Object as a String. + * Verifier should fail. + */ +public Method doit:"()Ljava/lang/String;" + stack 2 locals 1 +{ + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_0; + aload_0; + areturn; // tries to return an Object as a String +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm new file mode 100644 index 00000000000..c243d583484 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadNewClass2 + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a NotFoo as a Foo. + * Verifier should fail. + */ +public Method doit:"()LFoo;" + stack 2 locals 1 +{ + new class NotFoo; + dup; + invokespecial Method NotFoo."":"()V"; + astore_0; + aload_0; + areturn; // tries to return a NotFoo as a Foo +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm new file mode 100644 index 00000000000..afce8f76ed8 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadNewClass3 + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[]. + * Verifier should fail. + * + * Note: the arrays must have different number of dimensions, or else + * the new verifier will just check the "bottom" classes. I.e., String and Integer + */ +public Method doit:"()[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm new file mode 100644 index 00000000000..afebe3f1f8e --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadNewClass4 + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[][]. + * Verifier should fail. + * + * Note: the new verifier looks up the Integer and String types, + * not the array types. + */ +public Method doit:"()[[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm new file mode 100644 index 00000000000..adc6a50d4ba --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadOldClass + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return an Object as a String. + * Verifier should fail. + */ +public Method doit:"()Ljava/lang/String;" + stack 2 locals 1 +{ + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_0; + aload_0; + areturn; // tries to return an Object as a String +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm new file mode 100644 index 00000000000..1808a019ace --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadOldClass2 + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a NotFoo as a Foo. + * Verifier should fail. + */ +public Method doit:"()LFoo;" + stack 2 locals 1 +{ + new class NotFoo; + dup; + invokespecial Method NotFoo."":"()V"; + astore_0; + aload_0; + areturn; // tries to return a NotFoo as a Foo +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm new file mode 100644 index 00000000000..6e943cf5afc --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadOldClass3 + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[]. + * Verifier should fail. + * + * Note: the arrays have different number of dimensions. The old verifier + * rejects this immediately without looking up the String/Integer types. + */ +public Method doit:"()[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm new file mode 100644 index 00000000000..56f2a8d299a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class BadOldClass4 + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[][]. + * Verifier should fail. + * + * Note: the old verifier looks up the Integer and String types, + * not the array types. + */ +public Method doit:"()[[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java index 0f7707edae3..e1f5f548593 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java @@ -147,7 +147,7 @@ public class BulkLoaderTest { @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { if (isAOTWorkflow() && runMode == RunMode.TRAINING) { - out.shouldContain("Skipping BadOldClassA: Unlinked class not supported by AOTConfiguration"); + out.shouldContain("Skipping BadOldClassA: Failed verification"); out.shouldContain("Skipping SimpleCusty: Duplicated unregistered class"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm new file mode 100644 index 00000000000..92a79380d93 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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. + * + */ + +super public class GoodOldClass + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + +public static Method doit:"()LVehicle;" + stack 2 locals 1 +{ + new class Car; + dup; + invokespecial Method Car."":"()V"; + astore_0; + aload_0; + areturn; // tries to return a Car as a Vehicle +} + +} From 85996572b61e789d7e45bd26b23d233a0a41e158 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 10 Sep 2025 21:23:45 +0000 Subject: [PATCH 229/295] 8365676: javac incorrectly allows calling interface static method via type variable Co-authored-by: Maurizio Cimadamore Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 16 ++++++++++++--- .../generics/typevars/8365676/T8365676.java | 20 +++++++++++++++++++ .../generics/typevars/8365676/T8365676.out | 4 ++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/generics/typevars/8365676/T8365676.java create mode 100644 test/langtools/tools/javac/generics/typevars/8365676/T8365676.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 9f32e7f6186..f780df025bd 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 @@ -4569,9 +4569,19 @@ public class Attr extends JCTree.Visitor { log.error(pos, Errors.TypeVarCantBeDeref); return syms.errSymbol; } else { - Symbol sym2 = (sym.flags() & Flags.PRIVATE) != 0 ? - rs.new AccessError(env, site, sym) : - sym; + // JLS 4.9 specifies the members are derived by inheritance. + // We skip inducing a whole class by filtering members that + // can never be inherited: + Symbol sym2; + if (sym.isPrivate()) { + // Private members + sym2 = rs.new AccessError(env, site, sym); + } else if (sym.owner.isInterface() && sym.kind == MTH && (sym.flags() & STATIC) != 0) { + // Interface static methods + sym2 = rs.new SymbolNotFoundError(ABSENT_MTH); + } else { + sym2 = sym; + } rs.accessBase(sym2, pos, location, site, name, true); return sym; } diff --git a/test/langtools/tools/javac/generics/typevars/8365676/T8365676.java b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.java new file mode 100644 index 00000000000..f6b992cb47b --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.java @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8365676 + * @summary Interface static methods should not be inherited by type variables + * @compile/fail/ref=T8365676.out -XDrawDiagnostics T8365676.java + */ + +import java.text.Collator; +import java.util.Comparator; + +class T8365676 { + // T and P should have equivalent members + , P extends Object & Comparator> + void test() { + Comparator.reverseOrder(); + Collator.reverseOrder(); // Fails + P.reverseOrder(); // Fails + T.reverseOrder(); // Should fail + } +} diff --git a/test/langtools/tools/javac/generics/typevars/8365676/T8365676.out b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.out new file mode 100644 index 00000000000..214b1640d4a --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.out @@ -0,0 +1,4 @@ +T8365676.java:16:17: compiler.err.cant.resolve.location.args: kindname.method, reverseOrder, , , (compiler.misc.location: kindname.class, java.text.Collator, null) +T8365676.java:17:10: compiler.err.cant.resolve.location.args: kindname.method, reverseOrder, , , (compiler.misc.location: kindname.type.variable.bound, java.lang.Object&java.util.Comparator, null) +T8365676.java:18:10: compiler.err.cant.resolve.location.args: kindname.method, reverseOrder, , , (compiler.misc.location: kindname.type.variable.bound, T, null) +3 errors From 7fcce27096605a27ca3b74349d1012bb0bd5963d Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 10 Sep 2025 22:12:04 +0000 Subject: [PATCH 230/295] 8365956: GenShen: Adaptive tenuring threshold algorithm may raise threshold prematurely Reviewed-by: kdnilsen, phh --- .../shenandoahGenerationalHeuristics.cpp | 16 +- .../heuristics/shenandoahGlobalHeuristics.cpp | 7 +- .../heuristics/shenandoahYoungHeuristics.cpp | 34 ++-- .../gc/shenandoah/shenandoahAgeCensus.cpp | 96 +++++++---- .../gc/shenandoah/shenandoahAgeCensus.hpp | 30 +++- .../gc/shenandoah/shenandoahCollectionSet.cpp | 3 +- .../gc/shenandoah/shenandoahGeneration.cpp | 8 +- .../shenandoahGenerationalEvacuationTask.cpp | 12 +- .../shenandoahGenerationalEvacuationTask.hpp | 1 - .../shenandoahGenerationalFullGC.cpp | 5 +- .../shenandoahGenerationalFullGC.hpp | 1 - .../shenandoah/shenandoahGenerationalHeap.cpp | 2 +- .../shenandoah/shenandoahGenerationalHeap.hpp | 1 + .../shenandoahGenerationalHeap.inline.hpp | 37 ++++ .../shenandoah/test_shenandoahAgeCensus.cpp | 159 ++++++++++++++++++ 15 files changed, 318 insertions(+), 94 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp create mode 100644 test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 08fd4599346..dfae9040242 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -28,7 +28,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahEvacInfo.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahTrace.hpp" @@ -65,8 +65,6 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio size_t free = 0; size_t free_regions = 0; - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); - // This counts number of humongous regions that we intend to promote in this cycle. size_t humongous_regions_promoted = 0; // This counts number of regular regions that will be promoted in place. @@ -98,12 +96,12 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio bool is_candidate; // This is our candidate for later consideration. if (collection_set->is_preselected(i)) { - assert(region->age() >= tenuring_threshold, "Preselection filter"); + assert(heap->is_tenurable(region), "Preselection filter"); is_candidate = true; preselected_candidates++; // Set garbage value to maximum value to force this into the sorted collection set. garbage = region_size_bytes; - } else if (region->is_young() && (region->age() >= tenuring_threshold)) { + } else if (region->is_young() && heap->is_tenurable(region)) { // Note that for GLOBAL GC, region may be OLD, and OLD regions do not qualify for pre-selection // This region is old enough to be promoted but it was not preselected, either because its garbage is below @@ -142,7 +140,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio immediate_regions++; immediate_garbage += garbage; } else { - if (region->is_young() && region->age() >= tenuring_threshold) { + if (region->is_young() && heap->is_tenurable(region)) { oop obj = cast_to_oop(region->bottom()); size_t humongous_regions = ShenandoahHeapRegion::required_regions(obj->size() * HeapWordSize); humongous_regions_promoted += humongous_regions; @@ -246,10 +244,6 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio size_t ShenandoahGenerationalHeuristics::add_preselected_regions_to_collection_set(ShenandoahCollectionSet* cset, const RegionData* data, size_t size) const { -#ifdef ASSERT - const uint tenuring_threshold = ShenandoahGenerationalHeap::heap()->age_census()->tenuring_threshold(); -#endif - // cur_young_garbage represents the amount of memory to be reclaimed from young-gen. In the case that live objects // are known to be promoted out of young-gen, we count this as cur_young_garbage because this memory is reclaimed // from young-gen and becomes available to serve future young-gen allocation requests. @@ -257,7 +251,7 @@ size_t ShenandoahGenerationalHeuristics::add_preselected_regions_to_collection_s for (size_t idx = 0; idx < size; idx++) { ShenandoahHeapRegion* r = data[idx].get_region(); if (cset->is_preselected(r->index())) { - assert(r->age() >= tenuring_threshold, "Preselected regions must have tenure age"); + assert(ShenandoahGenerationalHeap::heap()->is_tenurable(r), "Preselected regions must have tenure age"); // Entire region will be promoted, This region does not impact young-gen or old-gen evacuation reserve. // This region has been pre-selected and its impact on promotion reserve is already accounted for. diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index 4e12b1d41e8..331bd040575 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -25,7 +25,7 @@ #include "gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahGlobalGeneration.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "utilities/quickSort.hpp" @@ -56,7 +56,6 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti size_t capacity = heap->soft_max_capacity(); size_t garbage_threshold = region_size_bytes * ShenandoahGarbageThreshold / 100; size_t ignore_threshold = region_size_bytes * ShenandoahIgnoreGarbageThreshold / 100; - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); size_t young_evac_reserve = heap->young_generation()->get_evacuation_reserve(); size_t old_evac_reserve = heap->old_generation()->get_evacuation_reserve(); @@ -100,7 +99,7 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti ShenandoahHeapRegion* r = data[idx].get_region(); assert(!cset->is_preselected(r->index()), "There should be no preselected regions during GLOBAL GC"); bool add_region = false; - if (r->is_old() || (r->age() >= tenuring_threshold)) { + if (r->is_old() || heap->is_tenurable(r)) { size_t new_cset = old_cur_cset + r->get_live_data_bytes(); if ((r->garbage() > garbage_threshold)) { while ((new_cset > max_old_cset) && (unaffiliated_young_regions > 0)) { @@ -114,7 +113,7 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti old_cur_cset = new_cset; } } else { - assert(r->is_young() && (r->age() < tenuring_threshold), "DeMorgan's law (assuming r->is_affiliated)"); + assert(r->is_young() && !heap->is_tenurable(r), "DeMorgan's law (assuming r->is_affiliated)"); size_t new_cset = young_cur_cset + r->get_live_data_bytes(); size_t region_garbage = r->garbage(); size_t new_garbage = cur_young_garbage + region_garbage; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index fbb165858dc..d236be8c9e6 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -26,7 +26,7 @@ #include "gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" @@ -64,19 +64,18 @@ void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollection size_t size, size_t actual_free, size_t cur_young_garbage) const { - auto heap = ShenandoahGenerationalHeap::heap(); + const auto heap = ShenandoahGenerationalHeap::heap(); - size_t capacity = heap->soft_max_capacity(); - size_t garbage_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; - size_t ignore_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahIgnoreGarbageThreshold / 100; - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); + const size_t capacity = heap->soft_max_capacity(); + const size_t garbage_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; + const size_t ignore_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahIgnoreGarbageThreshold / 100; // This is young-gen collection or a mixed evacuation. // If this is mixed evacuation, the old-gen candidate regions have already been added. - size_t max_cset = (size_t) (heap->young_generation()->get_evacuation_reserve() / ShenandoahEvacWaste); size_t cur_cset = 0; - size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_cset; - size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0; + const size_t max_cset = (size_t) (heap->young_generation()->get_evacuation_reserve() / ShenandoahEvacWaste); + const size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_cset; + const size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0; log_info(gc, ergo)( @@ -89,11 +88,15 @@ void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollection if (cset->is_preselected(r->index())) { continue; } - if (r->age() < tenuring_threshold) { - size_t new_cset = cur_cset + r->get_live_data_bytes(); - size_t region_garbage = r->garbage(); - size_t new_garbage = cur_young_garbage + region_garbage; - bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage); + + // Note that we do not add tenurable regions if they were not pre-selected. They were not preselected + // because there is insufficient room in old-gen to hold their to-be-promoted live objects or because + // they are to be promoted in place. + if (!heap->is_tenurable(r)) { + const size_t new_cset = cur_cset + r->get_live_data_bytes(); + const size_t region_garbage = r->garbage(); + const size_t new_garbage = cur_young_garbage + region_garbage; + const bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage); assert(r->is_young(), "Only young candidates expected in the data array"); if ((new_cset <= max_cset) && (add_regardless || (region_garbage > garbage_threshold))) { cur_cset = new_cset; @@ -101,9 +104,6 @@ void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollection cset->add_region(r); } } - // Note that we do not add aged regions if they were not pre-selected. The reason they were not preselected - // is because there is not sufficient room in old-gen to hold their to-be-promoted live objects or because - // they are to be promoted in place. } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index 94c98b78f1b..bd66f55bd8f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -27,8 +27,15 @@ #include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -ShenandoahAgeCensus::ShenandoahAgeCensus() { +ShenandoahAgeCensus::ShenandoahAgeCensus() + : ShenandoahAgeCensus(ShenandoahHeap::heap()->max_workers()) +{ assert(ShenandoahHeap::heap()->mode()->is_generational(), "Only in generational mode"); +} + +ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) + : _max_workers(max_workers) +{ if (ShenandoahGenerationalMinTenuringAge > ShenandoahGenerationalMaxTenuringAge) { vm_exit_during_initialization( err_msg("ShenandoahGenerationalMinTenuringAge=%zu" @@ -39,6 +46,9 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() { _global_age_table = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC); CENSUS_NOISE(_global_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, MAX_SNAPSHOTS, mtGC);) _tenuring_threshold = NEW_C_HEAP_ARRAY(uint, MAX_SNAPSHOTS, mtGC); + CENSUS_NOISE(_skipped = 0); + NOT_PRODUCT(_counted = 0); + NOT_PRODUCT(_total = 0); for (int i = 0; i < MAX_SNAPSHOTS; i++) { // Note that we don't now get perfdata from age_table @@ -48,10 +58,9 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() { _tenuring_threshold[i] = MAX_COHORTS; } if (ShenandoahGenerationalAdaptiveTenuring && !ShenandoahGenerationalCensusAtEvac) { - size_t max_workers = ShenandoahHeap::heap()->max_workers(); - _local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, max_workers, mtGC); + _local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);) - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { _local_age_table[i] = new AgeTable(false); CENSUS_NOISE(_local_noise[i].clear();) } @@ -61,6 +70,22 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() { _epoch = MAX_SNAPSHOTS - 1; // see update_epoch() } +ShenandoahAgeCensus::~ShenandoahAgeCensus() { + for (uint i = 0; i < MAX_SNAPSHOTS; i++) { + delete _global_age_table[i]; + } + FREE_C_HEAP_ARRAY(AgeTable*, _global_age_table); + FREE_C_HEAP_ARRAY(uint, _tenuring_threshold); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise)); + if (_local_age_table) { + for (uint i = 0; i < _max_workers; i++) { + delete _local_age_table[i]; + } + FREE_C_HEAP_ARRAY(AgeTable*, _local_age_table); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise)); + } +} + CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id) {) NO_CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, size_t size, uint worker_id) {) if (obj_age <= markWord::max_age) { @@ -131,12 +156,11 @@ void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable assert(pv1 == nullptr && pv2 == nullptr, "Error, check caller"); // Seed cohort 0 with population that may have been missed during // regular census. - _global_age_table[_epoch]->add((uint)0, age0_pop); + _global_age_table[_epoch]->add(0u, age0_pop); - size_t max_workers = ShenandoahHeap::heap()->max_workers(); // Merge data from local age tables into the global age table for the epoch, // clearing the local tables. - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { // age stats _global_age_table[_epoch]->merge(_local_age_table[i]); _local_age_table[i]->clear(); // clear for next census @@ -177,8 +201,7 @@ void ShenandoahAgeCensus::reset_local() { assert(_local_age_table == nullptr, "Error"); return; } - size_t max_workers = ShenandoahHeap::heap()->max_workers(); - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { _local_age_table[i]->clear(); CENSUS_NOISE(_local_noise[i].clear();) } @@ -204,8 +227,7 @@ bool ShenandoahAgeCensus::is_clear_local() { assert(_local_age_table == nullptr, "Error"); return true; } - size_t max_workers = ShenandoahHeap::heap()->max_workers(); - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { bool clear = _local_age_table[i]->is_clear(); CENSUS_NOISE(clear |= _local_noise[i].is_clear();) if (!clear) { @@ -246,7 +268,7 @@ void ShenandoahAgeCensus::update_tenuring_threshold() { _tenuring_threshold[_epoch] = tt; } print(); - log_trace(gc, age)("New tenuring threshold %zu (min %zu, max %zu)", + log_info(gc, age)("New tenuring threshold %zu (min %zu, max %zu)", (uintx) _tenuring_threshold[_epoch], ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge); } @@ -279,13 +301,14 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() { uint upper_bound = ShenandoahGenerationalMaxTenuringAge; const uint prev_tt = previous_tenuring_threshold(); if (ShenandoahGenerationalCensusIgnoreOlderCohorts && prev_tt > 0) { - // We stay below the computed tenuring threshold for the last cycle plus 1, - // ignoring the mortality rates of any older cohorts. - upper_bound = MIN2(upper_bound, prev_tt + 1); + // We stay below the computed tenuring threshold for the last cycle, + // ignoring the mortality rates of any older cohorts (which may see + // higher mortality rates due to promotions). + upper_bound = MIN2(upper_bound, prev_tt); } upper_bound = MIN2(upper_bound, markWord::max_age); - const uint lower_bound = MAX2((uint)ShenandoahGenerationalMinTenuringAge, (uint)1); + const uint lower_bound = MAX2((uint)ShenandoahGenerationalMinTenuringAge, 1u); uint tenuring_threshold = upper_bound; for (uint i = upper_bound; i >= lower_bound; i--) { @@ -303,9 +326,9 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() { // cohorts are considered eligible for tenuring when all older // cohorts are. We return the next higher age as the tenuring threshold // so that we do not prematurely promote objects of this age. - assert(tenuring_threshold == i+1 || tenuring_threshold == upper_bound, "Error"); + assert(tenuring_threshold == i + 1 || tenuring_threshold == upper_bound, "Error"); assert(tenuring_threshold >= lower_bound && tenuring_threshold <= upper_bound, "Error"); - return tenuring_threshold; + return i + 1; } // Remember that we passed over this cohort, looking for younger cohorts // showing high mortality. We want to tenure cohorts of this age. @@ -335,6 +358,14 @@ double ShenandoahAgeCensus::mortality_rate(size_t prev_pop, size_t cur_pop) { } void ShenandoahAgeCensus::print() { + + const LogTarget(Debug, gc, age) lt; + if (!lt.is_enabled()) { + return; + } + + LogStream ls(lt); + // Print the population vector for the current epoch, and // for the previous epoch, as well as the computed mortality // ratio for each extant cohort. @@ -350,33 +381,32 @@ void ShenandoahAgeCensus::print() { for (uint i = 1; i < MAX_COHORTS; i++) { const size_t prev_pop = prev_pv->sizes[i-1]; // (i-1) OK because i >= 1 const size_t cur_pop = cur_pv->sizes[i]; - double mr = mortality_rate(prev_pop, cur_pop); + const double mr = mortality_rate(prev_pop, cur_pop); // Suppress printing when everything is zero if (prev_pop + cur_pop > 0) { - log_info(gc, age) - (" - age %3u: prev %10zu bytes, curr %10zu bytes, mortality %.2f ", - i, prev_pop*oopSize, cur_pop*oopSize, mr); + ls.print_cr(" - age %3u: prev %10zu bytes, curr %10zu bytes, mortality %.2f ", + i, prev_pop * oopSize, cur_pop * oopSize, mr); } total += cur_pop; if (i == tt) { // Underline the cohort for tenuring threshold (if < MAX_COHORTS) - log_info(gc, age)("----------------------------------------------------------------------------"); + ls.print_cr("----------------------------------------------------------------------------"); } } - CENSUS_NOISE(_global_noise[cur_epoch].print(total);) + CENSUS_NOISE(_global_noise[cur_epoch].print(ls, total);) } #ifdef SHENANDOAH_CENSUS_NOISE -void ShenandoahNoiseStats::print(size_t total) { +void ShenandoahNoiseStats::print(LogStream& ls, const size_t total) { if (total > 0) { - float f_skipped = (float)skipped/(float)total; - float f_aged = (float)aged/(float)total; - float f_clamped = (float)clamped/(float)total; - float f_young = (float)young/(float)total; - log_info(gc, age)("Skipped: %10zu (%.2f), R-Aged: %10zu (%.2f), " - "Clamped: %10zu (%.2f), R-Young: %10zu (%.2f)", - skipped*oopSize, f_skipped, aged*oopSize, f_aged, - clamped*oopSize, f_clamped, young*oopSize, f_young); + const float f_skipped = (float)skipped/(float)total; + const float f_aged = (float)aged/(float)total; + const float f_clamped = (float)clamped/(float)total; + const float f_young = (float)young/(float)total; + ls.print_cr("Skipped: %10zu (%.2f), R-Aged: %10zu (%.2f), " + "Clamped: %10zu (%.2f), R-Young: %10zu (%.2f)", + skipped*oopSize, f_skipped, aged*oopSize, f_aged, + clamped*oopSize, f_clamped, young*oopSize, f_young); } } #endif // SHENANDOAH_CENSUS_NOISE diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 89c68f7120b..90d188e1fca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -37,6 +37,8 @@ #define CENSUS_NOISE(x) x #define NO_CENSUS_NOISE(x) +class LogStream; + struct ShenandoahNoiseStats { size_t skipped; // Volume of objects skipped size_t aged; // Volume of objects from aged regions @@ -67,7 +69,7 @@ struct ShenandoahNoiseStats { young += other.young; } - void print(size_t total); + void print(LogStream& ls, size_t total); }; #else // SHENANDOAH_CENSUS_NOISE #define CENSUS_NOISE(x) @@ -91,7 +93,7 @@ struct ShenandoahNoiseStats { // // In addition, this class also maintains per worker population vectors into which // census for the current minor GC is accumulated (during marking or, optionally, during -// evacuation). These are cleared after each marking (resectively, evacuation) cycle, +// evacuation). These are cleared after each marking (respectively, evacuation) cycle, // once the per-worker data is consolidated into the appropriate population vector // per minor collection. The _local_age_table is thus C x N, for N GC workers. class ShenandoahAgeCensus: public CHeapObj { @@ -111,10 +113,12 @@ class ShenandoahAgeCensus: public CHeapObj { size_t _total; // net size of objects encountered (counted or skipped) in census #endif - uint _epoch; // Current epoch (modulo max age) - uint *_tenuring_threshold; // An array of the last N tenuring threshold values we + uint _epoch; // Current epoch (modulo max age) + uint* _tenuring_threshold; // An array of the last N tenuring threshold values we // computed. + uint _max_workers; // Maximum number of workers for parallel tasks + // Mortality rate of a cohort, given its population in // previous and current epochs double mortality_rate(size_t prev_pop, size_t cur_pop); @@ -165,11 +169,22 @@ class ShenandoahAgeCensus: public CHeapObj { }; ShenandoahAgeCensus(); + ShenandoahAgeCensus(uint max_workers); + ~ShenandoahAgeCensus(); // Return the local age table (population vector) for worker_id. // Only used in the case of (ShenandoahGenerationalAdaptiveTenuring && !ShenandoahGenerationalCensusAtEvac) - AgeTable* get_local_age_table(uint worker_id) { - return (AgeTable*) _local_age_table[worker_id]; + AgeTable* get_local_age_table(uint worker_id) const { + return _local_age_table[worker_id]; + } + + // Return the most recently computed tenuring threshold. + // Visible for testing. Use is_tenurable for consistent tenuring comparisons. + uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } + + // Return true if this age is at or above the tenuring threshold. + bool is_tenurable(uint age) const { + return age >= tenuring_threshold(); } // Update the local age table for worker_id by size for @@ -201,9 +216,6 @@ class ShenandoahAgeCensus: public CHeapObj { // is 0, because the evacuated objects have all had their ages incremented. void update_census(size_t age0_pop, AgeTable* pv1 = nullptr, AgeTable* pv2 = nullptr); - // Return the most recently computed tenuring threshold - uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } - // Reset the epoch, clearing accumulated census history // Note: this isn't currently used, but reserved for planned // future usage. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp index 25b900f8d77..35faa40af77 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp @@ -27,6 +27,7 @@ #include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" @@ -98,7 +99,7 @@ void ShenandoahCollectionSet::add_region(ShenandoahHeapRegion* r) { if (r->is_young()) { _young_bytes_to_evacuate += live; _young_available_bytes_collected += free; - if (ShenandoahHeap::heap()->mode()->is_generational() && r->age() >= ShenandoahGenerationalHeap::heap()->age_census()->tenuring_threshold()) { + if (ShenandoahHeap::heap()->mode()->is_generational() && ShenandoahGenerationalHeap::heap()->is_tenurable(r)) { _young_bytes_to_promote += live; } } else if (r->is_old()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index f686334d3d5..7b3839dc198 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -28,9 +28,8 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" -#include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" @@ -534,7 +533,6 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) { bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions(); ShenandoahMarkingContext* const ctx = heap->marking_context(); - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); const size_t old_garbage_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahOldGarbageThreshold) / 100; size_t old_consumed = 0; @@ -558,7 +556,7 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) { // skip over regions that aren't regular young with some live data continue; } - if (r->age() >= tenuring_threshold) { + if (heap->is_tenurable(r)) { if ((r->garbage() < old_garbage_threshold)) { // This tenure-worthy region has too little garbage, so we do not want to expend the copying effort to // reclaim the garbage; instead this region may be eligible for promotion-in-place to the @@ -613,7 +611,7 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) { // these regions. The likely outcome is that these regions will not be selected for evacuation or promotion // in the current cycle and we will anticipate that they will be promoted in the next cycle. This will cause // us to reserve more old-gen memory so that these objects can be promoted in the subsequent cycle. - if (heap->is_aging_cycle() && (r->age() + 1 == tenuring_threshold)) { + if (heap->is_aging_cycle() && heap->age_census()->is_tenurable(r->age() + 1)) { if (r->garbage() >= old_garbage_threshold) { promo_potential += r->get_live_data_bytes(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 29fd3258b6c..3a0d7926865 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -26,7 +26,7 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" @@ -56,11 +56,9 @@ ShenandoahGenerationalEvacuationTask::ShenandoahGenerationalEvacuationTask(Shena _heap(heap), _regions(iterator), _concurrent(concurrent), - _only_promote_regions(only_promote_regions), - _tenuring_threshold(0) + _only_promote_regions(only_promote_regions) { shenandoah_assert_generational(); - _tenuring_threshold = _heap->age_census()->tenuring_threshold(); } void ShenandoahGenerationalEvacuationTask::work(uint worker_id) { @@ -138,7 +136,7 @@ void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() { void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRegion* r) { - if (r->is_young() && r->is_active() && (r->age() >= _tenuring_threshold)) { + if (r->is_young() && r->is_active() && _heap->is_tenurable(r)) { if (r->is_humongous_start()) { // We promote humongous_start regions along with their affiliated continuations during evacuation rather than // doing this work during a safepoint. We cannot put humongous regions into the collection set because that @@ -176,7 +174,7 @@ void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion assert(region->garbage_before_padded_for_promote() < old_garbage_threshold, "Region %zu has too much garbage for promotion", region->index()); assert(region->is_young(), "Only young regions can be promoted"); assert(region->is_regular(), "Use different service to promote humongous regions"); - assert(region->age() >= _tenuring_threshold, "Only promote regions that are sufficiently aged"); + assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged"); assert(region->get_top_before_promote() == tams, "Region %zu has been used for allocations before promotion", region->index()); } @@ -259,7 +257,7 @@ void ShenandoahGenerationalEvacuationTask::promote_humongous(ShenandoahHeapRegio shenandoah_assert_generations_reconciled(); assert(region->is_young(), "Only young regions can be promoted"); assert(region->is_humongous_start(), "Should not promote humongous continuation in isolation"); - assert(region->age() >= _tenuring_threshold, "Only promote regions that are sufficiently aged"); + assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged"); assert(marking_context->is_marked(obj), "promoted humongous object should be alive"); const size_t used_bytes = obj->size() * HeapWordSize; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp index abe2fc0110c..0c402d6c90a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp @@ -39,7 +39,6 @@ private: ShenandoahRegionIterator* _regions; bool _concurrent; bool _only_promote_regions; - uint _tenuring_threshold; public: ShenandoahGenerationalEvacuationTask(ShenandoahGenerationalHeap* sh, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index e2e3f0a4677..c4a7408e032 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -193,7 +193,6 @@ ShenandoahPrepareForGenerationalCompactionObjectClosure::ShenandoahPrepareForGen ShenandoahHeapRegion* from_region, uint worker_id) : _preserved_marks(preserved_marks), _heap(ShenandoahGenerationalHeap::heap()), - _tenuring_threshold(0), _empty_regions(empty_regions), _empty_regions_pos(0), _old_to_region(nullptr), @@ -212,8 +211,6 @@ ShenandoahPrepareForGenerationalCompactionObjectClosure::ShenandoahPrepareForGen _young_to_region = from_region; _young_compact_point = from_region->bottom(); } - - _tenuring_threshold = _heap->age_census()->tenuring_threshold(); } void ShenandoahPrepareForGenerationalCompactionObjectClosure::set_from_region(ShenandoahHeapRegion* from_region) { @@ -279,7 +276,7 @@ void ShenandoahPrepareForGenerationalCompactionObjectClosure::do_object(oop p) { bool promote_object = false; if ((_from_affiliation == ShenandoahAffiliation::YOUNG_GENERATION) && - (from_region_age + object_age >= _tenuring_threshold)) { + _heap->age_census()->is_tenurable(from_region_age + object_age)) { if ((_old_to_region != nullptr) && (_old_compact_point + obj_size > _old_to_region->end())) { finish_old_region(); _old_to_region = nullptr; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp index 9240a056105..06080286f22 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp @@ -90,7 +90,6 @@ class ShenandoahPrepareForGenerationalCompactionObjectClosure : public ObjectClo private: PreservedMarks* const _preserved_marks; ShenandoahGenerationalHeap* const _heap; - uint _tenuring_threshold; // _empty_regions is a thread-local list of heap regions that have been completely emptied by this worker thread's // compaction efforts. The worker thread that drives these efforts adds compacted regions to this list if the diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index d05ae713645..0aca8f971e3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -216,7 +216,7 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) { if (mark.has_displaced_mark_helper()) { // We don't want to deal with MT here just to ensure we read the right mark word. // Skip the potential promotion attempt for this one. - } else if (r->age() + mark.age() >= age_census()->tenuring_threshold()) { + } else if (age_census()->is_tenurable(r->age() + mark.age())) { oop result = try_evacuate_object(p, thread, r, OLD_GENERATION); if (result != nullptr) { return result; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index f23e49735e9..6960562b31d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -80,6 +80,7 @@ public: return _age_census; } + inline bool is_tenurable(const ShenandoahHeapRegion* r) const; // Ages regions that haven't been used for allocations in the current cycle. // Resets ages for regions that have been used for allocations. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp new file mode 100644 index 00000000000..8289b48185b --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp @@ -0,0 +1,37 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP + +#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" + +#include "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.hpp" + +inline bool ShenandoahGenerationalHeap::is_tenurable(const ShenandoahHeapRegion* r) const { + return _age_census->is_tenurable(r->age()); +} + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp new file mode 100644 index 00000000000..c53d0a15554 --- /dev/null +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp @@ -0,0 +1,159 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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 "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "unittest.hpp" + +class ShenandoahAgeCensusTest : public ::testing::Test { +protected: + static constexpr size_t MinimumPopulationSize = 4*K; + static constexpr size_t InitialPopulationSize = MinimumPopulationSize * 1000; + + size_t _cohorts_count = ShenandoahAgeCensus::MAX_COHORTS; + double _mortality_rates[ShenandoahAgeCensus::MAX_COHORTS]; + size_t _cohort_populations[ShenandoahAgeCensus::MAX_COHORTS]; + + ShenandoahAgeCensusTest() + : _mortality_rates{0.9, 0.7, 0.5, 0.3, 0.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} + { + build_cohort_populations(_mortality_rates, _cohort_populations, _cohorts_count); + } + + static void add_population(ShenandoahAgeCensus& census, const uint age, const size_t population_words) { + CENSUS_NOISE(census.add(age, 0, 0, population_words, 0)); + NO_CENSUS_NOISE(census.add(age, 0, population_words, 0)); + } + + void update(ShenandoahAgeCensus& census, size_t cohorts) const { + for (uint i = 1; i < cohorts; i++) { + add_population(census, i, _cohort_populations[i]); + } + census.update_census(_cohort_populations[0]); + } + + void update(ShenandoahAgeCensus& census) const { + update(census, _cohorts_count); + } + + size_t get_total_population_older_than(const size_t min_cohort_age) const { + size_t total = 0; + for (size_t i = 0; i < _cohorts_count; i++) { + if (i >= min_cohort_age) { + total += _cohort_populations[i]; + } + } + return total; + } + + void promote_all_tenurable(const size_t tenuring_threshold) { + for (size_t i = 0; i < _cohorts_count; i++) { + if (i > tenuring_threshold) { + _cohort_populations[i] = 0; + } + } + } + + static void build_cohort_populations(const double mortality_rates[], size_t cohort_populations[], const size_t cohorts) { + cohort_populations[0] = InitialPopulationSize; + for (size_t i = 1; i < cohorts; i++) { + cohort_populations[i] = cohort_populations[i - 1] * (1.0 - mortality_rates[i - 1]); + } + } +}; + +TEST_F(ShenandoahAgeCensusTest, initialize) { + const ShenandoahAgeCensus census(1); + EXPECT_EQ(census.tenuring_threshold(), ShenandoahAgeCensus::MAX_COHORTS); +} + +TEST_F(ShenandoahAgeCensusTest, ignore_small_populations) { + // Small populations are ignored so we do not return early before reaching the youngest cohort. + ShenandoahAgeCensus census(1); + add_population(census,1, 32); + add_population(census,1, 32); + census.update_census(64); + EXPECT_EQ(1u, census.tenuring_threshold()); +} + +TEST_F(ShenandoahAgeCensusTest, find_high_mortality_rate) { + ShenandoahAgeCensus census(1); + + // Initial threshold, no data + EXPECT_EQ(16u, census.tenuring_threshold()); + + // Provide population data for 1st cohort. Previous epoch has no population data so our + // algorithm skips over all cohorts, leaving tenuring threshold at 1. + update(census, 1); + EXPECT_EQ(1u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 1 is 0.9, we don't want to promote here. Move threshold to 2. + update(census, 2); + EXPECT_EQ(2u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 2 is 0.7, we don't want to promote here. Move threshold to 3. + update(census, 3); + EXPECT_EQ(3u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 3 is 0.5, we don't want to promote here. Move threshold to 4. + update(census, 4); + EXPECT_EQ(4u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 4 is 0.3, we don't want to promote here. Move threshold to 5. + update(census, 5); + EXPECT_EQ(5u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 5 is 0.09, this is less than the mortality rate threshold. It + // is okay to tenure objects older than 5 now. Keep threshold at 5. + update(census, 6); + EXPECT_EQ(5u, census.tenuring_threshold()); + + // Mortality rate at this age is 0. Keep tenuring threshold at 5. + update(census, 7); + EXPECT_EQ(5u, census.tenuring_threshold()); +} + +TEST_F(ShenandoahAgeCensusTest, ignore_mortality_caused_by_promotions) { + ShenandoahAgeCensus census(1); + + // Simulate a sequence of censuses with the same mortality rate. Each one will see a + // mortality rate above the tenuring threshold and raise the tenuring threshold by one. + update(census, 1); + update(census, 2); + update(census, 3); + update(census, 4); + update(census, 5); + + EXPECT_EQ(5u, census.tenuring_threshold()); + + // Simulate the effect of promoting all objects above the tenuring threshold + // out of the young generation. This will look like a very high (100%) mortality + // rate for these cohorts. However, we do _not_ want to raise the threshold in + // this case because these objects haven't really "died", they have just been + // tenured. + promote_all_tenurable(census.tenuring_threshold()); + update(census); + + // We want this to stay at 5 - the mortality in 1st cohort at age 6 was caused by expected promotions. + EXPECT_EQ(5u, census.tenuring_threshold()); +} From 134c3ef41e774b483bcce32ce2fe0ef416017728 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Thu, 11 Sep 2025 00:05:02 +0000 Subject: [PATCH 231/295] 8367293: RISC-V: enable vectorapi test for VectorMask.laneIsSet Reviewed-by: fyang, epeter --- .../vectorapi/VectorMaskLaneIsSetTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java index b7f2103c56c..17d483f1b16 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java @@ -69,7 +69,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 6" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testVectorMaskLaneIsSetByte_const() { Asserts.assertEquals(ma[0], mask_b.laneIsSet(0)); Asserts.assertEquals(ma[0], mask_s.laneIsSet(0)); @@ -81,7 +81,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Byte_variable(int i) { return mask_b.laneIsSet(i); } @@ -93,7 +93,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Short_variable(int i) { return mask_s.laneIsSet(i); } @@ -105,7 +105,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Int_variable(int i) { return mask_i.laneIsSet(i); } @@ -117,7 +117,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Long_variable(int i) { return mask_l.laneIsSet(i); } @@ -129,7 +129,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Float_variable(int i) { return mask_f.laneIsSet(i); } @@ -141,7 +141,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Double_variable(int i) { return mask_d.laneIsSet(i); } From eb9e04598db7a70347ada005035644012026f902 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 11 Sep 2025 04:59:07 +0000 Subject: [PATCH 232/295] 8361530: Test javax/swing/GraphicsConfigNotifier/StalePreferredSize.java timed out Reviewed-by: psadhukhan --- .../swing/GraphicsConfigNotifier/StalePreferredSize.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java b/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java index 371c6fb43ef..3be7d08870d 100644 --- a/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java +++ b/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +66,8 @@ import static javax.swing.UIManager.getInstalledLookAndFeels; * It is checked by SwingUtilities.updateComponentTreeUI(), if layout * was correct the call to updateComponentTreeUI() will be no-op. * @compile -encoding utf-8 StalePreferredSize.java - * @run main/othervm/timeout=600 StalePreferredSize - * @run main/othervm/timeout=600 -Dsun.java2d.uiScale=1 StalePreferredSize - * @run main/othervm/timeout=600 -Dsun.java2d.uiScale=2.25 StalePreferredSize + * @run main/othervm/timeout=420 StalePreferredSize + * @run main/othervm/timeout=420 -Dsun.java2d.uiScale=2.25 StalePreferredSize */ public final class StalePreferredSize { @@ -92,7 +91,7 @@ public final class StalePreferredSize { public static void main(final String[] args) throws Exception { for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { EventQueue.invokeAndWait(() -> setLookAndFeel(laf)); - for (typeFont = 0; typeFont < 3; typeFont++) { + for (typeFont = 0; typeFont < 1; typeFont++) { System.err.println("typeFont = " + typeFont); for (boolean usePopup : new boolean[]{true, false}) { addViaPopup = usePopup; From 4cc75be80e6a89e0ed293e2f8bbb6d0f94189468 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 11 Sep 2025 05:03:21 +0000 Subject: [PATCH 233/295] 8366702: C2 SuperWord: refactor VTransform vector nodes Reviewed-by: chagedorn, galder --- .../share/opto/superwordVTransformBuilder.cpp | 110 +++++---- .../share/opto/superwordVTransformBuilder.hpp | 4 +- src/hotspot/share/opto/vtransform.cpp | 211 +++++++++--------- src/hotspot/share/opto/vtransform.hpp | 139 ++++++++++-- 4 files changed, 286 insertions(+), 178 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index b31f2eda9c0..dbc96c234a9 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -80,11 +80,13 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every memory dependency only once per vtn. if (p0->is_Load()) { + init_req_with_scalar(p0, vtn, MemNode::Control); init_req_with_scalar(p0, vtn, MemNode::Address); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (p0->is_Store()) { + init_req_with_scalar(p0, vtn, MemNode::Control); init_req_with_scalar(p0, vtn, MemNode::Address); init_req_with_vector(pack, vtn, MemNode::ValueIn); for (uint k = 0; k < pack->size(); k++) { @@ -93,26 +95,27 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } else if (vtn->isa_ReductionVector() != nullptr) { init_req_with_scalar(p0, vtn, 1); // scalar init init_req_with_vector(pack, vtn, 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())) { - init_req_with_vector(pack, vtn, 1); - init_req_with_scalar(p0, vtn, 2); // constant rotation - } else if (VectorNode::is_roundopD(p0)) { - init_req_with_vector(pack, vtn, 1); - init_req_with_scalar(p0, vtn, 2); // constant rounding mode - } else if (p0->is_CMove()) { - // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. - set_all_req_with_vectors(pack, vtn); - VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(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); + } else if (VectorNode::is_scalar_rotate(p0) && + p0->in(2)->is_Con() && + Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rotation + } else if (VectorNode::is_roundopD(p0)) { + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rounding mode + } else if (p0->is_CMove()) { + // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. + init_all_req_with_vectors(pack, vtn); + // Inputs must be permuted from (mask, blend1, blend2) -> (blend1, blend2, mask) + vtn->swap_req(1, 2); + vtn->swap_req(2, 3); + // If the test was negated: (blend1, blend2, mask) -> (blend2, blend1, mask) + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(3)->isa_BoolVector(); + if (vtn_mask_cmp->test()._is_negated) { + vtn->swap_req(1, 2); // swap if test was negated. } + } else { + init_all_req_with_vectors(pack, vtn); } } } @@ -139,51 +142,72 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ init_req_with_scalar(n, vtn, 0); continue; } else { - set_all_req_with_scalars(n, vtn); + init_all_req_with_scalars(n, vtn); } } } // 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; + const VTransformVectorNodeProperties properties = VTransformVectorNodeProperties::make_from_pack(pack, _vloop_analyzer); + const int sopc = properties.scalar_opcode(); + const uint vlen = properties.vector_length(); + const BasicType bt = properties.element_basic_type(); + VTransformVectorNode* vtn = nullptr; if (p0->is_Load()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Load()); - const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * pack_size)); - vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, pack_size, vector_p); + const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type()); } else if (p0->is_Store()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Store()); - const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * pack_size)); - vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, pack_size, vector_p); + const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); + vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, properties, vector_p, p0->adr_type()); + } else if (p0->is_Cmp()) { + vtn = new (_vtransform.arena()) VTransformCmpVectorNode(_vtransform, properties); } else if (p0->is_Bool()) { VTransformBoolTest kind = _packset.get_bool_test(pack); - vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, pack_size, kind); + vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, properties, kind); + } else if (p0->is_CMove()) { + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, Op_VectorBlend); } else if (_vloop_analyzer.reductions().is_marked_reduction(p0)) { - vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, pack_size); + vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, properties); } 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); + int vopc = VectorNode::opcode(sopc, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, properties, vopc); + } else if (VectorNode::is_convert_opcode(sopc)) { + assert(p0->req() == 2, "convert should have 2 operands"); + BasicType def_bt = _vloop_analyzer.types().velt_basic_type(p0->in(1)); + int vopc = VectorCastNode::opcode(sopc, def_bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); + } else if (VectorNode::is_reinterpret_opcode(sopc)) { + assert(p0->req() == 2, "reinterpret should have 2 operands"); + BasicType src_bt = _vloop_analyzer.types().velt_basic_type(p0->in(1)); + vtn = new (_vtransform.arena()) VTransformReinterpretVectorNode(_vtransform, properties, src_bt); + } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(p0, bt)) { + int vopc = VectorNode::opcode(Op_RShiftI, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); + } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(sopc)) { + vtn = new (_vtransform.arena()) VTransformElementWiseLongOpWithCastToIntVectorNode(_vtransform, properties); } 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_reinterpret_opcode(opc) || - VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc) || - opc == Op_FmaD || - opc == Op_FmaF || - opc == Op_FmaHF || - opc == Op_SignumF || - opc == Op_SignumD, + VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(sopc) || + VectorNode::is_reinterpret_opcode(sopc) || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(sopc) || + sopc == Op_FmaD || + sopc == Op_FmaF || + sopc == Op_FmaHF || + sopc == Op_SignumF || + sopc == Op_SignumD, "pack type must be in this list"); - vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), pack_size); + assert(!VectorNode::is_roundopD(p0) || p0->in(2)->is_Con(), "rounding mode must be constant"); + int vopc = VectorNode::opcode(sopc, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); } vtn->set_nodes(pack); return vtn; @@ -291,7 +315,7 @@ void SuperWordVTransformBuilder::init_req_with_vector(const Node_List* pack, VTr vtn->init_req(j, req); } -void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn) { +void SuperWordVTransformBuilder::init_all_req_with_scalars(Node* n, VTransformNode* vtn) { 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); @@ -300,7 +324,7 @@ void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNod } } -void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { +void SuperWordVTransformBuilder::init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { 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. diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index ea93bb60ffb..6ed8480209a 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -79,8 +79,8 @@ private: VTransformNode* get_vtnode_or_wrap_as_outer(Node* n); void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); - void set_all_req_with_scalars(Node* n, VTransformNode* vtn); - void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); + void init_all_req_with_scalars(Node* n, VTransformNode* vtn); + void init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); }; diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 2f77c1c2e37..8c1210a5a09 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -104,7 +104,7 @@ bool VTransformGraph::schedule() { } #ifndef PRODUCT - if (_trace._verbose) { + if (_trace._info) { print_schedule(); } #endif @@ -158,11 +158,9 @@ void VTransform::apply_speculative_alignment_runtime_checks() { const GrowableArray& vtnodes = _graph.vtnodes(); for (int i = 0; i < vtnodes.length(); i++) { - VTransformVectorNode* vtn = vtnodes.at(i)->isa_Vector(); + VTransformMemVectorNode* vtn = vtnodes.at(i)->isa_MemVector(); if (vtn == nullptr) { continue; } - MemNode* p0 = vtn->nodes().at(0)->isa_Mem(); - if (p0 == nullptr) { continue; } - const VPointer& vp = vpointer(p0); + const VPointer& vp = vtn->vpointer(); if (vp.mem_pointer().base().is_object()) { continue; } assert(vp.mem_pointer().base().is_native(), "VPointer base must be object or native"); @@ -720,41 +718,41 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { } VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformReplicateNode::apply(VTransformApplyState& apply_state) const { Node* val = apply_state.transformed_node(in_req(1)); VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); - register_new_node_from_vectorization(apply_state, vn, val); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformConvI2LNode::apply(VTransformApplyState& apply_state) const { Node* val = apply_state.transformed_node(in_req(1)); Node* n = new ConvI2LNode(val); - register_new_node_from_vectorization(apply_state, n, val); + register_new_node_from_vectorization(apply_state, n); return VTransformApplyResult::make_scalar(n); } @@ -766,11 +764,11 @@ VTransformApplyResult VTransformShiftCountNode::apply(VTransformApplyState& appl // 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->intcon(_mask)); - register_new_node_from_vectorization(apply_state, shift_count_masked, shift_count_in); + register_new_node_from_vectorization(apply_state, shift_count_masked); // 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(apply_state, vn, shift_count_in); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } @@ -781,77 +779,62 @@ VTransformApplyResult VTransformPopulateIndexNode::apply(VTransformApplyState& a assert(VectorNode::is_populate_index_supported(_element_bt), "should support"); const TypeVect* vt = TypeVect::make(_element_bt, _vlen); VectorNode* vn = new PopulateIndexNode(val, phase->intcon(1), vt); - register_new_node_from_vectorization(apply_state, vn, val); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyState& apply_state) const { - Node* first = nodes().at(0); - uint vlen = nodes().length(); - int opc = first->Opcode(); - BasicType bt = apply_state.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; + const TypeVect* vt = TypeVect::make(element_basic_type(), vector_length()); Node* in1 = apply_state.transformed_node(in_req(1)); Node* in2 = (req() >= 3) ? apply_state.transformed_node(in_req(2)) : nullptr; - Node* in3 = (req() >= 4) ? apply_state.transformed_node(in_req(3)) : 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::is_reinterpret_opcode(opc)) { - assert(first->req() == 2 && req() == 2, "only one input expected"); - const TypeVect* vt = TypeVect::make(bt, vlen); - vn = new VectorReinterpretNode(in1, in1->bottom_type()->is_vect(), vt); - } 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(apply_state, 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 + VectorNode* vn = nullptr; + if (req() <= 3) { + vn = VectorNode::make(_vector_opcode, in1, in2, vt); // unary and binary } else { - assert(req() == 4, "three inputs expected"); - assert(opc == Op_FmaD || - opc == Op_FmaF || - opc == Op_FmaHF || - opc == Op_SignumF || - opc == Op_SignumD, - "element wise operation must be from this list"); - vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary + Node* in3 = apply_state.transformed_node(in_req(3)); + vn = VectorNode::make(_vector_opcode, in1, in2, in3, vt); // ternary } register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->length_in_bytes()); + return VTransformApplyResult::make_vector(vn); +} + +VTransformApplyResult VTransformElementWiseLongOpWithCastToIntVectorNode::apply(VTransformApplyState& apply_state) const { + uint vlen = vector_length(); + int sopc = scalar_opcode(); + Node* in1 = apply_state.transformed_node(in_req(1)); + + // The scalar operation was a long -> int operation. + // However, the vector operation is long -> long. + VectorNode* long_vn = VectorNode::make(sopc, in1, nullptr, vlen, T_LONG); + register_new_node_from_vectorization(apply_state, long_vn); + // Cast long -> int, to mimic the scalar long -> int operation. + VectorNode* vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + return VTransformApplyResult::make_vector(vn); +} + +VTransformApplyResult VTransformReinterpretVectorNode::apply(VTransformApplyState& apply_state) const { + const TypeVect* dst_vt = TypeVect::make(element_basic_type(), vector_length()); + const TypeVect* src_vt = TypeVect::make(_src_bt, vector_length()); + assert(VectorNode::is_reinterpret_opcode(scalar_opcode()), "scalar opcode must be reinterpret"); + + Node* in1 = apply_state.transformed_node(in_req(1)); + VectorNode* vn = new VectorReinterpretNode(in1, src_vt, dst_vt); + + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& apply_state) const { - BoolNode* first = nodes().at(0)->as_Bool(); - uint vlen = nodes().length(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); + const TypeVect* vt = TypeVect::make(element_basic_type(), vector_length()); + assert(scalar_opcode() == Op_Bool, ""); // Cmp + Bool -> VectorMaskCmp - VTransformElementWiseVectorNode* vtn_cmp = in_req(1)->isa_ElementWiseVector(); - assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), - "bool vtn expects cmp vtn as input"); + VTransformCmpVectorNode* vtn_cmp = in_req(1)->isa_CmpVector(); + assert(vtn_cmp != nullptr, "bool vtn expects cmp vtn as input"); Node* cmp_in1 = apply_state.transformed_node(vtn_cmp->in_req(1)); Node* cmp_in2 = apply_state.transformed_node(vtn_cmp->in_req(2)); @@ -859,35 +842,30 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl PhaseIdealLoop* phase = apply_state.phase(); ConINode* mask_node = phase->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(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& apply_state) const { - Node* first = nodes().at(0); - uint vlen = nodes().length(); - int opc = first->Opcode(); - BasicType bt = first->bottom_type()->basic_type(); - Node* init = apply_state.transformed_node(in_req(1)); Node* vec = apply_state.transformed_node(in_req(2)); - ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); + ReductionNode* vn = ReductionNode::make(scalar_opcode(), nullptr, init, vec, element_basic_type()); register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& apply_state) const { + int sopc = scalar_opcode(); + uint vlen = vector_length(); + BasicType bt = element_basic_type(); + LoadNode* first = nodes().at(0)->as_Load(); - uint vlen = nodes().length(); - Node* ctrl = first->in(MemNode::Control); + Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); + // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule 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 = apply_state.vloop_analyzer().types().velt_basic_type(first); + Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); // Set the memory dependency of the LoadVector as early as possible. // Walk up the memory chain, and ignore any StoreVector that provably @@ -902,34 +880,33 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl } } - LoadVectorNode* vn = LoadVectorNode::make(opc, ctrl, mem, adr, adr_type, vlen, bt, + LoadVectorNode* vn = LoadVectorNode::make(sopc, 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(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& apply_state) const { + int sopc = scalar_opcode(); + uint vlen = vector_length(); + StoreNode* first = nodes().at(0)->as_Store(); - uint vlen = nodes().length(); - Node* ctrl = first->in(MemNode::Control); + Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); + // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - int opc = first->Opcode(); - const TypePtr* adr_type = first->adr_type(); + Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); - StoreVectorNode* vn = StoreVectorNode::make(opc, ctrl, mem, adr, adr_type, value, vlen); + StoreVectorNode* vn = StoreVectorNode::make(sopc, 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(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { PhaseIdealLoop* phase = apply_state.phase(); - Node* first = nodes().at(0); - - register_new_node_from_vectorization(apply_state, vn, first); + register_new_node_from_vectorization(apply_state, vn); for (int i = 0; i < _nodes.length(); i++) { Node* n = _nodes.at(i); @@ -937,9 +914,11 @@ void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scal } } -void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const { +void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const { PhaseIdealLoop* phase = apply_state.phase(); - phase->register_new_node_with_ctrl_of(vn, old_node); + // Using the cl is sometimes not the most accurate, but still correct. We do not have to be + // perfectly accurate, because we will set major_progress anyway. + phase->register_new_node(vn, apply_state.vloop().cl()); phase->igvn()._worklist.push(vn); VectorNode::trace_new_vector(vn, "AutoVectorization"); } @@ -1050,18 +1029,32 @@ void VTransformPopulateIndexNode::print_spec() const { } 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("]"); + tty->print("Properties[orig=[%d %s] sopc=%s vlen=%d element_bt=%s]", + approximate_origin()->_idx, + approximate_origin()->Name(), + NodeClassNames[scalar_opcode()], + vector_length(), + type2name(element_basic_type())); if (is_load_or_store_in_loop()) { tty->print(" "); vpointer().print_on(tty, false); } } + +void VTransformElementWiseVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + tty->print(" vopc=%s", NodeClassNames[_vector_opcode]); +} + +void VTransformReinterpretVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + tty->print(" src_bt=%s", type2name(_src_bt)); +} + +void VTransformBoolVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + const BoolTest bt(_test._mask); + tty->print(" test="); + bt.dump_on(tty); +} #endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 60b0b5d4f9d..9a4e4de01a2 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -26,6 +26,7 @@ #include "opto/node.hpp" #include "opto/vectorization.hpp" +#include "opto/vectornode.hpp" // VTransform: // - Models the transformation of the scalar loop to vectorized loop: @@ -67,6 +68,7 @@ class VTransformCFGNode; class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; +class VTransformCmpVectorNode; class VTransformBoolVectorNode; class VTransformReductionVectorNode; class VTransformMemVectorNode; @@ -90,9 +92,12 @@ public: 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_vector(VectorNode* vn) { + return VTransformApplyResult(vn, vn->length(), vn->length_in_bytes()); + } + + static VTransformApplyResult make_vector(Node* n, const TypeVect* vt) { + return VTransformApplyResult(n, vt->length(), vt->length_in_bytes()); } static VTransformApplyResult make_empty() { @@ -431,6 +436,7 @@ public: virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } + virtual VTransformCmpVectorNode* isa_CmpVector() { return nullptr; } virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } virtual VTransformReductionVectorNode* isa_ReductionVector() { return nullptr; } virtual VTransformMemVectorNode* isa_MemVector() { return nullptr; } @@ -445,7 +451,7 @@ public: Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; - void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const; + void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual const char* name() const = 0;) NOT_PRODUCT(void print() const;) @@ -590,13 +596,52 @@ public: NOT_PRODUCT(virtual void print_spec() const override;) }; -// Base class for all vector vtnodes. +// Bundle the information needed for vector nodes. +class VTransformVectorNodeProperties : public StackObj { +private: + Node* _approximate_origin; // for proper propagation of node notes + const int _scalar_opcode; + const uint _vector_length; + const BasicType _element_basic_type; + + VTransformVectorNodeProperties(Node* approximate_origin, + int scalar_opcode, + uint vector_length, + BasicType element_basic_type) : + _approximate_origin(approximate_origin), + _scalar_opcode(scalar_opcode), + _vector_length(vector_length), + _element_basic_type(element_basic_type) {} + +public: + static VTransformVectorNodeProperties make_from_pack(const Node_List* pack, const VLoopAnalyzer& vloop_analyzer) { + Node* first = pack->at(0); + int opc = first->Opcode(); + int vlen = pack->size(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + return VTransformVectorNodeProperties(first, opc, vlen, bt); + } + + Node* approximate_origin() const { return _approximate_origin; } + int scalar_opcode() const { return _scalar_opcode; } + uint vector_length() const { return _vector_length; } + BasicType element_basic_type() const { return _element_basic_type; } +}; + +// Abstract base class for all vector vtnodes. class VTransformVectorNode : public VTransformNode { private: + const VTransformVectorNodeProperties _properties; +protected: 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) {} + VTransformVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties) : + VTransformNode(vtransform, req), + _properties(properties), + _nodes(vtransform.arena(), + properties.vector_length(), + properties.vector_length(), + nullptr) {} void set_nodes(const Node_List* pack) { for (uint k = 0; k < pack->size(); k++) { @@ -604,20 +649,50 @@ public: } } - const GrowableArray& nodes() const { return _nodes; } virtual VTransformVectorNode* isa_Vector() override { return this; } void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual void print_spec() const override;) + +protected: + Node* approximate_origin() const { return _properties.approximate_origin(); } + int scalar_opcode() const { return _properties.scalar_opcode(); } + uint vector_length() const { return _properties.vector_length(); } + BasicType element_basic_type() const { return _properties.element_basic_type(); } }; // Catch all for all element-wise vector operations. class VTransformElementWiseVectorNode : public VTransformVectorNode { +private: + const int _vector_opcode; public: - VTransformElementWiseVectorNode(VTransform& vtransform, uint req, uint number_of_nodes) : - VTransformVectorNode(vtransform, req, number_of_nodes) {} + VTransformElementWiseVectorNode(VTransform& vtransform, uint req, const VTransformVectorNodeProperties properties, const int vector_opcode) : + VTransformVectorNode(vtransform, req, properties), _vector_opcode(vector_opcode) {} virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// The scalar operation was a long -> int operation. +// However, the vector operation is long -> long. +// Hence, we vectorize it as: long --long_op--> long --cast--> int +class VTransformElementWiseLongOpWithCastToIntVectorNode : public VTransformVectorNode { +public: + VTransformElementWiseLongOpWithCastToIntVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 2, properties) {} + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseLongOpWithCastToIntVector"; };) +}; + +class VTransformReinterpretVectorNode : public VTransformVectorNode { +private: + const BasicType _src_bt; +public: + VTransformReinterpretVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const BasicType src_bt) : + VTransformVectorNode(vtransform, 2, properties), _src_bt(src_bt) {} + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ReinterpretVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; struct VTransformBoolTest { @@ -628,23 +703,35 @@ struct VTransformBoolTest { _mask(mask), _is_negated(is_negated) {} }; -class VTransformBoolVectorNode : public VTransformElementWiseVectorNode { +// Cmp + Bool -> VectorMaskCmp +// The Bool node takes care of "apply". +class VTransformCmpVectorNode : public VTransformVectorNode { +public: + VTransformCmpVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 3, properties) {} + virtual VTransformCmpVectorNode* isa_CmpVector() override { return this; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override { return VTransformApplyResult::make_empty(); } + NOT_PRODUCT(virtual const char* name() const override { return "CmpVector"; };) +}; + +class VTransformBoolVectorNode : public VTransformVectorNode { private: const VTransformBoolTest _test; public: - VTransformBoolVectorNode(VTransform& vtransform, uint number_of_nodes, VTransformBoolTest test) : - VTransformElementWiseVectorNode(vtransform, 2, number_of_nodes), _test(test) {} + VTransformBoolVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, VTransformBoolTest test) : + VTransformVectorNode(vtransform, 2, properties), _test(test) {} VTransformBoolTest test() const { return _test; } virtual VTransformBoolVectorNode* isa_BoolVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; class VTransformReductionVectorNode : public VTransformVectorNode { public: // req = 3 -> [ctrl, scalar init, vector] - VTransformReductionVectorNode(VTransform& vtransform, uint number_of_nodes) : - VTransformVectorNode(vtransform, 3, number_of_nodes) {} + VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 3, properties) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) @@ -653,12 +740,16 @@ public: class VTransformMemVectorNode : public VTransformVectorNode { private: const VPointer _vpointer; // with size of the vector +protected: + const TypePtr* _adr_type; public: - VTransformMemVectorNode(VTransform& vtransform, const uint req, uint number_of_nodes, const VPointer& vpointer) : - VTransformVectorNode(vtransform, req, number_of_nodes), - _vpointer(vpointer) {} + VTransformMemVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformVectorNode(vtransform, req, properties), + _vpointer(vpointer), + _adr_type(adr_type) {} + const GrowableArray& nodes() const { return _nodes; } virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } virtual const VPointer& vpointer() const override { return _vpointer; } @@ -667,8 +758,8 @@ public: class VTransformLoadVectorNode : public VTransformMemVectorNode { public: // req = 3 -> [ctrl, mem, adr] - VTransformLoadVectorNode(VTransform& vtransform, uint number_of_nodes, const VPointer& vpointer) : - VTransformMemVectorNode(vtransform, 3, number_of_nodes, vpointer) {} + VTransformLoadVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type) {} LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } @@ -679,8 +770,8 @@ public: class VTransformStoreVectorNode : public VTransformMemVectorNode { public: // req = 4 -> [ctrl, mem, adr, val] - VTransformStoreVectorNode(VTransform& vtransform, uint number_of_nodes, const VPointer& vpointer) : - VTransformMemVectorNode(vtransform, 4, number_of_nodes, vpointer) {} + VTransformStoreVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformMemVectorNode(vtransform, 4, properties, vpointer, adr_type) {} virtual VTransformStoreVectorNode* isa_StoreVector() override { return this; } virtual bool is_load_in_loop() const override { return false; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; @@ -703,8 +794,8 @@ void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { callback(scalar->node()); } - VTransformVectorNode* vector = vtn->isa_Vector(); - if (vector != nullptr && vector->nodes().at(0)->is_Mem()) { + VTransformMemVectorNode* vector = vtn->isa_MemVector(); + if (vector != nullptr) { for (int j = 0; j < vector->nodes().length(); j++) { callback(vector->nodes().at(j)->as_Mem()); } From 2826d1702534783023802ac5c8d8ea575558f09f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 11 Sep 2025 05:05:30 +0000 Subject: [PATCH 234/295] 8367243: Format issues with dist dump debug output in PhaseGVN::dead_loop_check Reviewed-by: thartmann --- src/hotspot/share/opto/phaseX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index a4248cb2b91..00b36d0bf43 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -780,7 +780,7 @@ void PhaseGVN::dead_loop_check( Node *n ) { } } } - if (!no_dead_loop) n->dump_bfs(100,nullptr,"#"); + if (!no_dead_loop) { n->dump_bfs(100, nullptr, ""); } assert(no_dead_loop, "dead loop detected"); } } From 7690a45f77a2da47fa912fe7a2b2faa589f259f0 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 11 Sep 2025 06:55:32 +0000 Subject: [PATCH 235/295] 8366342: Key generator and key pair generator tests skipping, but showing as passed Reviewed-by: weijun --- .../security/pkcs11/KeyGenerator/DESParity.java | 11 ++++++----- .../sun/security/pkcs11/KeyGenerator/TestAES.java | 14 +++++++------- .../security/pkcs11/KeyGenerator/TestChaCha20.java | 7 ++++--- .../pkcs11/KeyGenerator/TestKeyGenerator.java | 2 +- .../pkcs11/KeyPairGenerator/TestDH2048.java | 7 ++++--- .../TestDefaultDHPrivateExpSize.java | 9 ++++----- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java b/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java index 59f58ca525e..f9da78df0e2 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @run main/othervm DESParity */ +import jtreg.SkippedException; + import java.security.Provider; import java.util.Random; import javax.crypto.SecretKey; @@ -45,8 +47,7 @@ public class DESParity extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("SecretKeyFactory", "DES") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } Random random = new Random(); SecretKeyFactory kf; @@ -57,7 +58,7 @@ public class DESParity extends PKCS11Test { random.nextBytes(b); SecretKeySpec spec = new SecretKeySpec(b, "DES"); SecretKey key = kf.generateSecret(spec); - if (DESKeySpec.isParityAdjusted(key.getEncoded(), 0) == false) { + if (!DESKeySpec.isParityAdjusted(key.getEncoded(), 0)) { throw new Exception("DES key not parity adjusted"); } } @@ -68,7 +69,7 @@ public class DESParity extends PKCS11Test { random.nextBytes(b); SecretKeySpec spec = new SecretKeySpec(b, "DESede"); SecretKey key = kf.generateSecret(spec); - if (DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0) == false) { + if (!DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0)) { throw new Exception("DESede key not parity adjusted"); } } diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java index e74007a65e3..66078be30bd 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ * @library /test/lib .. * @run main TestAES */ +import jtreg.SkippedException; +import sun.security.util.SecurityProviderConstants; + import java.security.Provider; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; -import static sun.security.util.SecurityProviderConstants.*; public class TestAES extends PKCS11Test { @@ -53,17 +54,16 @@ public class TestAES extends PKCS11Test { try { kg = KeyGenerator.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO, nsae); } // first try w/o setting a key length and check if the generated key // length matches SecretKey key = kg.generateKey(); byte[] keyValue = key.getEncoded(); - if (key.getEncoded().length != getDefAESKeySize() >> 3) { + if (key.getEncoded().length != SecurityProviderConstants.getDefAESKeySize() >> 3) { throw new RuntimeException("Default AES key length should be " + - getDefAESKeySize()); + SecurityProviderConstants.getDefAESKeySize()); } for (int keySize : new int[] { 16, 32, 64, 128, 256, 512, 1024 }) { diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java index a21571cd957..0eaab538655 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @library /test/lib .. * @run main/othervm TestChaCha20 */ +import jtreg.SkippedException; + import java.security.Provider; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; @@ -54,8 +56,7 @@ public class TestChaCha20 extends PKCS11Test { try { kg = KeyGenerator.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO, nsae); } try { diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java index 15d0ee87fe4..50886a7aba3 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java index b05861ff3ae..06a9fa67afe 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run main/othervm TestDH2048 */ +import jtreg.SkippedException; + import java.security.InvalidParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -50,8 +52,7 @@ public class TestDH2048 extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyPairGenerator", "DH") == null) { - System.out.println("KPG for DH not supported, skipping"); - return; + throw new SkippedException("KPG for DH not supported, skipping"); } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); kpg.initialize(512); diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java index cb93a96fdd2..3f19a59423b 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * 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,12 +21,12 @@ * questions. */ -import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Provider; -import java.security.PrivateKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.interfaces.DHPrivateKey; + +import jtreg.SkippedException; import sun.security.util.SecurityProviderConstants; import sun.security.provider.ParameterCache; @@ -47,8 +47,7 @@ public class TestDefaultDHPrivateExpSize extends PKCS11Test { System.out.println("Testing " + p.getName()); if (p.getService("KeyPairGenerator", "DH") == null) { - System.out.println("Skip, no support for DH KeyPairGenerator"); - return; + throw new SkippedException("Skip, no support for DH KeyPairGenerator"); } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); From 8ba0db0de8b79f64cbfa56683f660f888c880182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 11 Sep 2025 07:42:39 +0000 Subject: [PATCH 236/295] 8366951: Test runtime/logging/StressAsyncUL.java is timing out Reviewed-by: ayang, lkorinth, dholmes, syan --- test/hotspot/jtreg/runtime/logging/StressAsyncUL.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java index 2967507fa64..479f62d6c30 100644 --- a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java @@ -45,12 +45,12 @@ public class StressAsyncUL { } } public static void main(String[] args) throws Exception { - analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", InnerClass.class.getName()); - analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=debug", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=debug", InnerClass.class.getName()); // Stress test with a very small buffer. Note: Any valid buffer size must be able to hold a flush token. // Therefore the size of the buffer cannot be zero. - analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); - analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=debug", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=debug", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); } public static class InnerClass { From 0b3a303053d0eb5a98ed3d9df42c659db148b470 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 11 Sep 2025 08:07:25 +0000 Subject: [PATCH 237/295] 8367066: RISC-V: refine register selection in MacroAssembler:: decode_klass_not_null Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 13 +++++-------- src/hotspot/cpu/riscv/riscv.ad | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 1436bc02113..8f136135a89 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3402,6 +3402,8 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register tmp) { assert(UseCompressedClassPointers, "should only be used for compressed headers"); + assert_different_registers(dst, tmp); + assert_different_registers(src, tmp); if (CompressedKlassPointers::base() == nullptr) { if (CompressedKlassPointers::shift() != 0) { @@ -3412,18 +3414,13 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register return; } - Register xbase = dst; - if (dst == src) { - xbase = tmp; - } + Register xbase = tmp; - assert_different_registers(src, xbase); mv(xbase, (uintptr_t)CompressedKlassPointers::base()); if (CompressedKlassPointers::shift() != 0) { - Register t = src == dst ? dst : t0; - assert_different_registers(t, xbase); - shadd(dst, src, xbase, t, CompressedKlassPointers::shift()); + // dst = (src << shift) + xbase + shadd(dst, src, xbase, dst /* temporary, dst != xbase */, CompressedKlassPointers::shift()); } else { add(dst, xbase, src); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 0c4dd7b71e2..739a525c9a4 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -8938,7 +8938,7 @@ instruct encodeKlass_not_null(iRegNNoSp dst, iRegP src) %{ instruct decodeKlass_not_null(iRegPNoSp dst, iRegN src, iRegPNoSp tmp) %{ match(Set dst (DecodeNKlass src)); - effect(TEMP tmp); + effect(TEMP_DEF dst, TEMP tmp); ins_cost(ALU_COST); format %{ "decode_klass_not_null $dst, $src\t#@decodeKlass_not_null" %} From 3d679087b0376c221d536780cee387dc2dd8019e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 11 Sep 2025 08:53:09 +0000 Subject: [PATCH 238/295] 8367268: Remove unused os::numa_topology_changed() Reviewed-by: ayang, dholmes --- src/hotspot/os/aix/os_aix.cpp | 4 ---- src/hotspot/os/bsd/os_bsd.cpp | 2 -- src/hotspot/os/linux/os_linux.cpp | 2 -- src/hotspot/os/windows/os_windows.cpp | 1 - src/hotspot/share/runtime/os.hpp | 1 - 5 files changed, 10 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index aa119210f47..2dd60b51119 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1753,10 +1753,6 @@ void os::numa_make_global(char *addr, size_t bytes) { void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { - return false; -} - size_t os::numa_get_groups_num() { return 1; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 4f5fed2c8c0..8b75c0dcdd8 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1599,8 +1599,6 @@ void os::numa_make_global(char *addr, size_t bytes) { void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { return false; } - size_t os::numa_get_groups_num() { return 1; } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index d133813feb0..9f896d62d4d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2988,8 +2988,6 @@ void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { Linux::numa_tonode_memory(addr, bytes, lgrp_hint); } -bool os::numa_topology_changed() { return false; } - size_t os::numa_get_groups_num() { // Return just the number of nodes in which it's possible to allocate memory // (in numa terminology, configured nodes). diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 09d8b542a10..4061ccf9dac 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3794,7 +3794,6 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { void os::numa_make_global(char *addr, size_t bytes) { } void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { return false; } size_t os::numa_get_groups_num() { return MAX2(numa_node_list_holder.get_count(), 1); } int os::numa_get_group_id() { return 0; } size_t os::numa_get_leaf_groups(uint *ids, size_t size) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 9db4380fc07..4f6830daa4c 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -540,7 +540,6 @@ class os: AllStatic { static void numa_make_global(char *addr, size_t bytes); static size_t numa_get_groups_num(); static size_t numa_get_leaf_groups(uint *ids, size_t size); - static bool numa_topology_changed(); static int numa_get_group_id(); static int numa_get_group_id_for_address(const void* address); static bool numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count); From 3355a9d3fa3e57d489f716ebc1c885c1391274ea Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 11 Sep 2025 10:43:25 +0000 Subject: [PATCH 239/295] 8285150: Improve tab completion for annotations Reviewed-by: liach --- .../jshell/tool/ConsoleIOContext.java | 19 +- .../jdk/jshell/SourceCodeAnalysisImpl.java | 262 ++++++++++++++++-- .../jdk/jshell/CompletionSuggestionTest.java | 43 +++ .../jdk/jshell/ToolTabSnippetTest.java | 20 ++ 4 files changed, 323 insertions(+), 21 deletions(-) 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 5cf301efac5..1662f81710a 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 @@ -394,9 +394,9 @@ class ConsoleIOContext extends IOContext { .reduce(ConsoleIOContext::commonPrefix); String prefix = - prefixOpt.orElse("").substring(cursor - anchor[0]); + prefixOpt.orElse(""); - if (!prefix.isEmpty() && !command) { + if (prefix.length() > cursor - anchor[0] && !command) { //the completion will fill in the prefix, which will invalidate //the documentation, avoid adding documentation tasks into the //todo list: @@ -405,6 +405,7 @@ class ConsoleIOContext extends IOContext { ordinaryCompletion = new OrdinaryCompletionTask(ordinaryCompletionToShow, + anchor[0], prefix, !command && !doc.isEmpty(), hasBoth); @@ -609,15 +610,18 @@ class ConsoleIOContext extends IOContext { private final class OrdinaryCompletionTask implements CompletionTask { private final List toShow; + private final int anchor; private final String prefix; private final boolean cont; private final boolean showSmart; public OrdinaryCompletionTask(List toShow, + int anchor, String prefix, boolean cont, boolean showSmart) { this.toShow = toShow; + this.anchor = anchor; this.prefix = prefix; this.cont = cont; this.showSmart = showSmart; @@ -630,7 +634,14 @@ class ConsoleIOContext extends IOContext { @Override public Result perform(String text, int cursor) throws IOException { - in.putString(prefix); + String existingPrefix = in.getBuffer().substring(anchor, cursor); + + if (prefix.startsWith(existingPrefix)) { + in.putString(prefix.substring(existingPrefix.length())); + } else { + in.getBuffer().backspace(existingPrefix.length()); + in.putString(prefix); + } boolean showItems = toShow.size() > 1 || showSmart; @@ -639,7 +650,7 @@ class ConsoleIOContext extends IOContext { printColumns(toShow); } - if (!prefix.isEmpty()) + if (prefix.length() > existingPrefix.length()) return showItems ? Result.FINISH : Result.SKIP_NOREPAINT; return cont ? Result.CONTINUE : Result.FINISH; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index fffdfd5b33c..045734d9f55 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -38,6 +38,7 @@ import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.ModifiersTree; +import com.sun.source.tree.NewArrayTree; import com.sun.source.tree.NewClassTree; import com.sun.source.tree.Scope; import com.sun.source.tree.Tree; @@ -111,6 +112,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -310,13 +312,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { default -> proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); }; String[] requiredPrefix = new String[] {identifier}; - return computeSuggestions(codeWrap, cursor, requiredPrefix, anchor).stream() - .filter(s -> s.continuation().startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) + return computeSuggestions(codeWrap, code, cursor, requiredPrefix, anchor).stream() + .filter(s -> filteringText(s).startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) .sorted(Comparator.comparing(Suggestion::continuation)) .toList(); } - private List computeSuggestions(OuterWrap code, int cursor, String[] requiredPrefix, int[] anchor) { + private static String filteringText(Suggestion suggestion) { + return suggestion instanceof SuggestionImpl impl + ? impl.filteringText + : suggestion.continuation(); + } + + private List computeSuggestions(OuterWrap code, String inputCode, int cursor, String[] requiredPrefix, int[] anchor) { return proc.taskFactory.analyze(code, at -> { SourcePositions sp = at.trees().getSourcePositions(); CompilationUnitTree topLevel = at.firstCuTree(); @@ -479,6 +487,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { addScopeElements(at, scope, IDENTITY, accept, IS_PACKAGE.negate().and(smartTypeFilter), result); break; } + if (isAnnotation(tp)) { + if (getAnnotationAttributeNameOrNull(tp.getParentPath(), true) != null) { + //nested annotation + result = completionSuggestionsImpl(inputCode, cursor - 1, anchor); + requiredPrefix[0] = "@" + requiredPrefix[0]; + return result; + } + + Predicate accept = accessibility.and(STATIC_ONLY) + .and(IS_PACKAGE.or(IS_CLASS).or(IS_INTERFACE)); + addScopeElements(at, scope, IDENTITY, accept, IS_PACKAGE.negate().and(smartTypeFilter), result); + break; + } ImportTree it = findImport(tp); if (it != null) { if (it.isModule()) { @@ -512,6 +533,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { case ERRONEOUS: { boolean staticOnly = ReplResolve.isStatic(((JavacScope)scope).getEnv()); Predicate accept = accessibility.and(staticOnly ? STATIC_ONLY : TRUE); + boolean insertPrimitiveTypes = true; if (isClass(tp)) { ClassTree clazz = (ClassTree) tp.getParentPath().getLeaf(); if (clazz.getExtendsClause() == tp.getLeaf()) { @@ -539,20 +561,101 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { if (var.getType() == tp.getLeaf()) { accept = accept.and(IS_TYPE); } + } else if (tp.getParentPath().getLeaf().getKind() == Kind.ANNOTATION) { + AnnotationTree annotation = (AnnotationTree) tp.getParentPath().getLeaf(); + Element annotationType = at.trees().getElement(tp.getParentPath()); + Set present = annotation.getArguments() + .stream() + .filter(expr -> expr.getKind() == Kind.ASSIGNMENT) + .map(expr -> (AssignmentTree) expr) + .map(assign -> assign.getVariable()) + .filter(var -> var.getKind() == Kind.IDENTIFIER) + .map(var -> ((IdentifierTree) var).getName().toString()) + .collect(Collectors.toSet()); + addElements(ElementFilter.methodsIn(annotationType.getEnclosedElements()), el -> !present.contains(el.getSimpleName().toString()), TRUE, _ -> " = ", result); + break; + } else if (getAnnotationAttributeNameOrNull(tp, true) instanceof String attributeName) { + Element annotationType = tp.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION + ? at.trees().getElement(tp.getParentPath().getParentPath()) + : at.trees().getElement(tp.getParentPath().getParentPath().getParentPath()); + if (sp.getEndPosition(topLevel, tp.getParentPath().getLeaf()) == (-1)) { + //synthetic 'value': + addElements(ElementFilter.methodsIn(annotationType.getEnclosedElements()), TRUE, TRUE, _ -> " = ", result); + boolean hasValue = findAnnotationAttributeIfAny(annotationType, "value").isPresent(); + if (!hasValue) { + break; + } + } + Optional ee = findAnnotationAttributeIfAny(annotationType, attributeName); + if (ee.isEmpty()) { + break; + } + TypeMirror relevantAttributeType = ee.orElseThrow().getReturnType(); + if (relevantAttributeType.getKind() == TypeKind.ARRAY) { + relevantAttributeType = ((ArrayType) relevantAttributeType).getComponentType(); + } + if (relevantAttributeType.getKind() == TypeKind.DECLARED && + at.getTypes().asElement(relevantAttributeType) instanceof Element attributeTypeEl) { + if (attributeTypeEl.getKind() == ElementKind.ANNOTATION_TYPE) { + boolean hasAnyAttributes = + ElementFilter.methodsIn(attributeTypeEl.getEnclosedElements()) + .stream() + .anyMatch(attribute -> attribute.getParameters().isEmpty()); + String paren = hasAnyAttributes ? "(" : ""; + String name = scopeContent(at, scope, IDENTITY).contains(attributeTypeEl) + ? attributeTypeEl.getSimpleName().toString() //simple name ought to be enough: + : ((TypeElement) attributeTypeEl).getQualifiedName().toString(); + result.add(new SuggestionImpl("@" + name + paren, true)); + break; + } else if (attributeTypeEl.getKind() == ElementKind.ENUM) { + String typeName = scopeContent(at, scope, IDENTITY).contains(attributeTypeEl) + ? attributeTypeEl.getSimpleName().toString() //simple name ought to be enough: + : ((TypeElement) attributeTypeEl).getQualifiedName().toString(); + result.add(new SuggestionImpl(typeName, true)); + result.addAll(ElementFilter.fieldsIn(attributeTypeEl.getEnclosedElements()) + .stream() + .filter(e -> e.getKind() == ElementKind.ENUM_CONSTANT) + .map(c -> new SuggestionImpl(scopeContent(at, scope, IDENTITY).contains(c) + ? c.getSimpleName().toString() + : typeName + "." + c.getSimpleName(), c.getSimpleName().toString(), + true)) + .toList()); + break; + } + } + accept = accessibility.and(el -> { + return switch (el.getKind()) { + case PACKAGE, ANNOTATION_TYPE, ENUM, INTERFACE, RECORD, ENUM_CONSTANT -> true; + case CLASS -> !((TypeElement) el).asType().getKind().isPrimitive(); + case FIELD -> isPermittedAnnotationAttributeFieldType(at, el.asType()); + default -> false; + }; + }); + insertPrimitiveTypes = false; } addScopeElements(at, scope, IDENTITY, accept, smartFilter, result); - Tree parent = tp.getParentPath().getLeaf(); - accept = switch (parent.getKind()) { - case VARIABLE -> ((VariableTree) parent).getType() == tp.getLeaf() ? - IS_VOID.negate() : - TRUE; - case PARAMETERIZED_TYPE -> FALSE; // TODO: JEP 218: Generics over Primitive Types - case TYPE_PARAMETER, CLASS, INTERFACE, ENUM, RECORD -> FALSE; - default -> TRUE; - }; - addElements(primitivesOrVoid(at), accept, smartFilter, result); + if (insertPrimitiveTypes) { + Tree parent = tp.getParentPath().getLeaf(); + accept = switch (parent.getKind()) { + case VARIABLE -> ((VariableTree) parent).getType() == tp.getLeaf() ? + IS_VOID.negate() : + TRUE; + case PARAMETERIZED_TYPE -> FALSE; // TODO: JEP 218: Generics over Primitive Types + case TYPE_PARAMETER, CLASS, INTERFACE, ENUM, RECORD -> FALSE; + default -> TRUE; + }; + addElements(primitivesOrVoid(at), accept, smartFilter, result); + } + + boolean hasBooleanSmartType = targetTypes != null && + StreamSupport.stream(targetTypes.spliterator(), false) + .anyMatch(tm -> tm.getKind() == TypeKind.BOOLEAN); + if (hasBooleanSmartType) { + result.add(new SuggestionImpl("true", true)); + result.add(new SuggestionImpl("false", true)); + } break; } } @@ -917,6 +1020,12 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { long start = sp.getStartPosition(topLevel, tree); long end = sp.getEndPosition(topLevel, tree); + if (end == (-1) && tree.getKind() == Kind.ASSIGNMENT && + getCurrentPath() != null && + getCurrentPath().getLeaf().getKind() == Kind.ANNOTATION) { + //the assignment is synthetically generated, take the end pos of the nested tree: + end = sp.getEndPosition(topLevel, ((AssignmentTree) tree).getExpression()); + } if (start <= wrapEndPos && wrapEndPos <= end && (deepest[0] == null || deepest[0].getLeaf() == getCurrentPath().getLeaf())) { deepest[0] = new TreePath(getCurrentPath(), tree); @@ -946,6 +1055,12 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { ((MethodTree)parent).getThrows().contains(tp.getLeaf()); } + private boolean isAnnotation(TreePath tp) { + Tree parent = tp.getParentPath().getLeaf(); + return parent.getKind() == Kind.ANNOTATION && + ((AnnotationTree)parent).getAnnotationType().equals(tp.getLeaf()); + } + private boolean isClass(TreePath tp) { return tp.getParentPath() != null && CLASS_KINDS.contains(tp.getParentPath().getLeaf().getKind()); @@ -961,6 +1076,39 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { tp.getParentPath().getLeaf().getKind() == Kind.VARIABLE; } + private String getAnnotationAttributeNameOrNull(TreePath tp, boolean acceptArray) { + if (tp.getParentPath() == null) { + return null; + } + if (tp.getParentPath().getLeaf().getKind() == Kind.NEW_ARRAY && + ((NewArrayTree) tp.getParentPath().getLeaf()).getInitializers().contains(tp.getLeaf())) { + if (acceptArray) { + return getAnnotationAttributeNameOrNull(tp.getParentPath(), false); + } else { + return null; + } + } + if (tp.getParentPath().getParentPath() == null || + tp.getParentPath().getLeaf().getKind() != Kind.ASSIGNMENT || + tp.getParentPath().getParentPath().getLeaf().getKind() != Kind.ANNOTATION) { + return null; + } + AssignmentTree assign = (AssignmentTree) tp.getParentPath().getLeaf(); + if (assign.getVariable().getKind() != Kind.IDENTIFIER) { + return null; + } + return ((IdentifierTree) assign.getVariable()).getName().toString(); + } + + private Optional findAnnotationAttributeIfAny(Element annotationType, + String attributeName) { + return ElementFilter.methodsIn(annotationType.getEnclosedElements()) + .stream() + .filter(ee -> ee.getSimpleName().contentEquals(attributeName)) + .filter(ee -> ee.getParameters().isEmpty()) + .findAny(); + } + private ImportTree findImport(TreePath tp) { while (tp != null && tp.getLeaf().getKind() != Kind.IMPORT) { tp = tp.getParentPath(); @@ -987,6 +1135,17 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { }; } + private boolean isPermittedAnnotationAttributeFieldType(AnalyzeTask at, TypeMirror type) { + if (type.getKind().isPrimitive()) { + return true; + } + if (type.getKind() == TypeKind.DECLARED) { + Element el = ((DeclaredType) type).asElement(); + return el.getKind() == ElementKind.ENUM || el.equals(at.getElements().getTypeElement("java.lang.String")); + } + return false; + } + private final Predicate TRUE = el -> true; private final Predicate FALSE = TRUE.negate(); private final Predicate IS_STATIC = el -> el.getModifiers().contains(Modifier.STATIC); @@ -1237,7 +1396,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { return new VarSymbol(Flags.PUBLIC | Flags.STATIC | Flags.FINAL, _class, classType, erasedSite.tsym); } - private Iterable scopeContent(AnalyzeTask at, Scope scope, Function> elementConvertor) { + private Collection scopeContent(AnalyzeTask at, Scope scope, Function> elementConvertor) { Iterable scopeIterable = () -> new Iterator() { private Scope currentScope = scope; @Override @@ -1306,11 +1465,54 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { Tree current = forPath.getLeaf(); + if (current.getKind() == Kind.ANNOTATION) { + Element type = at.trees().getElement(forPath); + if (type != null) { + Optional valueAttr = + ElementFilter.methodsIn(type.getEnclosedElements()) + .stream() + .filter(ee -> ee.getSimpleName().contentEquals("value")) + .findAny(); + if (valueAttr.isPresent()) { + TypeMirror returnType = valueAttr.orElseThrow().getReturnType(); + + if (returnType.getKind() == TypeKind.ARRAY) { + returnType = ((ArrayType) returnType).getComponentType(); + } + + return Collections.singletonList(returnType); + } + } + } + switch (forPath.getParentPath().getLeaf().getKind()) { + case NEW_ARRAY: + if (getAnnotationAttributeNameOrNull(forPath, true) != null) { + forPath = forPath.getParentPath(); + current = forPath.getLeaf(); + //fall-through + } else { + break; + } case ASSIGNMENT: { AssignmentTree tree = (AssignmentTree) forPath.getParentPath().getLeaf(); - if (tree.getExpression() == current) - return Collections.singletonList(at.trees().getTypeMirror(new TreePath(forPath.getParentPath(), tree.getVariable()))); + if (tree.getExpression() == current) { + if (forPath.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION) { + Element method = at.trees().getElement(new TreePath(forPath.getParentPath(), tree.getVariable())); + if (method != null && method.getKind() == ElementKind.METHOD) { + TypeMirror returnType = ((ExecutableElement) method).getReturnType(); + + if (returnType.getKind() == TypeKind.ARRAY) { + returnType = ((ArrayType) returnType).getComponentType(); + } + + return Collections.singletonList(returnType); + } + return null; + } else { + return Collections.singletonList(at.trees().getTypeMirror(new TreePath(forPath.getParentPath(), tree.getVariable()))); + } + } break; } case VARIABLE: { @@ -1558,7 +1760,8 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { TreePath prevPath = null; while (tp != null && tp.getLeaf().getKind() != Kind.METHOD_INVOCATION && tp.getLeaf().getKind() != Kind.NEW_CLASS && tp.getLeaf().getKind() != Kind.IDENTIFIER && - tp.getLeaf().getKind() != Kind.MEMBER_SELECT) { + tp.getLeaf().getKind() != Kind.MEMBER_SELECT && + tp.getLeaf().getKind() != Kind.ANNOTATION) { prevPath = tp; tp = tp.getParentPath(); } @@ -1611,6 +1814,18 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } elements = Stream.of(el); + } else if (tp.getLeaf().getKind() == Kind.ANNOTATION) { + Element el = at.trees().getElement(tp); + + if (el == null || + el.getKind() != ElementKind.ANNOTATION_TYPE) { + //erroneous state: + return Collections.emptyList(); + } + + elements = ElementFilter.methodsIn(el.getEnclosedElements()) + .stream() + .map(ee -> (Element) ee); } else { return Collections.emptyList(); } @@ -2220,6 +2435,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { private static class SuggestionImpl implements Suggestion { private final String continuation; + private final String filteringText; private final boolean matchesType; /** @@ -2229,7 +2445,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { * @param matchesType does the candidate match the target type */ public SuggestionImpl(String continuation, boolean matchesType) { + this(continuation, continuation, matchesType); + } + + /** + * Create a {@code Suggestion} instance. + * + * @param continuation a candidate continuation of the user's input + * @param filteringText a text that should be used for filtering + * @param matchesType does the candidate match the target type + */ + public SuggestionImpl(String continuation, String filteringText, boolean matchesType) { this.continuation = continuation; + this.filteringText = filteringText; this.matchesType = matchesType; } diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index a710f60aec4..19f7b89a1b3 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -898,4 +898,47 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("p1.|", "p2.", "p3."); } + + @Test + public void testAnnotation() { + assertCompletion("@Deprec|", "Deprecated"); + assertCompletion("@Deprecated(|", "forRemoval = ", "since = "); + assertCompletion("@Deprecated(forRemoval = |", true, "false", "true"); + assertCompletion("@Deprecated(forRemoval = true, |", "since = "); + assertEval("import java.lang.constant.ConstantDescs;"); + assertEval("import static java.lang.constant.ConstantDescs.*;"); + assertEval("@interface Ann1 { public String test(); }"); + assertCompletionIncludesExcludes("@Ann1(test = |", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("CD_char", "byte")); + assertEval("@interface Ann2 { public String[] test(); }"); + assertCompletionIncludesExcludes("@Ann2(test = {|", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("CD_char", "byte")); + assertCompletionIncludesExcludes("@Ann2(test = {|", true, Set.of("INIT_NAME"), Set.of("java.", "ConstantDescs", "CD_char", "byte")); + assertEval("@interface Ann3 { public String value(); }"); + assertCompletionIncludesExcludes("@Ann3(|", Set.of("java.", "ConstantDescs", "INIT_NAME", "value = "), Set.of("CD_char", "byte")); + assertCompletionIncludesExcludes("@Ann3(|", true, Set.of("INIT_NAME", "value = "), Set.of("java.", "ConstantDescs", "CD_char", "byte")); + assertSignature("@Deprecated(|", "boolean Deprecated.forRemoval()", "String Deprecated.since()"); + assertEval("@interface Ann4 { public String[] value(); }"); + assertCompletionIncludesExcludes("@Ann4({|", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("value = ")); + assertEval("@interface Ann5 { public Ann4[] value(); }"); + assertCompletion("@Ann5(|", true, "@Ann4(", "value = "); + assertCompletion("@Ann5({|", true, "@Ann4("); + assertCompletion("@Ann5(|", false); + assertCompletion("@Ann5({|", false); + assertCompletion("@Ann5(@|", true, "@Ann4("); + assertCompletion("@Ann5(v|", true, "value = "); + assertEval("@interface Ann6 { public java.lang.annotation.Retention[] value(); }"); + assertCompletion("@Ann6(|", true, "@java.lang.annotation.Retention(", "value = "); + assertEval("@interface Ann7 { }"); //no attributes + assertEval("@interface Ann8 { public Ann7[] value(); }"); + assertCompletion("@Ann8(|", true, "@Ann7", "value = "); + assertEval("enum En { AA, BB, EE; }"); + assertEval("@interface Ann9 { public En[] value(); }"); + assertCompletion("@Ann9(|", true, "En", "En.AA", "En.BB", "En.EE", "value = "); + assertCompletion("@Ann9(A|", true, "En.AA"); + assertCompletion("@Ann9(E|", true, "En", "En.EE"); + assertCompletionIncludesExcludes("@Ann9(En.|", Set.of("AA", "BB", "EE"), Set.of()); + assertEval("@interface AnnA { public java.lang.annotation.RetentionPolicy[] value(); }"); + assertCompletion("@AnnA(C|", true, "java.lang.annotation.RetentionPolicy.CLASS"); + assertEval("import static java.lang.annotation.RetentionPolicy.*;"); + assertCompletion("@AnnA(C|", true, "CLASS"); + } } diff --git a/test/langtools/jdk/jshell/ToolTabSnippetTest.java b/test/langtools/jdk/jshell/ToolTabSnippetTest.java index 39189da8686..968935b0814 100644 --- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java +++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java @@ -344,4 +344,24 @@ public class ToolTabSnippetTest extends UITesting { waitOutput(out, PROMPT + "new InstantiationE"); }); } + + @Test + public void testAnnotation() throws Exception { + doRunTest((inputSink, out) -> { + inputSink.write("@interface Ann1 { public java.lang.annotation.Retention[] value(); }\n"); + waitOutput(out, "\n\\u001B\\[\\?2004h" + PROMPT); + + //-> + inputSink.write("@Ann1(" + TAB); + waitOutput(out, ".*@java.lang.annotation.Retention\\(.*value =.*" + + REDRAW_PROMPT + "@Ann1\\("); + inputSink.write("@" + TAB); + waitOutput(out, "^@java.lang.annotation.Retention\\("); + inputSink.write(TAB); + waitOutput(out, ".*java.lang.annotation.RetentionPolicy.*java.lang.annotation.RetentionPolicy.CLASS.*" + + REDRAW_PROMPT + "@Ann1\\(@java.lang.annotation.Retention\\("); + inputSink.write("CL" + TAB); + waitOutput(out, "CL\\u001B\\[2Djava.lang.annotation.RetentionPolicy.CLASS \\u0008"); + }); + } } From 063f970f0f5e851d72dad0112735692761d6ba36 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 11 Sep 2025 11:22:12 +0000 Subject: [PATCH 240/295] 8367401: Parallel: Remove unused field in PSKeepAliveClosure Reviewed-by: stefank, fandreuzzi --- src/hotspot/share/gc/parallel/psScavenge.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 3a47d5864f3..ced84061ec5 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -148,15 +148,10 @@ public: PSIsAliveClosure PSScavenge::_is_alive_closure; class PSKeepAliveClosure: public OopClosure { -protected: - MutableSpace* _to_space; PSPromotionManager* _promotion_manager; public: PSKeepAliveClosure(PSPromotionManager* pm) : _promotion_manager(pm) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - _to_space = heap->young_gen()->to_space(); - assert(_promotion_manager != nullptr, "Sanity"); } From a2d272a02a079e2413d10ad2decb04681ce2f961 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 11 Sep 2025 11:22:29 +0000 Subject: [PATCH 241/295] 8367339: Parallel: Remove PSScavenge::should_scavenge Reviewed-by: tschatzl, fandreuzzi --- src/hotspot/share/gc/parallel/psCardTable.cpp | 1 - .../share/gc/parallel/psClosure.inline.hpp | 16 ++--- .../share/gc/parallel/psPromotionManager.cpp | 11 +--- .../share/gc/parallel/psPromotionManager.hpp | 3 - .../gc/parallel/psPromotionManager.inline.hpp | 8 +-- src/hotspot/share/gc/parallel/psScavenge.cpp | 2 +- src/hotspot/share/gc/parallel/psScavenge.hpp | 9 --- .../share/gc/parallel/psScavenge.inline.hpp | 63 ------------------- 8 files changed, 13 insertions(+), 100 deletions(-) delete mode 100644 src/hotspot/share/gc/parallel/psScavenge.inline.hpp diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index 22a38d816f6..3c40726b721 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -26,7 +26,6 @@ #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/psCardTable.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" #include "gc/parallel/psYoungGen.hpp" #include "memory/iterator.inline.hpp" #include "oops/access.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psClosure.inline.hpp b/src/hotspot/share/gc/parallel/psClosure.inline.hpp index 914a16e77a6..825612d598a 100644 --- a/src/hotspot/share/gc/parallel/psClosure.inline.hpp +++ b/src/hotspot/share/gc/parallel/psClosure.inline.hpp @@ -28,7 +28,7 @@ // No psClosure.hpp #include "gc/parallel/psPromotionManager.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "memory/iterator.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" @@ -39,8 +39,9 @@ public: virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } virtual void do_oop(oop* p) { - if (PSScavenge::should_scavenge(p)) { - oop o = RawAccess::oop_load(p); + oop o = RawAccess<>::oop_load(p); + if (PSScavenge::is_obj_in_young(o)) { + assert(!PSScavenge::is_obj_in_to_space(o), "Revisiting roots?"); assert(o->is_forwarded(), "Objects are already forwarded before weak processing"); oop new_obj = o->forwardee(); if (log_develop_is_enabled(Trace, gc, scavenge)) { @@ -89,12 +90,11 @@ public: void do_oop(narrowOop* p) { ShouldNotReachHere(); } void do_oop(oop* p) { - ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); - assert(!psh->is_in_reserved(p), "GC barrier needed"); - if (PSScavenge::should_scavenge(p)) { - assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); + assert(!ParallelScavengeHeap::heap()->is_in_reserved(p), "GC barrier needed"); - oop o = RawAccess::oop_load(p); + oop o = RawAccess<>::oop_load(p); + if (PSScavenge::is_obj_in_young(o)) { + assert(!PSScavenge::is_obj_in_to_space(o), "Revisiting roots?"); oop new_obj = _pm->copy_to_survivor_space(o); RawAccess::oop_store(p, new_obj); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 0a463ab7516..90914d87ba4 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -27,7 +27,7 @@ #include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/partialArraySplitter.inline.hpp" @@ -86,15 +86,6 @@ void PSPromotionManager::initialize() { } } -// Helper functions to get around the circular dependency between -// psScavenge.inline.hpp and psPromotionManager.inline.hpp. -bool PSPromotionManager::should_scavenge(oop* p, bool check_to_space) { - return PSScavenge::should_scavenge(p, check_to_space); -} -bool PSPromotionManager::should_scavenge(narrowOop* p, bool check_to_space) { - return PSScavenge::should_scavenge(p, check_to_space); -} - PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(uint index) { assert(index < ParallelGCThreads, "index out of range"); assert(_manager_array != nullptr, "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index f1169c8ad63..20fe3c74a46 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -167,9 +167,6 @@ class PSPromotionManager { inline void process_popped_location_depth(ScannerTask task, bool stolen); - static bool should_scavenge(oop* p, bool check_to_space = false); - static bool should_scavenge(narrowOop* p, bool check_to_space = false); - template void copy_and_push_safe_barrier(T* p); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 6154abf1b1c..31c1c445a32 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -31,7 +31,7 @@ #include "gc/parallel/parMarkBitMap.inline.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psPromotionLAB.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "gc/parallel/psStringDedup.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" @@ -139,7 +139,8 @@ inline void PSPromotionManager::push_contents_bounded(oop obj, HeapWord* left, H template inline oop PSPromotionManager::copy_to_survivor_space(oop o) { - assert(should_scavenge(&o), "Sanity"); + assert(PSScavenge::is_obj_in_young(o), "precondition"); + assert(!PSScavenge::is_obj_in_to_space(o), "precondition"); // NOTE! We must be very careful with any methods that access the mark // in o. There may be multiple threads racing on it, and it may be forwarded @@ -235,8 +236,6 @@ inline HeapWord* PSPromotionManager::allocate_in_old_gen(Klass* klass, template inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, markWord test_mark) { - assert(should_scavenge(&o), "Sanity"); - oop new_obj = nullptr; bool new_obj_is_tenured = false; @@ -334,7 +333,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, template inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { assert(ParallelScavengeHeap::heap()->is_in_reserved(p), "precondition"); - assert(should_scavenge(p, true), "revisiting object?"); oop o = RawAccess::oop_load(p); oop new_obj = copy_to_survivor_space(o); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index ced84061ec5..62d382b40f0 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -33,7 +33,7 @@ #include "gc/parallel/psParallelCompact.inline.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" #include "gc/parallel/psRootType.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcId.hpp" diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index 8da555a8bb4..c297a46a46e 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -100,15 +100,6 @@ class PSScavenge: AllStatic { // Return true iff a young-gc is completed without promotion-failure. static bool invoke(bool clear_soft_refs); - template static inline bool should_scavenge(T* p); - - // These call should_scavenge() above and, if it returns true, also check that - // the object was not newly copied into to_space. The version with the bool - // argument is a convenience wrapper that fetches the to_space pointer from - // the heap and calls the other version (if the arg is true). - template static inline bool should_scavenge(T* p, MutableSpace* to_space); - template static inline bool should_scavenge(T* p, bool check_to_space); - // Is an object in the young generation // This assumes that the 'o' is in the heap, // so it only checks one side of the complete predicate. diff --git a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp deleted file mode 100644 index af3ff4c6165..00000000000 --- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_PARALLEL_PSSCAVENGE_INLINE_HPP -#define SHARE_GC_PARALLEL_PSSCAVENGE_INLINE_HPP - -#include "gc/parallel/psScavenge.hpp" - -#include "gc/parallel/parallelScavengeHeap.hpp" -#include "logging/log.hpp" -#include "memory/iterator.hpp" -#include "memory/resourceArea.hpp" -#include "oops/access.inline.hpp" -#include "oops/oop.inline.hpp" -#include "utilities/globalDefinitions.hpp" - -template inline bool PSScavenge::should_scavenge(T* p) { - T heap_oop = RawAccess<>::oop_load(p); - return PSScavenge::is_obj_in_young(heap_oop); -} - -template -inline bool PSScavenge::should_scavenge(T* p, MutableSpace* to_space) { - if (should_scavenge(p)) { - oop obj = RawAccess::oop_load(p); - // Skip objects copied to to_space since the scavenge started. - HeapWord* const addr = cast_from_oop(obj); - return addr < to_space->bottom() || addr >= to_space->end(); - } - return false; -} - -template -inline bool PSScavenge::should_scavenge(T* p, bool check_to_space) { - if (check_to_space) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - return should_scavenge(p, heap->young_gen()->to_space()); - } - return should_scavenge(p); -} - -#endif // SHARE_GC_PARALLEL_PSSCAVENGE_INLINE_HPP From 56f2f7a3af0574357d5d3f99dcd908721ac710e9 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 11 Sep 2025 13:22:20 +0000 Subject: [PATCH 242/295] 8367138: JNI exception pending in os_getCmdlineAndUserInfo of ProcessHandleImpl_macosx.c Reviewed-by: bpb, naoto, jpai, lancea --- src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c index 9e1d092c57d..2db64ef37b5 100644 --- a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c +++ b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,6 +263,7 @@ void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) { // on other platforms like Linux/Solaris/AIX where the uid comes from the // same source like the command line info. unix_getUserInfo(env, jinfo, getUID(pid)); + JNU_CHECK_EXCEPTION(env); // Get the maximum size of the arguments mib[0] = CTL_KERN; From 4ea8979b93f80e9ecbc197ee12ceb523ef8da6aa Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Thu, 11 Sep 2025 13:53:08 +0000 Subject: [PATCH 243/295] 8365953: Key manager returns no certificates when handshakeSession is not an ExtendedSSLSession Reviewed-by: djelinski, wetmore --- .../ssl/X509KeyManagerCertChecking.java | 47 +- .../AlgorithmConstraintsCheck.java | 28 +- ...xtendedSSLSessionAlgorithmConstraints.java | 405 ++++++++++++++++++ 3 files changed, 436 insertions(+), 44 deletions(-) create mode 100644 test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java diff --git a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java index 00a7ae84352..6f18b80395a 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java +++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java @@ -167,25 +167,17 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { return null; } - if (socket != null && socket.isConnected() && - socket instanceof SSLSocket sslSocket) { - + if (socket instanceof SSLSocket sslSocket && sslSocket.isConnected()) { SSLSession session = sslSocket.getHandshakeSession(); - if (session != null) { - if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { - String[] peerSupportedSignAlgs = null; - - if (session instanceof ExtendedSSLSession extSession) { - // Peer supported certificate signature algorithms - // sent with "signature_algorithms_cert" TLS extension. - peerSupportedSignAlgs = - extSession.getPeerSupportedSignatureAlgorithms(); - } - - return SSLAlgorithmConstraints.forSocket( - sslSocket, peerSupportedSignAlgs, true); - } + if (session instanceof ExtendedSSLSession extSession + && ProtocolVersion.useTLS12PlusSpec( + extSession.getProtocol())) { + // Use peer supported certificate signature algorithms + // sent with "signature_algorithms_cert" TLS extension. + return SSLAlgorithmConstraints.forSocket(sslSocket, + extSession.getPeerSupportedSignatureAlgorithms(), + true); } return SSLAlgorithmConstraints.forSocket(sslSocket, true); @@ -203,20 +195,15 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { if (engine != null) { SSLSession session = engine.getHandshakeSession(); - if (session != null) { - if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { - String[] peerSupportedSignAlgs = null; - if (session instanceof ExtendedSSLSession extSession) { - // Peer supported certificate signature algorithms - // sent with "signature_algorithms_cert" TLS extension. - peerSupportedSignAlgs = - extSession.getPeerSupportedSignatureAlgorithms(); - } - - return SSLAlgorithmConstraints.forEngine( - engine, peerSupportedSignAlgs, true); - } + if (session instanceof ExtendedSSLSession extSession + && ProtocolVersion.useTLS12PlusSpec( + extSession.getProtocol())) { + // Use peer supported certificate signature algorithms + // sent with "signature_algorithms_cert" TLS extension. + return SSLAlgorithmConstraints.forEngine(engine, + extSession.getPeerSupportedSignatureAlgorithms(), + true); } } diff --git a/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java b/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java index 997fde5a07a..4caa7b6b944 100644 --- a/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java +++ b/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java @@ -57,31 +57,31 @@ import sun.security.x509.X500Name; * @modules java.base/sun.security.x509 * java.base/sun.security.util * @library /test/lib - * @run main/othervm AlgorithmConstraintsCheck false SunX509 SHA256withRSA - * @run main/othervm AlgorithmConstraintsCheck true SunX509 SHA256withRSA - * @run main/othervm AlgorithmConstraintsCheck false PKIX SHA256withRSA - * @run main/othervm AlgorithmConstraintsCheck true PKIX SHA256withRSA + * @run main/othervm AlgorithmConstraintsCheck false SunX509 + * @run main/othervm AlgorithmConstraintsCheck true SunX509 + * @run main/othervm AlgorithmConstraintsCheck false PKIX + * @run main/othervm AlgorithmConstraintsCheck true PKIX */ public class AlgorithmConstraintsCheck { - private static final String CERT_ALIAS = "testalias"; - private static final String KEY_TYPE = "RSA"; + protected static final String CERT_ALIAS = "testalias"; + protected static final String KEY_TYPE = "EC"; + protected static final String CERT_SIG_ALG = "SHA256withECDSA"; public static void main(String[] args) throws Exception { - if (args.length != 3) { + if (args.length != 2) { throw new RuntimeException("Wrong number of arguments"); } String enabled = args[0]; String kmAlg = args[1]; - String certSignatureAlg = args[2]; System.setProperty("jdk.tls.SunX509KeyManager.certChecking", enabled); - SecurityUtils.addToDisabledTlsAlgs(certSignatureAlg); + SecurityUtils.addToDisabledTlsAlgs(CERT_SIG_ALG); X509ExtendedKeyManager km = (X509ExtendedKeyManager) getKeyManager( - kmAlg, certSignatureAlg); + kmAlg, KEY_TYPE, CERT_SIG_ALG); String serverAlias = km.chooseServerAlias(KEY_TYPE, null, null); String engineServerAlias = km.chooseEngineServerAlias( KEY_TYPE, null, null); @@ -108,13 +108,13 @@ public class AlgorithmConstraintsCheck { } // PKIX KeyManager adds a cache prefix to an alias. - private static String normalizeAlias(String alias) { + protected static String normalizeAlias(String alias) { return alias.substring(alias.lastIndexOf(".") + 1); } - private static X509KeyManager getKeyManager(String kmAlg, - String certSignatureAlg) throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_TYPE); + protected static X509KeyManager getKeyManager(String kmAlg, + String keyAlg, String certSignatureAlg) throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlg); KeyPair caKeys = kpg.generateKeyPair(); KeyPair endpointKeys = kpg.generateKeyPair(); diff --git a/test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java b/test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java new file mode 100644 index 00000000000..30ec655f7b2 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * 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 8365953 + * @summary Key manager returns no certificates when handshakeSession is not + * an ExtendedSSLSession + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm NonExtendedSSLSessionAlgorithmConstraints + */ + +import static jdk.test.lib.Asserts.assertEquals; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.Principal; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.X509ExtendedKeyManager; + +/* + * Make sure Key Managers return the certificates when SSLSocket or SSLEngine + * use an SSLSession which is not extending ExtendedSSLSession. + */ +public class NonExtendedSSLSessionAlgorithmConstraints extends + AlgorithmConstraintsCheck { + + public static void main(String[] args) throws Exception { + new NonExtendedSSLSessionAlgorithmConstraints().runTest(); + } + + private void runTest() throws Exception { + for (String kmAlg : new String[]{"SunX509", "PKIX"}) { + + X509ExtendedKeyManager km = + (X509ExtendedKeyManager) getKeyManager( + kmAlg, KEY_TYPE, CERT_SIG_ALG); + var testSocket = new TestHandshakeSessionSSLSocket(); + var testEngine = new TestHandshakeSessionSSLEngine(); + + // Test SSLSocket + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseServerAlias( + KEY_TYPE, null, testSocket))); + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseClientAlias( + new String[]{KEY_TYPE}, null, testSocket))); + + // Test SSLEngine + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseEngineServerAlias( + KEY_TYPE, null, testEngine))); + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseEngineClientAlias( + new String[]{KEY_TYPE}, null, testEngine))); + } + } + + private static class TestHandshakeSessionSSLSocket extends SSLSocket { + + TestHandshakeSessionSSLSocket() { + } + + @Override + public SSLSession getHandshakeSession() { + return new TestSSLSession(); + } + + @Override + public boolean isConnected() { + return true; + } + + @Override + public SSLSession getSession() { + return null; + } + + @Override + public String[] getSupportedCipherSuites() { + return null; + } + + @Override + public String[] getSupportedProtocols() { + return null; + } + + @Override + public String[] getEnabledCipherSuites() { + return null; + } + + @Override + public void setEnabledCipherSuites(String[] suites) { + } + + @Override + public String[] getEnabledProtocols() { + return null; + } + + @Override + public void setEnabledProtocols(String[] protocols) { + } + + @Override + public void addHandshakeCompletedListener + (HandshakeCompletedListener listener) { + } + + @Override + public void removeHandshakeCompletedListener + (HandshakeCompletedListener listener) { + } + + @Override + public void startHandshake() throws IOException { + } + + @Override + public void setUseClientMode(boolean mode) { + } + + @Override + public boolean getUseClientMode() { + return false; + } + + @Override + public void setNeedClientAuth(boolean need) { + } + + @Override + public boolean getNeedClientAuth() { + return false; + } + + @Override + public void setWantClientAuth(boolean want) { + } + + @Override + public boolean getWantClientAuth() { + return false; + } + + @Override + public void setEnableSessionCreation(boolean flag) { + } + + @Override + public boolean getEnableSessionCreation() { + return true; + } + } + + private static class TestHandshakeSessionSSLEngine extends SSLEngine { + + @Override + public SSLSession getHandshakeSession() { + return new TestSSLSession(); + } + + @Override + public String[] getEnabledProtocols() { + return null; + } + + @Override + public SSLEngineResult wrap(ByteBuffer[] src, int off, int len, + ByteBuffer dst) throws SSLException { + return null; + } + + @Override + public SSLEngineResult unwrap(ByteBuffer src, + ByteBuffer[] dst, int off, int len) + throws SSLException { + return null; + } + + @Override + public Runnable getDelegatedTask() { + return null; + } + + @Override + public void closeInbound() { + } + + @Override + public boolean isInboundDone() { + return false; + } + + @Override + public void closeOutbound() { + } + + @Override + public boolean isOutboundDone() { + return false; + } + + @Override + public String[] getEnabledCipherSuites() { + return null; + } + + @Override + public String[] getSupportedCipherSuites() { + return null; + } + + @Override + public void setEnabledCipherSuites(String[] suites) { + } + + @Override + public String[] getSupportedProtocols() { + return null; + } + + @Override + public void setEnabledProtocols(String[] protocols) { + } + + @Override + public SSLSession getSession() { + return null; + } + + @Override + public void beginHandshake() { + } + + @Override + public SSLEngineResult.HandshakeStatus getHandshakeStatus() { + return null; + } + + @Override + public void setUseClientMode(boolean mode) { + } + + @Override + public boolean getUseClientMode() { + return false; + } + + public void setNeedClientAuth(boolean need) { + } + + @Override + public boolean getNeedClientAuth() { + return false; + } + + @Override + public void setWantClientAuth(boolean need) { + } + + @Override + public boolean getWantClientAuth() { + return false; + } + + @Override + public void setEnableSessionCreation(boolean flag) { + } + + @Override + public boolean getEnableSessionCreation() { + return false; + } + } + + public static class TestSSLSession implements SSLSession { + + TestSSLSession() { + } + + @Override + public String getProtocol() { + return "TLSv1.3"; + } + + @Override + public byte[] getId() { + return null; + } + + @Override + public SSLSessionContext getSessionContext() { + return null; + } + + @Override + public long getCreationTime() { + return 0; + } + + @Override + public long getLastAccessedTime() { + return 0; + } + + @Override + public void invalidate() { + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public void putValue(String name, Object value) { + } + + @Override + public Object getValue(String name) { + return null; + } + + @Override + public void removeValue(String name) { + } + + @Override + public String[] getValueNames() { + return null; + } + + @Override + public java.security.cert.Certificate[] getPeerCertificates() { + return new java.security.cert.Certificate[0]; + } + + @Override + public java.security.cert.Certificate[] getLocalCertificates() { + return new java.security.cert.Certificate[0]; + } + + @Override + public Principal getPeerPrincipal() { + return null; + } + + @Override + public Principal getLocalPrincipal() { + return null; + } + + @Override + public String getCipherSuite() { + return null; + } + + @Override + public String getPeerHost() { + return null; + } + + @Override + public int getPeerPort() { + return 0; + } + + @Override + public int getPacketBufferSize() { + return 0; + } + + @Override + public int getApplicationBufferSize() { + return 0; + } + } +} From 781f2b2f8188c02a6af220ebcc5bc8158fe8423e Mon Sep 17 00:00:00 2001 From: Pasam Soujanya Date: Thu, 11 Sep 2025 13:58:51 +0000 Subject: [PATCH 244/295] 8366278: Form control element + + + """; + Document doc = kit.createDefaultDocument(); + editorPane.setDocument(doc); + editorPane.setText(htmlString); + + frame.add(scrollPane, BorderLayout.CENTER); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(new Dimension(400, 200)); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean containsAlt(Container container) { + for (Component c : container.getComponents()) { + if (c instanceof JButton button) { + return "Logo".equals(button.getText()); + } else if (c instanceof Container cont) { + return containsAlt(cont); + } + } + return false; + } +} From 64155dfac068cf01bcab6adb401b360499f33a5f Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 15 Sep 2025 21:10:26 +0000 Subject: [PATCH 287/295] 8367237: Thread-Safety Usage Warning for java.text.Collator Classes Reviewed-by: iris, naoto --- src/java.base/share/classes/java/text/Collator.java | 9 +++++++-- .../share/classes/java/text/RuleBasedCollator.java | 11 ++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/text/Collator.java b/src/java.base/share/classes/java/text/Collator.java index 276a66cdc07..5e576cd800f 100644 --- a/src/java.base/share/classes/java/text/Collator.java +++ b/src/java.base/share/classes/java/text/Collator.java @@ -111,8 +111,13 @@ import sun.util.locale.provider.LocaleServiceProviderPool; *
          * @apiNote {@code CollationKey}s from different * {@code Collator}s can not be compared. See the class description - * for {@link CollationKey} - * for an example using {@code CollationKey}s. + * for {@link CollationKey} for an example using {@code CollationKey}s. + * + * @implNote Significant thread contention may occur during concurrent usage + * of the JDK Reference Implementation's {@link RuleBasedCollator}, which is the + * subtype returned by the default provider of the {@link #getInstance()} factory + * methods. As such, users should consider retrieving a separate instance for + * each thread when used in multithreaded environments. * * @see RuleBasedCollator * @see CollationKey diff --git a/src/java.base/share/classes/java/text/RuleBasedCollator.java b/src/java.base/share/classes/java/text/RuleBasedCollator.java index dc45dafb846..af1b6b62bdf 100644 --- a/src/java.base/share/classes/java/text/RuleBasedCollator.java +++ b/src/java.base/share/classes/java/text/RuleBasedCollator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 +38,6 @@ package java.text; -import java.text.Normalizer; -import java.util.Vector; -import java.util.Locale; - /** * The {@code RuleBasedCollator} class is a concrete subclass of * {@code Collator} that provides a simple, data-driven, table @@ -239,6 +235,11 @@ import java.util.Locale; * * * + * @implNote For this implementation, concurrent usage of this class may + * lead to significant thread contention since {@code synchronized} is employed + * to ensure thread-safety. As such, users of this class should consider creating + * a separate instance for each thread when used in multithreaded environments. + * * @see Collator * @see CollationElementIterator * @author Helena Shih, Laura Werner, Richard Gillam From 242558484985cb954b0e658776fd59cbca1be1db Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 16 Sep 2025 01:04:48 +0000 Subject: [PATCH 288/295] 8367142: Avoid InstanceKlass::cast when converting java mirror to InstanceKlass Reviewed-by: dholmes, coleenp --- src/hotspot/share/cds/aotMetaspace.cpp | 4 +- src/hotspot/share/cds/unregisteredClasses.cpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 27 +++--- src/hotspot/share/classfile/javaClasses.hpp | 12 +-- .../share/classfile/javaClasses.inline.hpp | 6 ++ .../share/classfile/systemDictionary.cpp | 4 +- .../jfr/leakprofiler/chains/edgeUtils.cpp | 2 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 2 +- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/prims/jvm.cpp | 82 +++++++------------ src/hotspot/share/prims/methodHandles.cpp | 2 +- src/hotspot/share/prims/unsafe.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 26 +++--- src/hotspot/share/runtime/reflection.cpp | 4 +- src/hotspot/share/runtime/sharedRuntime.cpp | 4 +- 15 files changed, 80 insertions(+), 101 deletions(-) diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 01bc4708eb5..b3f859fc4a8 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -785,7 +785,7 @@ void AOTMetaspace::link_all_loaded_classes(JavaThread* current) { const GrowableArray* mirrors = collect_classes.mirrors(); for (int i = 0; i < mirrors->length(); i++) { OopHandle mirror = mirrors->at(i); - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror.resolve()); if (may_be_eagerly_linked(ik)) { has_linked |= try_link_class(current, ik); } @@ -812,7 +812,7 @@ void AOTMetaspace::link_shared_classes(TRAPS) { const GrowableArray* mirrors = collect_classes.mirrors(); for (int i = 0; i < mirrors->length(); i++) { OopHandle mirror = mirrors->at(i); - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror.resolve()); AOTConstantPoolResolver::preresolve_string_cp_entries(ik, CHECK); } } diff --git a/src/hotspot/share/cds/unregisteredClasses.cpp b/src/hotspot/share/cds/unregisteredClasses.cpp index 31cfbd15d67..51b35899599 100644 --- a/src/hotspot/share/cds/unregisteredClasses.cpp +++ b/src/hotspot/share/cds/unregisteredClasses.cpp @@ -94,7 +94,7 @@ InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, T CHECK_NULL); assert(result.get_type() == T_OBJECT, "just checking"); - return InstanceKlass::cast(java_lang_Class::as_Klass(result.get_oop())); + return java_lang_Class::as_InstanceKlass(result.get_oop()); } bool UnregisteredClasses::check_for_exclusion(const InstanceKlass* k) { diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 86a3b22fbbb..da093936ce5 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -990,7 +990,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK); } -void java_lang_Class::initialize_mirror_fields(Klass* k, +void java_lang_Class::initialize_mirror_fields(InstanceKlass* ik, Handle mirror, Handle protection_domain, Handle classData, @@ -1005,7 +1005,7 @@ void java_lang_Class::initialize_mirror_fields(Klass* k, set_protection_domain(mirror(), protection_domain()); // Initialize static fields - InstanceKlass::cast(k)->do_local_static_fields(&initialize_static_field, mirror, CHECK); + ik->do_local_static_fields(&initialize_static_field, mirror, CHECK); // Set classData set_class_data(mirror(), classData()); @@ -1111,8 +1111,7 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // and java_mirror in this klass. } else { assert(k->is_instance_klass(), "Must be"); - - initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD); + initialize_mirror_fields(InstanceKlass::cast(k), mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field // from the mirror so GC doesn't follow it after the klass has been deallocated. @@ -2590,7 +2589,7 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m ResourceMark rm; stringStream ss; - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); + InstanceKlass* holder = java_lang_Class::as_InstanceKlass(mirror()); const char* klass_name = holder->external_name(); char* method_name = name->as_C_string(); ss.print("\tat %s.%s(", klass_name, method_name); @@ -2969,7 +2968,7 @@ void java_lang_Throwable::get_stack_trace_elements(int depth, Handle backtrace, THROW(vmSymbols::java_lang_NullPointerException()); } - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror())); + InstanceKlass* holder = java_lang_Class::as_InstanceKlass(bte._mirror()); methodHandle method (THREAD, holder->method_with_orig_idnum(bte._method_id, bte._version)); java_lang_StackTraceElement::fill_in(stack_trace_element, holder, @@ -3055,7 +3054,7 @@ bool java_lang_Throwable::get_top_method_and_bci(oop throwable, Method** method, // Get first backtrace element. BacktraceElement bte = iter.next(current); - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror())); + InstanceKlass* holder = java_lang_Class::as_InstanceKlass(bte._mirror()); assert(holder != nullptr, "first element should be non-null"); Method* m = holder->method_with_orig_idnum(bte._method_id, bte._version); @@ -3441,11 +3440,11 @@ void java_lang_reflect_Method::serialize_offsets(SerializeClosure* f) { Handle java_lang_reflect_Method::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); - Klass* klass = vmClasses::reflect_Method_klass(); + InstanceKlass* klass = vmClasses::reflect_Method_klass(); // This class is eagerly initialized during VM initialization, since we keep a reference // to one of the methods - assert(InstanceKlass::cast(klass)->is_initialized(), "must be initialized"); - return InstanceKlass::cast(klass)->allocate_instance_handle(THREAD); + assert(klass->is_initialized(), "must be initialized"); + return klass->allocate_instance_handle(THREAD); } oop java_lang_reflect_Method::clazz(oop reflect) { @@ -3914,17 +3913,15 @@ void reflect_ConstantPool::set_cp(oop reflect, ConstantPool* value) { } ConstantPool* reflect_ConstantPool::get_cp(oop reflect) { - oop mirror = reflect->obj_field(_oop_offset); - Klass* k = java_lang_Class::as_Klass(mirror); - assert(k->is_instance_klass(), "Must be"); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); // Get the constant pool back from the klass. Since class redefinition // merges the new constant pool into the old, this is essentially the // same constant pool as the original. If constant pool merging is // no longer done in the future, this will have to change to save // the original. - return InstanceKlass::cast(k)->constants(); + return ik->constants(); } @@ -5531,7 +5528,7 @@ void JavaClasses::check_offsets() { #endif // PRODUCT int InjectedField::compute_offset() { - InstanceKlass* ik = InstanceKlass::cast(klass()); + InstanceKlass* ik = klass(); for (AllFieldStream fs(ik); !fs.done(); fs.next()) { if (!may_be_java && !fs.field_flags().is_injected()) { // Only look at injected fields diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 70fa519f0f0..6f82ca10fd6 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -269,7 +269,7 @@ class java_lang_Class : AllStatic { 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); - static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, + static void initialize_mirror_fields(InstanceKlass* ik, Handle mirror, Handle protection_domain, Handle classData, TRAPS); static void set_mirror_module_field(JavaThread* current, Klass* K, Handle mirror, Handle module); public: @@ -293,8 +293,10 @@ class java_lang_Class : AllStatic { static void fixup_module_field(Klass* k, Handle module); - // Conversion + // Conversion -- java_class must not be null. The return value is null only if java_class is a primitive type. static Klass* as_Klass(oop java_class); + static InstanceKlass* as_InstanceKlass(oop java_class); + static void set_klass(oop java_class, Klass* klass); static BasicType as_BasicType(oop java_class, Klass** reference_klass = nullptr); static Symbol* as_signature(oop java_class, bool intern_if_not_found); @@ -1895,11 +1897,11 @@ class InjectedField { const vmClassID klass_id; const vmSymbolID name_index; const vmSymbolID signature_index; - const bool may_be_java; + const bool may_be_java; - Klass* klass() const { return vmClasses::klass_at(klass_id); } - Symbol* name() const { return lookup_symbol(name_index); } + InstanceKlass* klass() const { return vmClasses::klass_at(klass_id); } + Symbol* name() const { return lookup_symbol(name_index); } Symbol* signature() const { return lookup_symbol(signature_index); } int compute_offset(); diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp index 3cbbd2c12f2..21ad62f8408 100644 --- a/src/hotspot/share/classfile/javaClasses.inline.hpp +++ b/src/hotspot/share/classfile/javaClasses.inline.hpp @@ -291,6 +291,12 @@ inline Klass* java_lang_Class::as_Klass(oop java_class) { return k; } +inline InstanceKlass* java_lang_Class::as_InstanceKlass(oop java_class) { + Klass* k = as_Klass(java_class); + assert(k == nullptr || k->is_instance_klass(), "type check"); + return static_cast(k); +} + inline bool java_lang_Class::is_primitive(oop java_class) { // should assert: // assert(java_lang_Class::is_instance(java_class), "must be a Class object"); diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 22d4fd1892e..95f86a8950b 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1277,10 +1277,10 @@ InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Ha assert(result.get_type() == T_OBJECT, "just checking"); oop obj = result.get_oop(); - // Primitive classes return null since forName() can not be + // Primitive classes return null since forName() cannot be // used to obtain any of the Class objects representing primitives or void if ((obj != nullptr) && !(java_lang_Class::is_primitive(obj))) { - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(obj)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(obj); // For user defined Java class loaders, check that the name returned is // the same as that requested. This check is done for the bootstrap // loader when parsing the class file. diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index d431d98e383..da098634ba6 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -65,7 +65,7 @@ const Symbol* EdgeUtils::field_name(const Edge& edge, jshort* modifiers) { if (is_static_field(ref_owner, ik, offset)) { assert(ik->is_mirror_instance_klass(), "invariant"); assert(java_lang_Class::as_Klass(ref_owner)->is_instance_klass(), "invariant"); - ik = InstanceKlass::cast(java_lang_Class::as_Klass(ref_owner)); + ik = java_lang_Class::as_InstanceKlass(ref_owner); } while (ik != nullptr) { JavaFieldStream jfs(ik); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c7c3a00a127..137782f93ef 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -187,7 +187,7 @@ JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_or_null(JavaThread* current, oop JRT_END JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_or_null(JavaThread* current, oopDesc* type_mirror)) - InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(type_mirror)); + InstanceKlass* klass = java_lang_Class::as_InstanceKlass(type_mirror); if (klass == nullptr) { ResourceMark rm(current); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 0e469dd7f84..34d2d614d22 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -526,7 +526,7 @@ JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message)) jint ret = JNI_OK; DT_RETURN_MARK(ThrowNew, jint, (const jint&)ret); - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(clazz)); Symbol* name = k->name(); Handle class_loader (THREAD, k->class_loader()); THROW_MSG_LOADER_(name, (char *)message, class_loader, JNI_OK); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index daacfd4ab7a..2cbe764994d 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -840,14 +840,9 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, if (log_is_enabled(Debug, class, resolve) && result != nullptr) { // this function is generally only used for class loading during verification. ResourceMark rm; - oop from_mirror = JNIHandles::resolve_non_null(from); - Klass* from_class = java_lang_Class::as_Klass(from_mirror); - const char * from_name = from_class->external_name(); - - oop mirror = JNIHandles::resolve_non_null(result); - Klass* to_class = java_lang_Class::as_Klass(mirror); - const char * to = to_class->external_name(); - log_debug(class, resolve)("%s %s (verification)", from_name, to); + const char* from_name = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(from))->external_name(); + const char* to_name = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))->external_name(); + log_debug(class, resolve)("%s %s (verification)", from_name, to_name); } #if INCLUDE_CDS @@ -918,12 +913,12 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, jboolean init, int flags, jobject classData, TRAPS) { ResourceMark rm(THREAD); - Klass* lookup_k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(lookup)); - // Lookup class must be a non-null instance + InstanceKlass* lookup_k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(lookup)); + // Lookup class must not be a primitive class (whose mirror has a null Klass*) if (lookup_k == nullptr) { + // The error message is wrong. We come here only if lookup is a primitive class THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null"); } - assert(lookup_k->is_instance_klass(), "Lookup class must be an instance klass"); Handle class_loader (THREAD, lookup_k->class_loader()); @@ -934,7 +929,7 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, InstanceKlass* host_class = nullptr; if (is_nestmate) { - host_class = InstanceKlass::cast(lookup_k)->nest_host(CHECK_NULL); + host_class = lookup_k->nest_host(CHECK_NULL); } log_info(class, nestmates)("LookupDefineClass: %s - %s%s, %s, %s, %s", @@ -1265,7 +1260,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) return (jobjectArray)JNIHandles::make_local(THREAD, result); } - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(ofMirror); InnerClassesIterator iter(k); if (iter.length() == 0) { @@ -1404,11 +1399,10 @@ static bool jvm_get_field_common(jobject field, fieldDescriptor& fd) { oop reflected = JNIHandles::resolve_non_null(field); oop mirror = java_lang_reflect_Field::clazz(reflected); - Klass* k = java_lang_Class::as_Klass(mirror); int slot = java_lang_reflect_Field::slot(reflected); int modifiers = java_lang_reflect_Field::modifiers(reflected); - InstanceKlass* ik = InstanceKlass::cast(k); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); int offset = ik->field_offset(slot); if (modifiers & JVM_ACC_STATIC) { @@ -1444,9 +1438,9 @@ static Method* jvm_get_method_common(jobject method) { mirror = java_lang_reflect_Method::clazz(reflected); slot = java_lang_reflect_Method::slot(reflected); } - Klass* k = java_lang_Class::as_Klass(mirror); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); - Method* m = InstanceKlass::cast(k)->method_with_idnum(slot); + Method* m = ik->method_with_idnum(slot); assert(m != nullptr, "cannot find method"); return m; // caller has to deal with null in product mode } @@ -1570,7 +1564,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, return (jobjectArray) JNIHandles::make_local(THREAD, res); } - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(ofMirror); constantPoolHandle cp(THREAD, k->constants()); // Ensure class is linked @@ -1627,9 +1621,7 @@ JVM_END // even if the class is not a record. JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass)) { - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ik = InstanceKlass::cast(c); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(ofClass)); Array* components = ik->record_components(); if (components != nullptr) { @@ -1671,7 +1663,7 @@ static jobjectArray get_class_declared_methods_helper( return (jobjectArray) JNIHandles::make_local(THREAD, res); } - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(ofMirror); // Ensure class is linked k->link_class(CHECK_NULL); @@ -1750,23 +1742,17 @@ JVM_END JVM_ENTRY(jboolean, JVM_AreNestMates(JNIEnv *env, jclass current, jclass member)) { - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ck = InstanceKlass::cast(c); - Klass* m = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(member)); - assert(m->is_instance_klass(), "must be"); - InstanceKlass* mk = InstanceKlass::cast(m); - return ck->has_nestmate_access_to(mk, THREAD); + InstanceKlass* c = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(current)); + InstanceKlass* m = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(member)); + return c->has_nestmate_access_to(m, THREAD); } JVM_END JVM_ENTRY(jclass, JVM_GetNestHost(JNIEnv* env, jclass current)) { // current is not a primitive or array class - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ck = InstanceKlass::cast(c); - InstanceKlass* host = ck->nest_host(THREAD); + InstanceKlass* c = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(current)); + InstanceKlass* host = c->nest_host(THREAD); return (jclass) (host == nullptr ? nullptr : JNIHandles::make_local(THREAD, host->java_mirror())); } @@ -1776,13 +1762,11 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current)) { // current is not a primitive or array class ResourceMark rm(THREAD); - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ck = InstanceKlass::cast(c); - InstanceKlass* host = ck->nest_host(THREAD); + InstanceKlass* c = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(current)); + InstanceKlass* host = c->nest_host(THREAD); log_trace(class, nestmates)("Calling GetNestMembers for type %s with nest-host %s", - ck->external_name(), host->external_name()); + c->external_name(), host->external_name()); { JvmtiVMObjectAllocEventCollector oam; Array* members = host->nest_members(); @@ -1845,7 +1829,7 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current)) } } else { - assert(host == ck || ck->is_hidden(), "must be singleton nest or dynamic nestmate"); + assert(host == c || c->is_hidden(), "must be singleton nest or dynamic nestmate"); } return (jobjectArray)JNIHandles::make_local(THREAD, result()); } @@ -1856,9 +1840,8 @@ JVM_ENTRY(jobjectArray, JVM_GetPermittedSubclasses(JNIEnv* env, jclass current)) { oop mirror = JNIHandles::resolve_non_null(current); assert(!java_lang_Class::is_primitive(mirror), "should not be"); - Klass* c = java_lang_Class::as_Klass(mirror); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ik = InstanceKlass::cast(c); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); + ResourceMark rm(THREAD); log_trace(class, sealed)("Calling GetPermittedSubclasses for %s type %s", ik->is_sealed() ? "sealed" : "non-sealed", ik->external_name()); @@ -3379,16 +3362,14 @@ JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env, return; } - Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); - InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); + InstanceKlass* caller_ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(caller)); if (caller_ik->is_hidden()) { // Hidden classes not of type lambda proxy classes are currently not being archived. // If the caller_ik is of one of the above types, the corresponding lambda proxy class won't be // registered for archiving. return; } - Klass* lambda_k = java_lang_Class::as_Klass(JNIHandles::resolve(lambdaProxyClass)); - InstanceKlass* lambda_ik = InstanceKlass::cast(lambda_k); + InstanceKlass* lambda_ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(lambdaProxyClass)); assert(lambda_ik->is_hidden(), "must be a hidden class"); assert(!lambda_ik->is_non_strong_hidden(), "expected a strong hidden class"); @@ -3428,8 +3409,7 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, THROW_(vmSymbols::java_lang_NullPointerException(), nullptr); } - Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); - InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); + InstanceKlass* caller_ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(caller)); if (!caller_ik->in_aot_cache()) { // there won't be a shared lambda class if the caller_ik is not in the shared archive. return nullptr; @@ -3825,11 +3805,7 @@ JVM_ENTRY(jint, JVM_GetClassFileVersion(JNIEnv* env, jclass current)) // return latest major version and minor version of 0. return JVM_CLASSFILE_MAJOR_VERSION; } - assert(!java_lang_Class::as_Klass(mirror)->is_array_klass(), "unexpected array class"); - - Klass* c = java_lang_Class::as_Klass(mirror); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ik = InstanceKlass::cast(c); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); return (ik->minor_version() << 16) | ik->major_version(); JVM_END diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index c46b46b1af1..b13bd392eaa 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -902,7 +902,7 @@ void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) { if (clazz == nullptr) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand (as field)"); } - InstanceKlass* defc = InstanceKlass::cast(java_lang_Class::as_Klass(clazz)); + InstanceKlass* defc = java_lang_Class::as_InstanceKlass(clazz); DEBUG_ONLY(clazz = nullptr); // safety intptr_t vmindex = java_lang_invoke_MemberName::vmindex(mname()); bool is_static = ((flags & JVM_ACC_STATIC) != 0); diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 4b2ffd57860..c950690e8ab 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -489,7 +489,7 @@ static jlong find_known_instance_field_offset(jclass clazz, jstring name, TRAPS) ResourceMark rm(THREAD); char *utf_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(name)); - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(clazz)); jint offset = -1; // Not found for (JavaFieldStream fs(k); !fs.done(); fs.next()) { diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index afaa089e0b2..ce559d47b24 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1156,7 +1156,7 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec WB_END WB_ENTRY(jboolean, WB_EnqueueInitializerForCompilation(JNIEnv* env, jobject o, jclass klass, jint comp_level)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); Method* clinit = ik->class_initializer(); if (clinit == nullptr || clinit->method_holder()->is_not_initialized()) { return false; @@ -1936,18 +1936,18 @@ WB_ENTRY(void, WB_ForceClassLoaderStatsSafepoint(JNIEnv* env, jobject wb)) WB_END WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); return (jlong) ik->constants(); WB_END WB_ENTRY(jobjectArray, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); objArrayOop resolved_refs= ik->constants()->resolved_references(); return (jobjectArray)JNIHandles::make_local(THREAD, resolved_refs); WB_END WB_ENTRY(jint, WB_getFieldEntriesLength(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1956,7 +1956,7 @@ WB_ENTRY(jint, WB_getFieldEntriesLength(JNIEnv* env, jobject wb, jclass klass)) WB_END WB_ENTRY(jint, WB_getFieldCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1965,7 +1965,7 @@ WB_ENTRY(jint, WB_getFieldCPIndex(JNIEnv* env, jobject wb, jclass klass, jint in WB_END WB_ENTRY(jint, WB_getMethodEntriesLength(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1974,7 +1974,7 @@ WB_ENTRY(jint, WB_getMethodEntriesLength(JNIEnv* env, jobject wb, jclass klass)) WB_END WB_ENTRY(jint, WB_getMethodCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1983,7 +1983,7 @@ WB_ENTRY(jint, WB_getMethodCPIndex(JNIEnv* env, jobject wb, jclass klass, jint i WB_END WB_ENTRY(jint, WB_getIndyInfoLength(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1992,7 +1992,7 @@ WB_ENTRY(jint, WB_getIndyInfoLength(JNIEnv* env, jobject wb, jclass klass)) WB_END WB_ENTRY(jint, WB_getIndyCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -2386,10 +2386,8 @@ int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { assert(field_name != nullptr && strlen(field_name) > 0, "Field name not valid"); - //Get the class of our object - Klass* arg_klass = object->klass(); - //Turn it into an instance-klass - InstanceKlass* ik = InstanceKlass::cast(arg_klass); + //Only non-array oops have fields. Don't call this function on arrays! + InstanceKlass* ik = InstanceKlass::cast(object->klass()); //Create symbols to look for in the class TempNewSymbol name_symbol = SymbolTable::new_symbol(field_name); @@ -3065,7 +3063,7 @@ JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass)) { if (WhiteBoxAPI) { // Make sure that wbclass is loaded by the null classloader - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(wbclass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(wbclass)); Handle loader(THREAD, ik->class_loader()); if (loader.is_null()) { WhiteBox::register_methods(env, wbclass, thread, methods, sizeof(methods) / sizeof(methods[0])); diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index a7b468c57a3..7728643c640 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1136,7 +1136,7 @@ oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle rtype = T_OBJECT; } - InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); + InstanceKlass* klass = java_lang_Class::as_InstanceKlass(mirror); Method* m = klass->method_with_idnum(slot); if (m == nullptr) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "invoke"); @@ -1153,7 +1153,7 @@ oop Reflection::invoke_constructor(oop constructor_mirror, objArrayHandle args, bool override = java_lang_reflect_Constructor::override(constructor_mirror) != 0; objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Constructor::parameter_types(constructor_mirror))); - InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); + InstanceKlass* klass = java_lang_Class::as_InstanceKlass(mirror); Method* m = klass->method_with_idnum(slot); if (m == nullptr) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "invoke"); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index b7ad8081c52..2f7161ff744 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -881,8 +881,8 @@ void SharedRuntime::throw_StackOverflowError_common(JavaThread* current, bool de // We avoid using the normal exception construction in this case because // it performs an upcall to Java, and we're already out of stack space. JavaThread* THREAD = current; // For exception macros. - Klass* k = vmClasses::StackOverflowError_klass(); - oop exception_oop = InstanceKlass::cast(k)->allocate_instance(CHECK); + InstanceKlass* k = vmClasses::StackOverflowError_klass(); + oop exception_oop = k->allocate_instance(CHECK); if (delayed) { java_lang_Throwable::set_message(exception_oop, Universe::delayed_stack_overflow_error_message()); From 90e81c2bee86f404250fb9b833d43b18190b5272 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 16 Sep 2025 01:11:04 +0000 Subject: [PATCH 289/295] 8367616: RISC-V: Auto-enable Zicboz extension for debug builds Reviewed-by: fyang, fjiang --- src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 3d771123f12..3e5fb4610de 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -191,6 +191,9 @@ void RiscvHwprobe::add_features_from_query_result() { VM_Version::ext_Zbs.enable_feature(); } #ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICBOZ)) { + VM_Version::ext_Zicboz.enable_feature(); + } if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBKB)) { VM_Version::ext_Zbkb.enable_feature(); } From 0fbae8050b6f853053c7dee6a43d3ffbcfa69954 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 16 Sep 2025 04:42:50 +0000 Subject: [PATCH 290/295] 8252582: HotSpot Style Guide should permit variable templates Reviewed-by: dholmes, stefank, kvn --- doc/hotspot-style.html | 45 +++++++++++++++++++++++------------------- doc/hotspot-style.md | 33 +++++++++++++++++-------------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index fb4cffc9d43..7be6867b3ca 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -86,8 +86,9 @@ values
        • thread_local
        • nullptr
        • <atomic>
        • -
        • Inline -Variables
        • +
        • Variable Templates and +Inline Variables
        • Initializing variables with static storage duration
        • @@ -937,12 +938,18 @@ differ from what the Java compilers implement.

          "conservative" memory ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering.

          -

          Inline Variables

          -

          Variables with static storage duration may be declared -inline (p0386r2). -This has similar effects as for declaring a function inline: it can be -defined, identically, in multiple translation units, must be defined in -every translation unit in which it is Variable Templates and +Inline Variables +

          The use of variable templates (including static data member +templates) (N3651) is permitted. +They provide parameterized variables and constants in a simple and +direct form, instead of requiring the use of various workarounds.

          +

          Variables with static storage duration and variable templates may be +declared inline (p0386r2), and this usage is +permitted. This has similar effects as for declaring a function inline: +it can be defined, identically, in multiple translation units, must be +defined in every translation unit in which it is ODR used, and the behavior of the program is as if there is exactly one variable.

          @@ -955,16 +962,17 @@ initializations can make initialization order problems worse. The few ordering constraints that exist for non-inline variables don't apply, as there isn't a single program-designated translation unit containing the definition.

          -

          A constexpr static data member is implicitly -inline. As a consequence, an A constexpr static data member or static data member +template is implicitly inline. As a consequence, an ODR use of such a variable doesn't -require a definition in some .cpp file. (This is a change from -pre-C++17. Beginning with C++17, such a definition is considered a -duplicate definition, and is deprecated.)

          -

          Declaring a thread_local variable inline is -forbidden for HotSpot code. The use of -thread_local is already heavily restricted.

          +title="One Definition Rule">ODR use of such a member doesn't require +a definition in some .cpp file. (This is a change from pre-C++17. +Beginning with C++17, such a definition is considered a duplicate +definition, and is deprecated.)

          +

          Declaring a thread_local variable template or +inline variable is forbidden in HotSpot code. The use of thread_local is already +heavily restricted.

          Initializing variables with static storage duration

          @@ -1853,9 +1861,6 @@ Features
          • Trailing return type syntax for functions (n2541)

          • -
          • Variable templates (n3651, p0127r2)

          • Member initializers and aggregates (n3653)

          • Rvalue references and move semantics

          • diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 3fd5468d531..facdf68462f 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -856,14 +856,19 @@ ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering. -### Inline Variables +### Variable Templates and Inline Variables -Variables with static storage duration may be declared `inline` -([p0386r2](https://wg21.link/p0386r2)). This has similar effects as for -declaring a function inline: it can be defined, identically, in multiple -translation units, must be defined in every translation unit in which it is -[ODR used][ODR], and the behavior of the program is as if there is exactly one -variable. +The use of variable templates (including static data member templates) +([N3651](https://wg21.link/N3651)) is permitted. They provide parameterized +variables and constants in a simple and direct form, instead of requiring the +use of various workarounds. + +Variables with static storage duration and variable templates may be declared +`inline` ([p0386r2](https://wg21.link/p0386r2)), and this usage is +permitted. This has similar effects as for declaring a function inline: it can +be defined, identically, in multiple translation units, must be defined in +every translation unit in which it is [ODR used][ODR], and the behavior of the +program is as if there is exactly one variable. Declaring a variable inline allows the complete definition to be in a header file, rather than having a declaration in a header and the definition in a @@ -874,13 +879,15 @@ make initialization order problems worse. The few ordering constraints that exist for non-inline variables don't apply, as there isn't a single program-designated translation unit containing the definition. -A `constexpr` static data member is implicitly `inline`. As a consequence, an -[ODR use][ODR] of such a variable doesn't require a definition in some .cpp +A `constexpr` static data member or static data member template +is implicitly `inline`. As a consequence, an +[ODR use][ODR] of such a member doesn't require a definition in some .cpp file. (This is a change from pre-C++17. Beginning with C++17, such a definition is considered a duplicate definition, and is deprecated.) -Declaring a `thread_local` variable `inline` is forbidden for HotSpot code. -[The use of `thread_local`](#thread_local) is already heavily restricted. +Declaring a `thread_local` variable template or `inline` variable is forbidden +in HotSpot code. [The use of `thread_local`](#thread_local) is already +heavily restricted. ### Initializing variables with static storage duration @@ -1849,10 +1856,6 @@ See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8 * Trailing return type syntax for functions ([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)) -* Variable templates -([n3651](https://isocpp.org/files/papers/N3651.pdf), -[p0127r2](http://wg21.link/p0127r2)) - * Member initializers and aggregates ([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html)) From 76e464bcd56dab6ef0dfd917f87fdedeb9f838b4 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 16 Sep 2025 05:06:17 +0000 Subject: [PATCH 291/295] 8367150: Add a header line to improve VMErrorCallback printing Reviewed-by: stefank, ayang --- src/hotspot/share/utilities/vmError.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 357bf111804..0fbd8ed4259 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1143,9 +1143,11 @@ void VMError::report(outputStream* st, bool _verbose) { } STEP_IF("printing registered callbacks", _verbose && _thread != nullptr); + size_t count = 0; for (VMErrorCallback* callback = _thread->_vm_error_callbacks; callback != nullptr; callback = callback->_next) { + st->print_cr("VMErrorCallback %zu:", ++count); callback->call(st); st->cr(); } From 60e9222fe147413f20c140f2c00541b6472dfaa4 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 16 Sep 2025 06:30:53 +0000 Subject: [PATCH 292/295] 8015444: java/awt/Focus/KeyStrokeTest.java sometimes fails Reviewed-by: tr --- test/jdk/java/awt/Focus/KeyStrokeTest.java | 79 +++++++++++----------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/test/jdk/java/awt/Focus/KeyStrokeTest.java b/test/jdk/java/awt/Focus/KeyStrokeTest.java index 7c462ce8f22..668bc1216c8 100644 --- a/test/jdk/java/awt/Focus/KeyStrokeTest.java +++ b/test/jdk/java/awt/Focus/KeyStrokeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run main KeyStrokeTest */ -import java.awt.BorderLayout; import java.awt.Button; import java.awt.Dialog; +import java.awt.EventQueue; import java.awt.Frame; import java.awt.Robot; import java.awt.TextField; @@ -39,25 +39,53 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class KeyStrokeTest { static boolean keyTyped; static Frame frame; + static Robot robot; + static final CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) throws Exception { + robot = new Robot(); try { - KeyStrokeTest test = new KeyStrokeTest(); - test.doTest(); - } finally { - if (frame != null) { - frame.dispose(); + EventQueue.invokeAndWait(() -> { + KeyStrokeTest test = new KeyStrokeTest(); + test.initTest(); + }); + robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + + robot.delay(1000); + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SPACE); + + robot.delay(1000); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + try { + latch.await(3, TimeUnit.SECONDS); + } catch (InterruptedException e) {} + if (!keyTyped) { + throw new + RuntimeException("First keystroke after JDialog is closed is lost"); } + System.out.println("Test passed"); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } - private static void doTest() throws Exception { - final Object monitor = new Object(); - frame = new Frame(); + private static void initTest() { + frame = new Frame("KeyStrokeTest"); TextField textField = new TextField() { public void transferFocus() { System.err.println("transferFocus()"); @@ -71,6 +99,7 @@ public class KeyStrokeTest { }); dialog.add(btn); dialog.setSize(200, 200); + dialog.setLocationRelativeTo(null); dialog.setVisible(true); } }; @@ -81,38 +110,12 @@ public class KeyStrokeTest { if (e.getKeyChar() == 'a') { keyTyped = true; } - - synchronized (monitor) { - monitor.notifyAll(); - } + latch.countDown(); } }); frame.add(textField); frame.setSize(400, 400); + frame.setLocationRelativeTo(null); frame.setVisible(true); - - Robot robot = new Robot(); - robot.waitForIdle(); - robot.delay(1000); - robot.keyPress(KeyEvent.VK_TAB); - robot.keyRelease(KeyEvent.VK_TAB); - - robot.delay(1000); - robot.keyPress(KeyEvent.VK_SPACE); - robot.keyRelease(KeyEvent.VK_SPACE); - - robot.delay(1000); - synchronized (monitor) { - robot.keyPress(KeyEvent.VK_A); - robot.keyRelease(KeyEvent.VK_A); - monitor.wait(3000); - } - - if (!keyTyped) { - throw new RuntimeException("TEST FAILED"); - } - - System.out.println("Test passed"); } - } From 73df06c80c33be584b054a528ecdab4ecbf51d56 Mon Sep 17 00:00:00 2001 From: Andreas Steiner Date: Tue, 16 Sep 2025 07:17:53 +0000 Subject: [PATCH 293/295] 8359104: gc/TestAlwaysPreTouchBehavior.java# fails on Linux Reviewed-by: mbaesken, ayang --- src/hotspot/os/linux/os_linux.cpp | 46 +++++++++++++++++-- src/hotspot/os/linux/os_linux.hpp | 17 +++++++ .../jtreg/gc/TestAlwaysPreTouchBehavior.java | 2 +- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index d7bc524e75b..3d44d839735 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -370,11 +370,20 @@ size_t os::physical_memory() { return phys_mem; } +// Returns the resident set size (RSS) of the process. +// Falls back to using VmRSS from /proc/self/status if /proc/self/smaps_rollup is unavailable. +// Note: On kernels with memory cgroups or shared memory, VmRSS may underreport RSS. +// Users requiring accurate RSS values should be aware of this limitation. size_t os::rss() { size_t size = 0; - os::Linux::meminfo_t info; - if (os::Linux::query_process_memory_info(&info)) { - size = info.vmrss * K; + os::Linux::accurate_meminfo_t accurate_info; + if (os::Linux::query_accurate_process_memory_info(&accurate_info) && accurate_info.rss != -1) { + size = accurate_info.rss * K; + } else { + os::Linux::meminfo_t info; + if (os::Linux::query_process_memory_info(&info)) { + size = info.vmrss * K; + } } return size; } @@ -2362,6 +2371,37 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { return false; } +// Accurate memory information need Linux 4.14 or newer +bool os::Linux::query_accurate_process_memory_info(os::Linux::accurate_meminfo_t* info) { + FILE* f = os::fopen("/proc/self/smaps_rollup", "r"); + if (f == nullptr) { + return false; + } + + const size_t num_values = sizeof(os::Linux::accurate_meminfo_t) / sizeof(size_t); + size_t num_found = 0; + char buf[256]; + info->rss = info->pss = info->pssdirty = info->pssanon = + info->pssfile = info->pssshmem = info->swap = info->swappss = -1; + + while (::fgets(buf, sizeof(buf), f) != nullptr && num_found < num_values) { + if ( (info->rss == -1 && sscanf(buf, "Rss: %zd kB", &info->rss) == 1) || + (info->pss == -1 && sscanf(buf, "Pss: %zd kB", &info->pss) == 1) || + (info->pssdirty == -1 && sscanf(buf, "Pss_Dirty: %zd kB", &info->pssdirty) == 1) || + (info->pssanon == -1 && sscanf(buf, "Pss_Anon: %zd kB", &info->pssanon) == 1) || + (info->pssfile == -1 && sscanf(buf, "Pss_File: %zd kB", &info->pssfile) == 1) || + (info->pssshmem == -1 && sscanf(buf, "Pss_Shmem: %zd kB", &info->pssshmem) == 1) || + (info->swap == -1 && sscanf(buf, "Swap: %zd kB", &info->swap) == 1) || + (info->swappss == -1 && sscanf(buf, "SwapPss: %zd kB", &info->swappss) == 1) + ) + { + num_found ++; + } + } + fclose(f); + return true; +} + #ifdef __GLIBC__ // For Glibc, print a one-liner with the malloc tunables. // Most important and popular is MALLOC_ARENA_MAX, but we are diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index d3e0d6c5668..497d383200d 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -181,6 +181,23 @@ class os::Linux { // fields will contain -1. static bool query_process_memory_info(meminfo_t* info); + // Output structure for query_accurate_process_memory_info() (all values in KB) + struct accurate_meminfo_t { + ssize_t rss; // current resident set size + ssize_t pss; // current proportional set size + ssize_t pssdirty; // proportional set size (dirty) + ssize_t pssanon; // proportional set size (anonymous mappings) + ssize_t pssfile; // proportional set size (file mappings) + ssize_t pssshmem; // proportional set size (shared mappings) + ssize_t swap; // swapped out + ssize_t swappss; // proportional set size (swapped out) + }; + + // Attempts to query accurate memory information from /proc/self/smaps_rollup and return it in the output structure. + // May fail (returns false) or succeed (returns true) but not all output fields are available; unavailable + // fields will contain -1. + static bool query_accurate_process_memory_info(accurate_meminfo_t* info); + // Tells if the user asked for transparent huge pages. static bool _thp_requested; diff --git a/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java b/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java index b8197f70384..141ef7ba197 100644 --- a/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java +++ b/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java @@ -155,7 +155,7 @@ public class TestAlwaysPreTouchBehavior { } if (available > requiredAvailable) { Asserts.assertGreaterThan(rss, minRequiredRss, "RSS of this process(" + rss + "b) should be bigger " + - "than or equal to heap size(" + heapSize + "b) (available memory: " + available + ")"); + "than or equal to heap size(" + heapSize + "b) (available memory: " + available + "). On Linux Kernel < 4.14 RSS can be inaccurate"); } } } From 3ba2e748d61a9ed8098093c6d4732973051808b2 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Tue, 16 Sep 2025 08:00:09 +0000 Subject: [PATCH 294/295] 8366925: Improper std::nothrow new expression in NativeHeapTrimmerThread ctor Reviewed-by: ayang, kbarrett, dholmes --- src/hotspot/share/runtime/trimNativeHeap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp index 875bcb8e0c8..6049f4531c0 100644 --- a/src/hotspot/share/runtime/trimNativeHeap.cpp +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -163,7 +163,7 @@ class NativeHeapTrimmerThread : public NamedThread { public: NativeHeapTrimmerThread() : - _lock(new (std::nothrow) PaddedMonitor(Mutex::nosafepoint, "NativeHeapTrimmer_lock")), + _lock(new PaddedMonitor(Mutex::nosafepoint, "NativeHeapTrimmer_lock")), _stop(false), _suspend_count(0), _num_trims_performed(0) From eb26865c36f1961ee802c8db812c786d4bdd4944 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Tue, 16 Sep 2025 08:00:32 +0000 Subject: [PATCH 295/295] 8367552: JCmdTestFileSafety.java fails when run by root user Reviewed-by: dcubed, ayang, phubner --- .../jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java index 68d77c5455c..74f98d5b777 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestFileSafety.java @@ -141,6 +141,9 @@ public class JCmdTestFileSafety extends JCmdTestDumpBase { // to create archive successfully which is not expected. throw new jtreg.SkippedException("Test skipped on Windows"); } + if (Platform.isRoot()) { + throw new jtreg.SkippedException("Test skipped when executed by root user."); + } runTest(JCmdTestFileSafety::test); } }