| /* | |
| * 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 | |
| * 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 "logging/log.hpp" | |
| #include "runtime/atomic.hpp" | |
| #include "runtime/frame.inline.hpp" | |
| #include "runtime/javaThread.inline.hpp" | |
| #include "runtime/safepoint.hpp" | |
| #include "runtime/safepointMechanism.inline.hpp" | |
| #include "runtime/stackWatermark.inline.hpp" | |
| #include "runtime/stackWatermarkSet.inline.hpp" | |
| #include "runtime/threadSMR.hpp" | |
| #include "runtime/vmOperation.hpp" | |
| #include "runtime/vmThread.hpp" | |
| #include "utilities/debug.hpp" | |
| #include "utilities/globalDefinitions.hpp" | |
| #include "utilities/preserveException.hpp" | |
| #include "utilities/vmError.hpp" | |
| StackWatermarks::StackWatermarks() : | |
| _head(nullptr) {} | |
| StackWatermarks::~StackWatermarks() { | |
| StackWatermark* current = _head; | |
| while (current != nullptr) { | |
| StackWatermark* next = current->next(); | |
| delete current; | |
| current = next; | |
| } | |
| } | |
| StackWatermark* StackWatermarkSet::head(JavaThread* jt) { | |
| return jt->stack_watermarks()->_head; | |
| } | |
| void StackWatermarkSet::set_head(JavaThread* jt, StackWatermark* watermark) { | |
| jt->stack_watermarks()->_head = watermark; | |
| } | |
| void StackWatermarkSet::add_watermark(JavaThread* jt, StackWatermark* watermark) { | |
| assert(!has_watermark(jt, watermark->kind()), "Two instances of same kind"); | |
| StackWatermark* prev = head(jt); | |
| watermark->set_next(prev); | |
| set_head(jt, watermark); | |
| } | |
| static void verify_processing_context() { | |
| #ifdef ASSERT | |
| Thread* thread = Thread::current(); | |
| if (thread->is_Java_thread()) { | |
| JavaThread* jt = JavaThread::cast(thread); | |
| JavaThreadState state = jt->thread_state(); | |
| assert(state != _thread_in_native, "unsafe thread state"); | |
| assert(state != _thread_blocked, "unsafe thread state"); | |
| } else if (thread->is_VM_thread()) { | |
| } else { | |
| assert_locked_or_safepoint(Threads_lock); | |
| } | |
| #endif | |
| } | |
| void StackWatermarkSet::before_unwind(JavaThread* jt) { | |
| verify_processing_context(); | |
| assert(jt->has_last_Java_frame(), "must have a Java frame"); | |
| for (StackWatermark* current = head(jt); current != nullptr; current = current->next()) { | |
| current->before_unwind(); | |
| } | |
| SafepointMechanism::update_poll_values(jt); | |
| } | |
| void StackWatermarkSet::after_unwind(JavaThread* jt) { | |
| verify_processing_context(); | |
| assert(jt->has_last_Java_frame(), "must have a Java frame"); | |
| for (StackWatermark* current = head(jt); current != nullptr; current = current->next()) { | |
| current->after_unwind(); | |
| } | |
| SafepointMechanism::update_poll_values(jt); | |
| } | |
| void StackWatermarkSet::on_iteration(JavaThread* jt, const frame& fr) { | |
| if (VMError::is_error_reported()) { | |
| // Don't perform barrier when error reporting walks the stack. | |
| return; | |
| } | |
| verify_processing_context(); | |
| for (StackWatermark* current = head(jt); current != nullptr; current = current->next()) { | |
| current->on_iteration(fr); | |
| } | |
| // We don't call SafepointMechanism::update_poll_values here, because the thread | |
| // calling this might not be Thread::current(). | |
| } | |
| void StackWatermarkSet::on_safepoint(JavaThread* jt) { | |
| StackWatermark* watermark = get(jt, StackWatermarkKind::gc); | |
| if (watermark != nullptr) { | |
| watermark->on_safepoint(); | |
| } | |
| } | |
| void StackWatermarkSet::start_processing(JavaThread* jt, StackWatermarkKind kind) { | |
| verify_processing_context(); | |
| StackWatermark* watermark = get(jt, kind); | |
| if (watermark != nullptr) { | |
| watermark->start_processing(); | |
| } | |
| // We don't call SafepointMechanism::update_poll_values here, because the thread | |
| // calling this might not be Thread::current(). The thread the stack belongs to | |
| // will always update the poll values when waking up from a safepoint. | |
| } | |
| bool StackWatermarkSet::processing_started(JavaThread* jt) { | |
| for (StackWatermark* current = head(jt); current != nullptr; current = current->next()) { | |
| if (!current->processing_started()) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| void StackWatermarkSet::finish_processing(JavaThread* jt, void* context, StackWatermarkKind kind) { | |
| StackWatermark* watermark = get(jt, kind); | |
| if (watermark != nullptr) { | |
| watermark->finish_processing(context); | |
| } | |
| // We don't call SafepointMechanism::update_poll_values here, because the thread | |
| // calling this might not be Thread::current(). | |
| } | |
| uintptr_t StackWatermarkSet::lowest_watermark(JavaThread* jt) { | |
| uintptr_t max_watermark = uintptr_t(0) - 1; | |
| uintptr_t watermark = max_watermark; | |
| for (StackWatermark* current = head(jt); current != nullptr; current = current->next()) { | |
| watermark = MIN2(watermark, current->watermark()); | |
| } | |
| if (watermark == max_watermark) { | |
| return 0; | |
| } else { | |
| return watermark; | |
| } | |
| } | |
| void StackWatermarkSet::safepoint_synchronize_begin() { | |
| if (VMThread::vm_operation()->skip_thread_oop_barriers()) { | |
| return; | |
| } | |
| for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) { | |
| StackWatermarkSet::start_processing(thread, StackWatermarkKind::gc); | |
| } | |
| } |