diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 59f41f1c0dc..36663ab1088 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -371,6 +371,7 @@ void CompileQueue::delete_all() { // Iterate over all tasks in the compile queue while (current != nullptr) { + CompileTask* next = current->next(); if (!current->is_blocking()) { // Non-blocking task. No one is waiting for it, delete it now. delete current; @@ -379,7 +380,7 @@ void CompileQueue::delete_all() { // to delete the task. We cannot delete it here, because we do not // coordinate with waiters. We will notify the waiters later. } - current = current->next(); + current = next; } _first = nullptr; _last = nullptr; @@ -504,6 +505,8 @@ void CompileQueue::remove(CompileTask* task) { assert(task == _last, "Sanity"); _last = task->prev(); } + task->set_next(nullptr); + task->set_prev(nullptr); --_size; ++_total_removed; } @@ -1728,17 +1731,22 @@ void CompileBroker::wait_for_completion(CompileTask* task) { // It is harmless to check this status without the lock, because // completion is a stable property. - if (!task->is_complete() && is_compilation_disabled_forever()) { - // Task is not complete, and we are exiting for compilation shutdown. - // The task can still be executed by some compiler thread, therefore - // we cannot delete it. This will leave task allocated, which leaks it. - // At this (degraded) point, it is less risky to abandon the task, - // rather than attempting a more complicated deletion protocol. + if (!task->is_complete()) { + // Task is not complete, likely because we are exiting for compilation + // shutdown. The task can still be reached through the queue, or executed + // by some compiler thread. There is no coordination with either MCQ lock + // holders or compilers, therefore we cannot delete the task. + // + // This will leave task allocated, which leaks it. At this (degraded) point, + // it is less risky to abandon the task, rather than attempting a more + // complicated deletion protocol. free_task = false; } if (free_task) { assert(task->is_complete(), "Compilation should have completed"); + assert(task->next() == nullptr && task->prev() == nullptr, + "Completed task should not be in the queue"); // By convention, the waiter is responsible for deleting a // blocking CompileTask. Since there is only one waiter ever diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index c5f1c789039..e3b640372a3 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -74,6 +74,7 @@ CompileTask::CompileTask(int compile_id, _arena_bytes = 0; _next = nullptr; + _prev = nullptr; Atomic::add(&_active_tasks, 1, memory_order_relaxed); } diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 148bdd28009..2cc5e9afe3c 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -101,7 +101,8 @@ class CompileTask : public CHeapObj { #endif int _comp_level; int _num_inlined_bytecodes; - CompileTask* _next, *_prev; + CompileTask* _next; + CompileTask* _prev; // Fields used for logging why the compilation was initiated: jlong _time_queued; // time when task was enqueued jlong _time_started; // time when compilation started