diff --git a/make/modules/jdk.crypto.cryptoki/Lib.gmk b/make/modules/jdk.crypto.cryptoki/Lib.gmk index 29d1422cd787..2d7904e60165 100644 --- a/make/modules/jdk.crypto.cryptoki/Lib.gmk +++ b/make/modules/jdk.crypto.cryptoki/Lib.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # 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,8 +35,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJ2PKCS11, \ NAME := j2pkcs11, \ OPTIMIZATION := LOW, \ EXTRA_HEADER_DIRS := java.base:libjava, \ - DISABLED_WARNINGS_gcc_p11_md.c := unused-variable, \ - DISABLED_WARNINGS_clang_p11_md.c := unused-variable, \ DISABLED_WARNINGS_clang_p11_util.c := format-nonliteral, \ LIBS_unix := $(LIBDL), \ )) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 941cb2545325..4c56ca5dddbe 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved. + * Copyright 2025 Arm Limited and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -223,10 +224,13 @@ void VM_Version::initialize() { // Neoverse // N1: 0xd0c // N2: 0xd49 + // N3: 0xd8e // V1: 0xd40 // V2: 0xd4f + // V3: 0xd84 if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) || - model_is(0xd40) || model_is(0xd4f))) { + model_is(0xd40) || model_is(0xd4f) || + model_is(0xd8e) || model_is(0xd84))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } @@ -261,7 +265,9 @@ void VM_Version::initialize() { // Neoverse // V1: 0xd40 // V2: 0xd4f - if (_cpu == CPU_ARM && (model_is(0xd40) || model_is(0xd4f))) { + // V3: 0xd84 + if (_cpu == CPU_ARM && + (model_is(0xd40) || model_is(0xd4f) || model_is(0xd84))) { if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) { FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 9b7e71387100..37fd78370475 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1608,6 +1608,27 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r int src_offset = ra_->reg2offset(src_lo); int dst_offset = ra_->reg2offset(dst_lo); + // Stack-to-stack copies use t0 for the value. Bail out if a destination + // address also needs t0 to materialize an offset outside the 12-bit range. + if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { + int last_dst_offset = dst_offset; + if (bottom_type()->isa_vectmask()) { + int vmask_size_in_bytes = Matcher::scalable_predicate_reg_slots() * 32 / 8; + last_dst_offset += vmask_size_in_bytes - 4; + } else if (ideal_reg() == Op_VecA) { + int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); + last_dst_offset += vector_reg_size_in_bytes - 8; + } + + if (masm != nullptr && !Assembler::is_simm12(last_dst_offset)) { + // size() emits into a scratch buffer where recording a failure is not allowed. + if (!C->output()->in_scratch_emit_size()) { + C->record_method_not_compilable("unsupported large stack-to-stack spill copy"); + } + return 0; + } + } + if (bottom_type()->isa_vect() != nullptr) { uint ireg = ideal_reg(); if (ireg == Op_VecA && masm) { diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 8d84f144f024..c0c67fda9493 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 4f3d135c9199..9aa51f29ec04 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/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 458b7ab99afc..be5c87a8daa8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -307,22 +307,25 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau } bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { + // Only read the cancellation cause once. Other threads may change it. ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->cancelled_gc()) { - if (heap->cancelled_cause() == GCCause::_shenandoah_stop_vm) { - return true; - } + const GCCause::Cause cancelled_cause = heap->cancelled_cause(); + if (cancelled_cause == GCCause::_no_gc) { + return false; + } - if (ShenandoahCollectorPolicy::is_allocation_failure(heap->cancelled_cause())) { - assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, - "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); - _degen_point = point; - return true; - } + if (cancelled_cause == GCCause::_shenandoah_stop_vm) { + return true; + } - fatal("Unexpected reason for cancellation: %s", GCCause::to_string(heap->cancelled_cause())); + if (ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause)) { + assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, + "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); + _degen_point = point; + return true; } - return false; + + fatal("Unexpected reason for cancellation: %s", GCCause::to_string(cancelled_cause)); } void ShenandoahControlThread::stop_service() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 125c60b54460..816f3f3846b2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -581,28 +581,31 @@ void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahGen } bool ShenandoahGenerationalControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { - if (!_heap->cancelled_gc()) { + // Only read the cancellation cause once. Other threads may change it. + const GCCause::Cause cancelled_cause = _heap->cancelled_cause(); + if (cancelled_cause == GCCause::_no_gc) { return false; } - if (_heap->cancelled_cause() == GCCause::_shenandoah_stop_vm - || _heap->cancelled_cause() == GCCause::_shenandoah_concurrent_gc) { - log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(_heap->cancelled_cause())); + if (cancelled_cause == GCCause::_shenandoah_stop_vm + || cancelled_cause == GCCause::_shenandoah_concurrent_gc) { + log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(cancelled_cause)); return true; } - if (ShenandoahCollectorPolicy::is_allocation_failure(_heap->cancelled_cause())) { + if (ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause)) { assert(_degen_point == ShenandoahGC::_degenerated_unset, "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + _requested_gc_cause = cancelled_cause; _degen_point = point; log_debug(gc, thread)("Cancellation detected:, reason: %s, degen point: %s", - GCCause::to_string(_heap->cancelled_cause()), + GCCause::to_string(cancelled_cause), ShenandoahGC::degen_point_to_string(_degen_point)); return true; } fatal("Cancel GC either for alloc failure GC, or gracefully exiting, or to pause old generation marking"); - return false; } void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause cause) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 574959428b5b..1749c3077835 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -2224,8 +2224,18 @@ size_t ShenandoahHeap::tlab_used(Thread* thread) const { } bool ShenandoahHeap::try_cancel_gc(GCCause::Cause cause) { - const GCCause::Cause prev = _cancelled_gc.xchg(cause); - return prev == GCCause::_no_gc || prev == GCCause::_shenandoah_concurrent_gc; + while (true) { + const GCCause::Cause prev = _cancelled_gc.get(); + if (prev != GCCause::_no_gc && prev != GCCause::_shenandoah_concurrent_gc && cause != GCCause::_shenandoah_stop_vm) { + // Only when the gc has not been cancelled, or it has been cancelled to interrupt an old marking cycle + // do we allow the new cancellation request to happen. We make an exception for stopping the VM. + return false; + } + + if (_cancelled_gc.cmpxchg(cause, prev) == prev) { + return true; + } + } } void ShenandoahHeap::cancel_concurrent_mark() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 4aef14f2c9ab..d4e8d23ef0f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -81,13 +81,13 @@ class ShenandoahMark: public StackObj { inline void do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveData* live_data, StringDedup::Requests* const req, ShenandoahMarkTask* task, uint worker_id); template - inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array, bool weak); + inline void do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop array, Klass* klass, bool weak); template inline void do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop array, int chunk, int pow, bool weak); template - inline void count_liveness(ShenandoahLiveData* live_data, oop obj, uint worker_id); + inline void count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id); template void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 09b872deadad..b5a9f5ecaed7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -75,31 +75,32 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD cl->set_weak(weak); if (task->is_not_chunked()) { - if (obj->is_instance()) { + Klass* klass = obj->klass(); + if (klass->is_instance_klass()) { // Case 1: Normal oop, process as usual. - if (obj->is_stackChunk()) { + if (klass->is_stack_chunk_instance_klass()) { // Loom doesn't support mixing of weak marking and strong marking of stack chunks. cl->set_weak(false); } obj->oop_iterate(cl); dedup_string(obj, req); - } else if (obj->is_objArray()) { + } else if (klass->is_objArray_klass()) { // Case 2: Object array instance and no chunk is set. Must be the first // time we visit it, start the chunked processing. - do_chunked_array_start(q, cl, obj, weak); + do_chunked_array_start(q, cl, obj, klass, weak); } else { // Case 3: Primitive array. Do nothing, no oops there. We use the same // performance tweak TypeArrayKlass::oop_oop_iterate_impl is using: // We skip iterating over the klass pointer since we know that // Universe::TypeArrayKlass never moves. - assert (obj->is_typeArray(), "should be type array"); + assert(klass->is_typeArray_klass(), "should be type array"); } // Count liveness the last: push the outstanding work to the queues first // Avoid double-counting objects that are visited twice due to upgrade // from final- to strong mark. if (task->count_liveness()) { - count_liveness(live_data, obj, worker_id); + count_liveness(live_data, obj, klass, worker_id); } } else { // Case 4: Array chunk, has sensible chunk id. Process it. @@ -108,11 +109,11 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD } template -inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj, uint worker_id) { +inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop obj, Klass* klass, uint worker_id) { const ShenandoahHeap* const heap = ShenandoahHeap::heap(); const size_t region_idx = heap->heap_region_index_containing(obj); ShenandoahHeapRegion* const region = heap->get_region(region_idx); - const size_t size = obj->size(); + const size_t size = obj->size_given_klass(klass); // Age census for objects in the young generation if (GENERATION == YOUNG || (GENERATION == GLOBAL && region->is_young())) { @@ -152,14 +153,14 @@ inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop ob } template -inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj, bool weak) { +inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj, Klass* klass, bool weak) { assert(obj->is_objArray(), "expect object array"); objArrayOop array = objArrayOop(obj); int len = array->length(); // Mark objArray klass metadata if (Devirtualizer::do_metadata(cl)) { - Devirtualizer::do_klass(cl, array->klass()); + Devirtualizer::do_klass(cl, klass); } if (len <= (int) ObjArrayMarkingStride*2) { diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 8048c8770c2b..219fe7e49d27 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -64,9 +64,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 cc96e4f2bbb6..04528131554c 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); } diff --git a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c index 62895895123d..19f39188a18f 100644 --- a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c +++ b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -79,10 +79,6 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect jstring jGetFunctionList) { void *hModule; - int i; - CK_ULONG ulCount = 0; - CK_C_GetInterfaceList C_GetInterfaceList = NULL; - CK_INTERFACE_PTR iList = NULL; CK_C_GetInterface C_GetInterface = NULL; CK_INTERFACE_PTR interface = NULL; CK_C_GetFunctionList C_GetFunctionList = NULL; @@ -124,27 +120,31 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect } #ifdef DEBUG - C_GetInterfaceList = (CK_C_GetInterfaceList) dlsym(hModule, - "C_GetInterfaceList"); + CK_C_GetInterfaceList C_GetInterfaceList = (CK_C_GetInterfaceList) dlsym(hModule, "C_GetInterfaceList"); if (C_GetInterfaceList != NULL) { + CK_ULONG ulCount = 0; TRACE0("Connect: Found C_GetInterfaceList func\n"); rv = (C_GetInterfaceList)(NULL, &ulCount); if (rv == CKR_OK) { TRACE1("Connect: interface list size %ld \n", ulCount); // retrieve available interfaces and report their info - iList = (CK_INTERFACE_PTR) - malloc(ulCount*sizeof(CK_INTERFACE)); - rv = C_GetInterfaceList(iList, &ulCount); - if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { - TRACE0("Connect: error polling interface list\n"); - goto cleanup; - } - for (i=0; i < (int)ulCount; i++) { - TRACE4("Connect: name %s, version %d.%d, flags 0x%lX\n", - iList[i].pInterfaceName, - ((CK_VERSION *)iList[i].pFunctionList)->major, - ((CK_VERSION *)iList[i].pFunctionList)->minor, - iList[i].flags); + CK_INTERFACE_PTR iList = (CK_INTERFACE_PTR) malloc(ulCount*sizeof(CK_INTERFACE)); + if (iList == NULL) { + TRACE0("Connect: error allocating interface list\n"); + } else { + rv = C_GetInterfaceList(iList, &ulCount); + if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { + TRACE0("Connect: error polling interface list\n"); + goto cleanup; + } + for (int i=0; i < (int)ulCount; i++) { + TRACE4("Connect: name %s, version %d.%d, flags 0x%lX\n", + iList[i].pInterfaceName, + ((CK_VERSION *)iList[i].pFunctionList)->major, + ((CK_VERSION *)iList[i].pFunctionList)->minor, + iList[i].flags); + } + free(iList); } } else { TRACE0("Connect: error polling interface list size\n"); diff --git a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c index ca0fd3172300..6892e6f93fc3 100644 --- a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c +++ b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -79,10 +79,6 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect jstring jGetFunctionList) { HINSTANCE hModule; - int i = 0; - CK_ULONG ulCount = 0; - CK_C_GetInterfaceList C_GetInterfaceList = NULL; - CK_INTERFACE_PTR iList = NULL; CK_C_GetInterface C_GetInterface = NULL; CK_INTERFACE_PTR interface = NULL; CK_C_GetFunctionList C_GetFunctionList = NULL; @@ -129,22 +125,27 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect /* * Get function pointer to C_GetInterfaceList */ - C_GetInterfaceList = (CK_C_GetInterfaceList) GetProcAddress(hModule, + CK_C_GetInterfaceList C_GetInterfaceList = (CK_C_GetInterfaceList) GetProcAddress(hModule, "C_GetInterfaceList"); if (C_GetInterfaceList != NULL) { + CK_ULONG ulCount = 0; TRACE0("Found C_GetInterfaceList func\n"); rv = (C_GetInterfaceList)(NULL, &ulCount); if (rv == CKR_OK) { /* get copy of interfaces */ - iList = (CK_INTERFACE_PTR) - malloc(ulCount*sizeof(CK_INTERFACE)); - rv = C_GetInterfaceList(iList, &ulCount); - for (i=0; i < (int)ulCount; i++) { - printf("interface %s version %d.%d funcs %p flags 0x%lu\n", - iList[i].pInterfaceName, - ((CK_VERSION *)iList[i].pFunctionList)->major, - ((CK_VERSION *)iList[i].pFunctionList)->minor, - iList[i].pFunctionList, iList[i].flags); + CK_INTERFACE_PTR iList = (CK_INTERFACE_PTR) malloc(ulCount*sizeof(CK_INTERFACE)); + if (iList == NULL) { + TRACE0("Connect: error allocating interface list\n"); + } else { + rv = C_GetInterfaceList(iList, &ulCount); + for (int i=0; i < (int)ulCount; i++) { + printf("interface %s version %d.%d funcs %p flags 0x%lu\n", + iList[i].pInterfaceName, + ((CK_VERSION *)iList[i].pFunctionList)->major, + ((CK_VERSION *)iList[i].pFunctionList)->minor, + iList[i].pFunctionList, iList[i].flags); + } + free(iList); } } else { TRACE0("Connect: error polling interface list size\n"); diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json index bf52bb3915d2..1da3e3941ef7 100644 --- a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json +++ b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json @@ -81,7 +81,7 @@ "owner": { "type": "string", "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer." - } + }, "required": [ "object" ] diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java index 0775e5baadd2..45891e0bd40c 100644 --- a/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java @@ -24,7 +24,9 @@ /* * @test id=default + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -50,7 +52,9 @@ /* * @test id=default-verify + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -79,9 +83,82 @@ * TestClone */ +/* + * @test id=passive + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:TieredStopAtLevel=4 + * TestClone + */ + +/* + * @test id=passive-verify + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC + * -XX:ShenandoahGCMode=passive -XX:+ShenandoahCloneBarrier + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=4 + * TestClone + */ + /* * @test id=aggressive + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -105,9 +182,44 @@ * TestClone */ +/* + * @test id=aggressive-verify + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=4 + * TestClone + */ + /* * @test id=no-coops + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * @requires vm.bits == "64" * @@ -139,7 +251,9 @@ /* * @test id=no-coops-verify + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * @requires vm.bits == "64" * @@ -176,7 +290,9 @@ /* * @test id=no-coops-aggressive + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * @requires vm.bits == "64" * @@ -208,7 +324,9 @@ /* * @test id=generational + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -234,7 +352,9 @@ /* * @test id=generational-small-card-size + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -260,7 +380,9 @@ /* * @test id=generational-verify + * @key randomness * @summary Test clone barriers work correctly + * @library /test/lib * @requires vm.gc.Shenandoah * * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g @@ -289,100 +411,241 @@ * TestClone */ - /* - * @test id=generational-no-coops - * @summary Test clone barriers work correctly - * @requires vm.gc.Shenandoah - * @requires vm.bits == "64" - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -Xint - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:-TieredCompilation - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:TieredStopAtLevel=1 - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:TieredStopAtLevel=4 - * TestClone - */ - - /* - * @test id=generational-no-coops-verify - * @summary Test clone barriers work correctly - * @requires vm.gc.Shenandoah - * @requires vm.bits == "64" - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -Xint - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -XX:-TieredCompilation - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -XX:TieredStopAtLevel=1 - * TestClone - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g - * -XX:-UseCompressedOops - * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational - * -XX:+ShenandoahVerify - * -XX:TieredStopAtLevel=4 - * TestClone - */ +/* + * @test id=generational-no-coops + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * @requires vm.bits == "64" + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:TieredStopAtLevel=4 + * TestClone + */ +/* + * @test id=generational-no-coops-verify + * @key randomness + * @summary Test clone barriers work correctly + * @library /test/lib + * @requires vm.gc.Shenandoah + * @requires vm.bits == "64" + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:-UseCompressedOops + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational + * -XX:+ShenandoahVerify + * -XX:TieredStopAtLevel=4 + * TestClone + */ + +import java.util.Random; + +import jdk.test.lib.Utils; public class TestClone { + private static final int ENTRIES = 1_000; + private static final int ITERS = 50_000; + private static final int ARRAY_MAX_SIZE = 128; + private static final Random RAND = Utils.getRandomInstance(); + private static final SmallObject[] SMALL = new SmallObject[ENTRIES]; + private static final LargeObject[] LARGE = new LargeObject[ENTRIES]; + private static final Ref[][] ARRAY = new Ref[ENTRIES][]; + public static void main(String[] args) throws Exception { - for (int i = 0; i < 10000; i++) { - Object[] src = new Object[i]; - for (int c = 0; c < src.length; c++) { - src[c] = new Object(); - } - testWith(src); + // Seed + for (int i = 0; i < ENTRIES; i++) { + SMALL[i] = new SmallObject(i); + LARGE[i] = new LargeObject(i); + ARRAY[i] = newArray(i); } + + // Random clone and verify + for (int i = 0; i < ITERS; i++) { + cloneAndVerify(); + } + + // Verify everything + for (int i = 0; i < ENTRIES; i++) { + verify(SMALL[i], i); + verify(LARGE[i], i); + verify(ARRAY[i], i); + } + } + + static void cloneAndVerify() { + int r = RAND.nextInt(ENTRIES); + SMALL[r] = SMALL[r].clone(); + LARGE[r] = LARGE[r].clone(); + ARRAY[r] = ARRAY[r].clone(); + + // Verify will trigger LRB. + // We don't want LRB to heal refs in the clone source or target, + // so we verify a different random location. + r = RAND.nextInt(ENTRIES); + verify(SMALL[r], r); + verify(LARGE[r], r); + verify(ARRAY[r], r); + } + + static Ref[] newArray(int id) { + int size = id % ARRAY_MAX_SIZE; + Ref[] arr = new Ref[size]; + for (int i = 0; i < size; i++) { + arr[i] = new Ref(elementValue(id, i)); + } + return arr; + } + + static void verify(SmallObject src, int id) { + assertEquals(elementValue(id, 0), src.x1.x); + assertEquals(elementValue(id, 1), src.x2.x); + assertEquals(elementValue(id, 2), src.x3.x); + assertEquals(elementValue(id, 3), src.x4.x); } - static void testWith(Object[] src) { - Object[] dst = src.clone(); + static void verify(LargeObject src, int id) { + assertEquals(elementValue(id, 0), src.x01.x); + assertEquals(elementValue(id, 1), src.x02.x); + assertEquals(elementValue(id, 2), src.x03.x); + assertEquals(elementValue(id, 3), src.x04.x); + assertEquals(elementValue(id, 4), src.x05.x); + assertEquals(elementValue(id, 5), src.x06.x); + assertEquals(elementValue(id, 6), src.x07.x); + assertEquals(elementValue(id, 7), src.x08.x); + assertEquals(elementValue(id, 8), src.x09.x); + assertEquals(elementValue(id, 9), src.x10.x); + assertEquals(elementValue(id, 10), src.x11.x); + assertEquals(elementValue(id, 11), src.x12.x); + assertEquals(elementValue(id, 12), src.x13.x); + assertEquals(elementValue(id, 13), src.x14.x); + assertEquals(elementValue(id, 14), src.x15.x); + assertEquals(elementValue(id, 15), src.x16.x); + } + + static void assertEquals(int expected, int actual) { + if (actual != expected) { + throw new IllegalStateException("Mismatch: expected=" + expected + ", actual=" + actual); + } + } + + static void verify(Ref[] src, int id) { + int expectedLen = id % ARRAY_MAX_SIZE; int srcLen = src.length; - int dstLen = dst.length; - if (srcLen != dstLen) { - throw new IllegalStateException("Lengths do not match: " + srcLen + " vs " + dstLen); + if (srcLen != expectedLen) { + throw new IllegalStateException("Lengths do not match: " + srcLen + " vs " + expectedLen); } - for (int c = 0; c < src.length; c++) { - Object s = src[c]; - Object d = dst[c]; - if (s != d) { - throw new IllegalStateException("Elements do not match at " + c + ": " + s + " vs " + d); + for (int i = 0; i < src.length; i++) { + int expectedVal = elementValue(id, i); + int val = src[i].x; + if (val != expectedVal) { + throw new IllegalStateException("Elements do not match at " + i + ": " + val + " vs " + expectedVal + ", len = " + srcLen); } } } + + static int elementValue(int id, int offset) { + // Globally unique (per type). + return ENTRIES * id + offset; + } + + static class Ref { + int x; + + Ref(int x) { + this.x = x; + } + } + + abstract static class DefaultClone implements Cloneable { + @Override + @SuppressWarnings("unchecked") + public T clone() { + try { + return (T) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); + } + } + } + + static class SmallObject extends DefaultClone { + Ref x1, x2, x3, x4; + + SmallObject(int x) { + x1 = new Ref(elementValue(x, 0)); + x2 = new Ref(elementValue(x, 1)); + x3 = new Ref(elementValue(x, 2)); + x4 = new Ref(elementValue(x, 3)); + } + } + + static class LargeObject extends DefaultClone { + Ref x01, x02, x03, x04, x05, x06, x07, x08; + Ref x09, x10, x11, x12, x13, x14, x15, x16; + + LargeObject(int x) { + x01 = new Ref(elementValue(x, 0)); + x02 = new Ref(elementValue(x, 1)); + x03 = new Ref(elementValue(x, 2)); + x04 = new Ref(elementValue(x, 3)); + x05 = new Ref(elementValue(x, 4)); + x06 = new Ref(elementValue(x, 5)); + x07 = new Ref(elementValue(x, 6)); + x08 = new Ref(elementValue(x, 7)); + x09 = new Ref(elementValue(x, 8)); + x10 = new Ref(elementValue(x, 9)); + x11 = new Ref(elementValue(x, 10)); + x12 = new Ref(elementValue(x, 11)); + x13 = new Ref(elementValue(x, 12)); + x14 = new Ref(elementValue(x, 13)); + x15 = new Ref(elementValue(x, 14)); + x16 = new Ref(elementValue(x, 15)); + } + } } diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java index 77020491c29b..3878513d3f2e 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -238,6 +239,7 @@ void testBlockedThreadWhenPinned() throws Exception { void testBlockedThread(ThreadFactory factory, boolean pinned) throws Exception { var lock = new Object(); + String lockAsString = Objects.toIdentityString(lock); var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { @@ -258,9 +260,7 @@ void testBlockedThread(ThreadFactory factory, boolean pinned) throws Exception { thread.start(); started.await(); await(thread, Thread.State.BLOCKED); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); @@ -308,6 +308,7 @@ void testWaitingThreadWhenPinned() throws Exception { void testWaitingThread(ThreadFactory factory, boolean pinned) throws Exception { var lock = new Object(); + String lockAsString = Objects.toIdentityString(lock); var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { @@ -331,9 +332,7 @@ void testWaitingThread(ThreadFactory factory, boolean pinned) throws Exception { thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); @@ -417,7 +416,6 @@ void testParkedThread(ThreadFactory factory, boolean pinned) throws Exception { thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); // thread dump in plain text should include thread @@ -460,7 +458,7 @@ void testParkedThread(ThreadFactory factory, boolean pinned) throws Exception { } /** - * Test thread dump with a thread owning a monitor. + * Test thread dump with a thread owning monitors. */ @ParameterizedTest @MethodSource("threadFactories") @@ -475,19 +473,26 @@ void testThreadOwnsMonitorWhenPinned() throws Exception { } void testThreadOwnsMonitor(ThreadFactory factory, boolean pinned) throws Exception { - var lock = new Object(); - var started = new CountDownLatch(1); + var lock1 = new Object(); + var lock2 = new Object(); + var lock3 = new Object(); + String lock1AsString = Objects.toIdentityString(lock1); + String lock2AsString = Objects.toIdentityString(lock2); + String lock3AsString = Objects.toIdentityString(lock3); + var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { - synchronized (lock) { - if (pinned) { - VThreadPinner.runPinned(() -> { + synchronized (lock1) { + synchronized (lock2) { + if (pinned) { + VThreadPinner.runPinned(() -> { + started.countDown(); + lockAndRun(lock3, LockSupport::park); + }); + } else { started.countDown(); - LockSupport.park(); - }); - } else { - started.countDown(); - LockSupport.park(); + lockAndRun(lock3, LockSupport::park); + } } } }); @@ -497,16 +502,16 @@ void testThreadOwnsMonitor(ThreadFactory factory, boolean pinned) throws Excepti thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); ThreadFields fields = findThread(tid, lines); assertNotNull(fields, "thread not found"); assertEquals("WAITING", fields.state()); - assertTrue(contains(lines, "- locked <" + lockAsString)); + assertTrue(contains(lines, "- locked <" + lock1AsString)); + assertTrue(contains(lines, "- locked <" + lock2AsString)); + assertTrue(contains(lines, "- locked <" + lock3AsString)); // thread dump in JSON format should include thread in root container ThreadDump threadDump = dumpThreadsToJson(); @@ -516,18 +521,47 @@ void testThreadOwnsMonitor(ThreadFactory factory, boolean pinned) throws Excepti assertNotNull(ti, "thread not found"); assertEquals(ti.isVirtual(), thread.isVirtual()); - // the lock should be in the ownedMonitors array - Set ownedMonitors = ti.ownedMonitors().values() + // depth -> list of locks + Map> ownedMonitors = ti.ownedMonitors(); + + // lock -> list of depths + Map> monitorDepths = ownedMonitors.entrySet() .stream() - .flatMap(List::stream) - .collect(Collectors.toSet()); - assertTrue(ownedMonitors.contains(lockAsString), lockAsString + " not found"); + .flatMap(e -> e.getValue() + .stream() + .map(monitor -> Map.entry(monitor, e.getKey()))) + .collect(Collectors.groupingBy( + Map.Entry::getKey, + Collectors.mapping(Map.Entry::getValue, Collectors.toList()) + )); + + // each lock should be owned + List lock1Depths = monitorDepths.getOrDefault(lock1AsString, List.of()); + List lock2Depths = monitorDepths.getOrDefault(lock2AsString, List.of()); + List lock3Depths = monitorDepths.getOrDefault(lock3AsString, List.of()); + assertEquals(1, lock1Depths.size()); + assertEquals(1, lock2Depths.size()); + assertEquals(1, lock3Depths.size()); + + // lock1 and lock2 owned at the same depth, lock3 is the innermost + int depth1 = lock1Depths.get(0); + int depth2 = lock2Depths.get(0); + int depth3 = lock3Depths.get(0); + assertEquals(depth1, depth2); + assertTrue(depth3 < depth1); + } finally { LockSupport.unpark(thread); thread.join(); } } + private void lockAndRun(Object lock, Runnable action) { + synchronized (lock) { + action.run(); + } + } + /** * Test mounted virtual thread. */ diff --git a/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java b/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java index 56a39758874e..bb30cc65597a 100644 --- a/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java +++ b/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java @@ -79,13 +79,15 @@ public void setupGUI() { public void test() throws AWTException, InterruptedException, InvocationTargetException { - EventQueue.invokeAndWait(() -> { - onScreen = text_field.getLocationOnScreen(); - size = text_field.getSize(); - }); Robot robot = new Robot(); robot.setAutoDelay(50); robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + onScreen = text_field.getLocationOnScreen(); + size = text_field.getSize(); + }); + int y = onScreen.y + (size.height / 2); robot.mouseMove(onScreen.x + (size.width / 2), y); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java index ac56642b8d7b..f76f3d8b9a82 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,13 +88,13 @@ static void sigGenTest(JSONValue kat, Provider p) throws Exception { for (var t : kat.get("testGroups").asArray()) { var pname = t.get("parameterSet").asString(); System.out.println(">> " + pname + " sign"); - var det = Boolean.parseBoolean(t.get("deterministic").asString()); + var det = t.get("deterministic").asBoolean(); if (t.get("signatureInterface").asString().equals("internal")) { ML_DSA_Impls.version = ML_DSA_Impls.Version.DRAFT; } else { ML_DSA_Impls.version = ML_DSA_Impls.Version.FINAL; } - if (t.get("externalMu").asString().equals("true")) { + if (t.get("externalMu").asBoolean()) { continue; // Not supported } for (var c : t.get("tests").asArray()) { @@ -139,7 +139,7 @@ static void sigVerTest(JSONValue kat, Provider p) throws Exception { ML_DSA_Impls.version = ML_DSA_Impls.Version.FINAL; } - if (t.get("externalMu").asString().equals("true")) { + if (t.get("externalMu").asBoolean()) { continue; // Not supported } @@ -157,7 +157,7 @@ static void sigVerTest(JSONValue kat, Provider p) throws Exception { public byte[] getEncoded() { return toByteArray(c.get("pk").asString()); } }; // Only ML-DSA sigVer has negative tests - var expected = Boolean.parseBoolean(c.get("testPassed").asString()); + var expected = c.get("testPassed").asBoolean(); var actual = true; try { s.initVerify(pk); diff --git a/test/lib/jdk/test/lib/json/JSONValue.java b/test/lib/jdk/test/lib/json/JSONValue.java index f89d13b3bba9..72ed2fd917c0 100644 --- a/test/lib/jdk/test/lib/json/JSONValue.java +++ b/test/lib/jdk/test/lib/json/JSONValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; public interface JSONValue { @@ -88,9 +89,6 @@ public String asString() { @Override public String toString() { - if (value == null) { - return "null"; - } var builder = new StringBuilder(); builder.append("\""); @@ -172,6 +170,56 @@ public String toString() { public Iterator iterator() { return values.iterator(); } + + @Override + public List elements() { + return List.copyOf(values); + } + } + + public final class JSONBoolean implements JSONValue { + private static JSONBoolean TRUE = new JSONBoolean(true); + private static JSONBoolean FALSE = new JSONBoolean(false); + + private final boolean value; + + private JSONBoolean(boolean value) { + this.value = value; + } + + @Override + public boolean asBoolean() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static JSONBoolean of(boolean value) { + return value ? TRUE : FALSE; + } + } + + public final class JSONNull implements JSONValue { + private static JSONNull NULL = new JSONNull(); + + private JSONNull() {} + + @Override + public Optional valueOrNull() { + return Optional.empty(); + } + + @Override + public String toString() { + return "null"; + } + + public static JSONNull of() { + return NULL; + } } class JSONParser { @@ -181,8 +229,8 @@ class JSONParser { JSONParser() { } - private IllegalStateException failure(String message) { - return new IllegalStateException(String.format("[%d]: %s : %s", pos, message, input)); + private IllegalArgumentException failure(String message) { + return new IllegalArgumentException(String.format("[%d]: %s : %s", pos, message, input)); } private char current() { @@ -220,13 +268,13 @@ private void expect(char c) { } } - private JSONString parseBoolean() { + private JSONBoolean parseBoolean() { if (current() == 't') { expect('r'); expect('u'); expect('e'); advance(); - return new JSONString("true"); + return JSONBoolean.of(true); } if (current() == 'f') { @@ -235,7 +283,7 @@ private JSONString parseBoolean() { expect('s'); expect('e'); advance(); - return new JSONString("false"); + return JSONBoolean.of(false); } throw failure("a boolean can only be 'true' or 'false'"); } @@ -400,12 +448,12 @@ private JSONArray parseArray() { return new JSONArray(list); } - public JSONString parseNull() { + public JSONNull parseNull() { expect('u'); expect('l'); expect('l'); advance(); - return new JSONString(null); + return JSONNull.of(); } public JSONObject parseObject() { @@ -531,22 +579,38 @@ public static JSONValue parse(String s) { } default int size() { - throw new IllegalStateException("Size operation unsupported"); + throw new UnsupportedOperationException("Size operation unsupported"); + } + + default List elements() { + throw new UnsupportedOperationException("Unsupported conversion to array"); } default String asString() { - throw new IllegalStateException("Unsupported conversion to String"); + throw new UnsupportedOperationException("Unsupported conversion to String"); } default JSONArray asArray() { - throw new IllegalStateException("Unsupported conversion to array"); + throw new UnsupportedOperationException("Unsupported conversion to array"); } default JSONObject asObject() { - throw new IllegalStateException("Unsupported conversion to object"); + throw new UnsupportedOperationException("Unsupported conversion to object"); + } + + default boolean asBoolean() { + throw new UnsupportedOperationException("Unsupported conversion to boolean"); } default JSONValue get(String field) { return asObject().get(field); } + + default Optional getOrAbsent(String field) { + return Optional.ofNullable(get(field)); + } + + default Optional valueOrNull() { + return Optional.of(this); + } } diff --git a/test/lib/jdk/test/lib/threaddump/ThreadDump.java b/test/lib/jdk/test/lib/threaddump/ThreadDump.java index ca728e625fc8..972d46675f4c 100644 --- a/test/lib/jdk/test/lib/threaddump/ThreadDump.java +++ b/test/lib/jdk/test/lib/threaddump/ThreadDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +32,17 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.test.lib.json.JSONValue; /** * Represents a thread dump that is obtained by parsing JSON text. A thread dump in JSON * format is generated with the {@code com.sun.management.HotSpotDiagnosticMXBean} API or - * using {@code jcmd Thread.dump_to_file -format=json }. + * using {@code jcmd Thread.dump_to_file -format=json }. The thread dump + * format is documented in {@code + * src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json}. * *

