| // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #if !defined(PRODUCT) |
| |
| #include "vm/microtask_mirror_queues.h" |
| |
| #include <utility> |
| |
| #include "platform/hashmap.h" |
| #include "vm/flags.h" |
| #include "vm/object.h" |
| #include "vm/timeline.h" |
| |
| namespace dart { |
| |
| MicrotaskMirrorQueue* MicrotaskMirrorQueues::GetQueue(int64_t isolate_id) { |
| void* key = reinterpret_cast<void*>(isolate_id); |
| const intptr_t hash = Utils::WordHash(isolate_id); |
| |
| MutexLocker ml(&isolate_id_to_queue_lock_); |
| |
| SimpleHashMap::Entry* entry = isolate_id_to_queue_.Lookup(key, hash, true); |
| if (entry->value == nullptr) { |
| entry->value = new MicrotaskMirrorQueue(); |
| } |
| return static_cast<MicrotaskMirrorQueue*>(entry->value); |
| } |
| |
| void MicrotaskMirrorQueue::OnScheduleAsyncCallback(const StackTrace& st) { |
| if (is_disabled_) { |
| return; |
| } |
| |
| queue_.PushBack(MicrotaskMirrorQueueEntry( |
| next_available_id_++, CStringUniquePtr(Utils::StrDup(st.ToCString())))); |
| } |
| |
| void MicrotaskMirrorQueue::OnSchedulePriorityAsyncCallback() { |
| // If this function is called, it means that the microtask queue can no longer |
| // be accurately modeled by a |ListQueue|. This only ever gets called when an |
| // exception goes unhandled, so we just handle the situation by disabling all |
| // further reads from / writes to this queue. |
| is_disabled_ = true; |
| } |
| |
| void MicrotaskMirrorQueue::OnAsyncCallbackComplete(int64_t start_time, |
| int64_t end_time) { |
| if (is_disabled_) { |
| return; |
| } |
| |
| ASSERT(queue_.Length() >= 1); |
| MicrotaskMirrorQueueEntry&& front = std::move(queue_.PopFront()); |
| |
| TimelineStream* stream = Timeline::GetMicrotaskStream(); |
| ASSERT(stream != nullptr); |
| TimelineEvent* event = stream->StartEvent(); |
| if (event != nullptr) { |
| if (start_time < end_time) { |
| event->Duration("Microtask", start_time, end_time); |
| } else { |
| event->Instant("Microtask", start_time); |
| } |
| |
| event->SetNumArguments(2); |
| event->FormatArgument(0, "microtaskId", "%" Pd, front.id()); |
| event->SetArgument(1, "stack trace captured when microtask was enqueued", |
| front.ReleaseStackTrace()); |
| event->Complete(); |
| } |
| } |
| |
| Mutex MicrotaskMirrorQueues::isolate_id_to_queue_lock_; |
| |
| SimpleHashMap MicrotaskMirrorQueues::isolate_id_to_queue_( |
| &SimpleHashMap::SamePointerValue, |
| MicrotaskMirrorQueues::kIsolateIdToQueueInitialCapacity); |
| |
| void MicrotaskMirrorQueues::CleanUp() { |
| for (SimpleHashMap::Entry* entry = isolate_id_to_queue_.Start(); |
| entry != nullptr; entry = isolate_id_to_queue_.Next(entry)) { |
| MicrotaskMirrorQueue* value = |
| static_cast<MicrotaskMirrorQueue*>(entry->value); |
| delete value; |
| } |
| } |
| |
| } // namespace dart |
| |
| #endif // !defined(PRODUCT) |