From 0d8f2b10a20b99cdab89e455d6d8298385443d13 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 14 Jul 2025 16:40:20 -0700 Subject: [PATCH 1/4] 8362203: assert(state == nullptr || state->get_thread_oop() != nullptr) failed: incomplete state --- src/hotspot/share/prims/jvmtiExport.cpp | 6 +++++- src/hotspot/share/prims/jvmtiThreadState.cpp | 9 +++++++++ src/hotspot/share/prims/jvmtiThreadState.hpp | 1 + .../StartPhase/AllowedFunctions/AllowedFunctions.java | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 10614f445d3d8..eb02eea3dc55d 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -675,6 +675,11 @@ void JvmtiExport::post_early_vm_start() { void JvmtiExport::post_vm_start() { EVT_TRIG_TRACE(JVMTI_EVENT_VM_START, ("Trg VM start event triggered" )); + // The thread state might be incomplete if initialized in post_early_vm_start + // before classes are initialized. It should be updated now. + JavaThread *thread = JavaThread::current(); + thread->jvmti_thread_state()->update_thread_oop(thread); + // can now enable some events JvmtiEventController::vm_start(); @@ -684,7 +689,6 @@ void JvmtiExport::post_vm_start() { if (!env->early_vmstart_env() && env->is_enabled(JVMTI_EVENT_VM_START)) { EVT_TRACE(JVMTI_EVENT_VM_START, ("Evt VM start event sent" )); - JavaThread *thread = JavaThread::current(); JvmtiThreadEventMark jem(thread); JvmtiJavaThreadEventTransition jet(thread); jvmtiEventVMStart callback = env->callbacks()->VMStart; diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 01600b26c28c5..8b4ca252ca84a 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -1041,6 +1041,15 @@ oop JvmtiThreadState::get_thread_oop() { return _thread_oop_h.resolve(); } +void JvmtiThreadState::update_thread_oop(JavaThread* thread) { + assert(thread->threadObj() != nullptr, "Should threadObj be already initialized"); + if (thread->jvmti_thread_state() != nullptr + && thread->jvmti_thread_state()->get_thread_oop() == nullptr) { + _thread_oop_h.release(JvmtiExport::jvmti_oop_storage()); + _thread_oop_h = OopHandle(JvmtiExport::jvmti_oop_storage(), thread->threadObj()); + } +} + void JvmtiThreadState::set_thread(JavaThread* thread) { _thread_saved = nullptr; // Common case. if (!_is_virtual && thread == nullptr) { diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 62d0c45e33728..1a0e5a94b5f03 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -311,6 +311,7 @@ class JvmtiThreadState : public CHeapObj { // Also used for carrier threads to clear/restore _thread. void set_thread(JavaThread* thread); oop get_thread_oop(); + void update_thread_oop(JavaThread* thread); inline bool is_virtual() { return _is_virtual; } // the _thread is virtual diff --git a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java index b4465d8fa56ec..7190ffa58f937 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java +++ b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java @@ -29,6 +29,7 @@ * @requires vm.jvmti * @run main/othervm/native -agentlib:AllowedFunctions AllowedFunctions * @run main/othervm/native -agentlib:AllowedFunctions=with_early_vmstart AllowedFunctions + * @run main/othervm/native -agentlib:AllowedFunctions=with_early_vmstart -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n AllowedFunctions */ public class AllowedFunctions { From 19e76aa9feecb6b7f09de2949067945c6f3a1996 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 14 Jul 2025 19:59:00 -0700 Subject: [PATCH 2/4] fixed comments after feedback, some polishing --- src/hotspot/share/prims/jvmtiExport.cpp | 6 ++++-- src/hotspot/share/prims/jvmtiThreadState.cpp | 7 +++---- src/hotspot/share/prims/jvmtiThreadState.hpp | 2 +- .../StartPhase/AllowedFunctions/AllowedFunctions.java | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index eb02eea3dc55d..b1c8dc7483158 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -675,10 +675,12 @@ void JvmtiExport::post_early_vm_start() { void JvmtiExport::post_vm_start() { EVT_TRIG_TRACE(JVMTI_EVENT_VM_START, ("Trg VM start event triggered" )); - // The thread state might be incomplete if initialized in post_early_vm_start + // The JvmtiThreadState is incomplete if initialized in post_early_vm_start // before classes are initialized. It should be updated now. JavaThread *thread = JavaThread::current(); - thread->jvmti_thread_state()->update_thread_oop(thread); + if (thread->jvmti_thread_state() != nullptr) { + thread->jvmti_thread_state()->update_thread_oop_during_vm_start(thread); + } // can now enable some events JvmtiEventController::vm_start(); diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 8b4ca252ca84a..cc2bc0f2c10ae 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -1041,10 +1041,9 @@ oop JvmtiThreadState::get_thread_oop() { return _thread_oop_h.resolve(); } -void JvmtiThreadState::update_thread_oop(JavaThread* thread) { - assert(thread->threadObj() != nullptr, "Should threadObj be already initialized"); - if (thread->jvmti_thread_state() != nullptr - && thread->jvmti_thread_state()->get_thread_oop() == nullptr) { +void JvmtiThreadState::update_thread_oop_during_vm_start(JavaThread* thread) { + assert(thread->threadObj() != nullptr, "santity check"); + if (thread->jvmti_thread_state()->get_thread_oop() == nullptr) { _thread_oop_h.release(JvmtiExport::jvmti_oop_storage()); _thread_oop_h = OopHandle(JvmtiExport::jvmti_oop_storage(), thread->threadObj()); } diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 1a0e5a94b5f03..364c786648d5d 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -311,7 +311,7 @@ class JvmtiThreadState : public CHeapObj { // Also used for carrier threads to clear/restore _thread. void set_thread(JavaThread* thread); oop get_thread_oop(); - void update_thread_oop(JavaThread* thread); + void update_thread_oop_during_vm_start(JavaThread* thread); inline bool is_virtual() { return _is_virtual; } // the _thread is virtual diff --git a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java index 7190ffa58f937..5249d8dc83566 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java +++ b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8172970 + * @bug 8172970 8362203 * @summary Verify the functions that are allowed to operate in the start phase * with and without can_generate_early_vmstart capability. * @requires vm.jvmti From a8d5e277b12c874592e241ce4d28a5ee6ac9aaac Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 15 Jul 2025 00:51:16 -0700 Subject: [PATCH 3/4] simplified the update --- src/hotspot/share/prims/jvmtiExport.cpp | 2 +- src/hotspot/share/prims/jvmtiThreadState.cpp | 9 ++++----- src/hotspot/share/prims/jvmtiThreadState.hpp | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index b1c8dc7483158..cdd32f13646c1 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -679,7 +679,7 @@ void JvmtiExport::post_vm_start() { // before classes are initialized. It should be updated now. JavaThread *thread = JavaThread::current(); if (thread->jvmti_thread_state() != nullptr) { - thread->jvmti_thread_state()->update_thread_oop_during_vm_start(thread); + thread->jvmti_thread_state()->update_thread_oop_during_vm_start(); } // can now enable some events diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index cc2bc0f2c10ae..e76782e3d3385 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -1041,11 +1041,10 @@ oop JvmtiThreadState::get_thread_oop() { return _thread_oop_h.resolve(); } -void JvmtiThreadState::update_thread_oop_during_vm_start(JavaThread* thread) { - assert(thread->threadObj() != nullptr, "santity check"); - if (thread->jvmti_thread_state()->get_thread_oop() == nullptr) { - _thread_oop_h.release(JvmtiExport::jvmti_oop_storage()); - _thread_oop_h = OopHandle(JvmtiExport::jvmti_oop_storage(), thread->threadObj()); +void JvmtiThreadState::update_thread_oop_during_vm_start() { + assert(_thread->threadObj() != nullptr, "santity check"); + if (get_thread_oop() == nullptr) { + _thread_oop_h.replace(_thread->threadObj()); } } diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 364c786648d5d..cec251613f36d 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -311,7 +311,8 @@ class JvmtiThreadState : public CHeapObj { // Also used for carrier threads to clear/restore _thread. void set_thread(JavaThread* thread); oop get_thread_oop(); - void update_thread_oop_during_vm_start(JavaThread* thread); + + void update_thread_oop_during_vm_start(); inline bool is_virtual() { return _is_virtual; } // the _thread is virtual From 739b0c1c287df1131393b9631d990d07b42ec72e Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 15 Jul 2025 16:33:23 -0700 Subject: [PATCH 4/4] fixed test --- .../jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java index 5249d8dc83566..35d3d56441558 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java +++ b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.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 @@ -29,7 +29,7 @@ * @requires vm.jvmti * @run main/othervm/native -agentlib:AllowedFunctions AllowedFunctions * @run main/othervm/native -agentlib:AllowedFunctions=with_early_vmstart AllowedFunctions - * @run main/othervm/native -agentlib:AllowedFunctions=with_early_vmstart -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n AllowedFunctions + * @run main/othervm/native -agentlib:AllowedFunctions=with_early_vmstart -Xrunjdwp:transport=dt_socket,address=0,server=y,suspend=n AllowedFunctions */ public class AllowedFunctions {