The following is an example thread dump that is parsed by this class. Many of the * objects are collapsed to reduce the size. @@ -127,6 +131,20 @@ private ThreadDump(ThreadContainer rootThreadContainer, this.threadDumpObj = threadDumpObj; } + /** + * Assert that a JSONValue is a JSONString and parse the string as an int. + */ + private static int parseStringAsInt(JSONValue valueObj) { + return Integer.parseInt(valueObj.asString()); + } + + /** + * Assert that a JSONValue is a JSONString and parse the string as a long. + */ + private static long parseStringAsLong(JSONValue valueObj) { + return Long.parseLong(valueObj.asString()); + } + /** * Represents an element in the threadDump/threadContainers array. */ @@ -149,14 +167,6 @@ void addChild(ThreadContainer container) { children.add(container); } - /** - * Returns the value of a property of this thread container, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = containerObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - /** * Returns the thread container name. */ @@ -168,10 +178,10 @@ public String name() { * Return the thread identifier of the owner or empty OptionalLong if not owned. */ public OptionalLong owner() { - String owner = getStringProperty("owner"); - return (owner != null) - ? OptionalLong.of(Long.parseLong(owner)) - : OptionalLong.empty(); + return containerObj.get("owner") // string or null + .valueOrNull() + .map(v -> OptionalLong.of(parseStringAsLong(v))) + .orElse(OptionalLong.empty()); } /** @@ -192,12 +202,10 @@ public Stream children() { * Returns a stream of {@code ThreadInfo} objects for the threads in this container. */ public Stream threads() { - JSONValue.JSONArray threadsObj = containerObj.get("threads").asArray(); - Set threadInfos = new HashSet<>(); - for (JSONValue threadObj : threadsObj) { - threadInfos.add(new ThreadInfo(threadObj)); - } - return threadInfos.stream(); + return containerObj.get("threads") + .elements() + .stream() + .map(ThreadInfo::new); } /** @@ -237,29 +245,10 @@ public static final class ThreadInfo { private final JSONValue threadObj; ThreadInfo(JSONValue threadObj) { - this.tid = Long.parseLong(threadObj.get("tid").asString()); + this.tid = parseStringAsLong(threadObj.get("tid")); this.threadObj = threadObj; } - /** - * Returns the value of a property of this thread object, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = threadObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - - /** - * Returns the value of a property of an object in this thread object, as a string. - */ - private String getStringProperty(String objectName, String propertyName) { - if (threadObj.get(objectName) instanceof JSONValue.JSONObject obj - && obj.get(propertyName) instanceof JSONValue value) { - return value.asString(); - } - return null; - } - /** * Returns the thread identifier. */ @@ -271,83 +260,92 @@ public long tid() { * Returns the thread name. */ public String name() { - return getStringProperty("name"); + return threadObj.get("name").asString(); } /** * Returns the thread state. */ public String state() { - return getStringProperty("state"); + return threadObj.get("state").asString(); } /** * Returns true if virtual thread. */ public boolean isVirtual() { - String s = getStringProperty("virtual"); - return (s != null) ? Boolean.parseBoolean(s) : false; + return threadObj.getOrAbsent("virtual") + .map(JSONValue::asBoolean) + .orElse(false); } /** - * Returns the thread's parkBlocker. + * Returns the thread's parkBlocker or null. */ public String parkBlocker() { - return getStringProperty("parkBlocker", "object"); + return threadObj.getOrAbsent("parkBlocker") + .map(v -> v.get("object").asString()) + .orElse(null); } /** * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. */ public OptionalLong parkBlockerOwner() { - String owner = getStringProperty("parkBlocker", "owner"); - return (owner != null) - ? OptionalLong.of(Long.parseLong(owner)) - : OptionalLong.empty(); + return threadObj.getOrAbsent("parkBlocker") + .map(v -> OptionalLong.of(parseStringAsLong(v.get("owner")))) + .orElse(OptionalLong.empty()); } /** - * Returns the object that the thread is blocked entering its monitor. + * Returns the object that the thread is blocked entering its monitor or null. */ public String blockedOn() { - return getStringProperty("blockedOn"); + return threadObj.getOrAbsent("blockedOn") + .map(JSONValue::asString) + .orElse(null); } /** - * Return the object that is the therad is waiting on with Object.wait. + * Return the object that is the thread is waiting on with Object.wait or null. */ public String waitingOn() { - return getStringProperty("waitingOn"); + return threadObj.getOrAbsent("waitingOn") + .map(JSONValue::asString) + .orElse(null); } /** * Returns the thread stack. */ public Stream stack() { - JSONValue.JSONArray stackObj = threadObj.get("stack").asArray(); - List stack = new ArrayList<>(); - for (JSONValue steObject : stackObj) { - stack.add(steObject.asString()); - } - return stack.stream(); + return threadObj.get("stack") + .elements() + .stream() + .map(JSONValue::asString); } /** * Return a map of monitors owned. */ public Map> ownedMonitors() { - Map> ownedMonitors = new HashMap<>(); - JSONValue monitorsOwnedObj = threadObj.get("monitorsOwned"); - if (monitorsOwnedObj != null) { - for (JSONValue obj : monitorsOwnedObj.asArray()) { - int depth = Integer.parseInt(obj.get("depth").asString()); - for (JSONValue lock : obj.get("locks").asArray()) { - ownedMonitors.computeIfAbsent(depth, _ -> new ArrayList<>()) - .add(lock.asString()); - } - } - } - return ownedMonitors; + Map> result = new HashMap<>(); + threadObj.getOrAbsent("monitorsOwned") + .map(JSONValue::elements) + .orElse(List.of()) + .forEach(e -> { + int depth = parseStringAsInt(e.get("depth")); + List locks = e.get("locks") + .elements() + .stream() + .map(v -> v.valueOrNull() // string or null + .map(JSONValue::asString) + .orElse(null)) + .toList(); + result.computeIfAbsent(depth, _ -> new ArrayList<>()).addAll(locks); + }); + + return result; } /** @@ -355,10 +353,9 @@ public Map> ownedMonitors() { * its carrier. */ public OptionalLong carrier() { - String s = getStringProperty("carrier"); - return (s != null) - ? OptionalLong.of(Long.parseLong(s)) - : OptionalLong.empty(); + return threadObj.getOrAbsent("carrier") + .map(s -> OptionalLong.of(parseStringAsLong(s))) + .orElse(OptionalLong.empty()); } @Override @@ -388,33 +385,25 @@ public String toString() { } } - /** - * Returns the value of a property of this thread dump, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = threadDumpObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - /** * Returns the value of threadDump/processId. */ public long processId() { - return Long.parseLong(getStringProperty("processId")); + return parseStringAsLong(threadDumpObj.get("processId")); } /** * Returns the value of threadDump/time. */ public String time() { - return getStringProperty("time"); + return threadDumpObj.get("time").asString(); } /** * Returns the value of threadDump/runtimeVersion. */ public String runtimeVersion() { - return getStringProperty("runtimeVersion"); + return threadDumpObj.get("runtimeVersion").asString(); } /** @@ -449,24 +438,31 @@ public static ThreadDump parse(String json) { JSONValue threadDumpObj = JSONValue.parse(json).get("threadDump"); // threadContainers array, preserve insertion order (parents are added before children) - Map containerObjs = new LinkedHashMap<>(); - JSONValue threadContainersObj = threadDumpObj.get("threadContainers"); - for (JSONValue containerObj : threadContainersObj.asArray()) { - String name = containerObj.get("container").asString(); - containerObjs.put(name, containerObj); - } + Map containerObjs = threadDumpObj.get("threadContainers") + .elements() + .stream() + .collect(Collectors.toMap( + c -> c.get("container").asString(), + Function.identity(), + (a, b) -> { throw new RuntimeException("Duplicate container"); }, + LinkedHashMap::new + )); // find root and create tree of thread containers ThreadContainer root = null; Map map = new HashMap<>(); for (String name : containerObjs.keySet()) { JSONValue containerObj = containerObjs.get(name); - String parentName = containerObj.get("parent").asString(); - if (parentName == null) { + JSONValue parentObj = containerObj.get("parent"); + if (parentObj instanceof JSONValue.JSONNull) { + if (root != null) { + throw new RuntimeException("More than one root container"); + } root = new ThreadContainer(name, null, containerObj); map.put(name, root); } else { - var parent = map.get(parentName); + String parentName = parentObj.asString(); + ThreadContainer parent = map.get(parentName); if (parent == null) { throw new RuntimeException("Thread container " + name + " found before " + parentName); } @@ -475,7 +471,10 @@ public static ThreadDump parse(String json) { map.put(name, container); } } + if (root == null) { + throw new RuntimeException("No root container"); + } return new ThreadDump(root, map, threadDumpObj); } -} \ No newline at end of file +}