blob: dcaf339a3fa62aa17e65a76b5d77fe6616b845f4 [file] [edit]
// Copyright (c) 2011, 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.
#include "vm/message.h"
#include <utility>
#include "vm/dart_api_state.h"
#include "vm/dart_entry.h"
#include "vm/object.h"
#include "vm/port.h"
namespace dart {
const Dart_Port Message::kIllegalPort = 0;
Message::Message(Dart_Port dest_port,
uint8_t* snapshot,
intptr_t snapshot_length,
MessageFinalizableData* finalizable_data,
Priority priority)
: dest_port_(dest_port),
payload_(snapshot),
snapshot_length_(snapshot_length),
finalizable_data_(finalizable_data),
priority_(priority) {
ASSERT(IsSnapshot());
}
Message::Message(Dart_Port dest_port, ObjectPtr raw_obj, Priority priority)
: dest_port_(dest_port), payload_(raw_obj), priority_(priority) {
ASSERT(!raw_obj->IsHeapObject());
ASSERT(IsRaw());
}
Message::Message(Dart_Port dest_port,
PersistentHandle* handle,
Priority priority)
: dest_port_(dest_port),
payload_(handle),
snapshot_length_(kPersistentHandleSnapshotLen),
priority_(priority) {
ASSERT(IsPersistentHandle());
}
Message::Message(PersistentHandle* handle, Priority priority)
: dest_port_(ILLEGAL_PORT),
payload_(handle),
snapshot_length_(kFinalizerSnapshotLen),
priority_(priority) {
ASSERT(IsFinalizerInvocationRequest());
}
Message::~Message() {
if (IsSnapshot()) {
free(payload_.snapshot_);
}
delete finalizable_data_;
if (IsPersistentHandle() || IsFinalizerInvocationRequest()) {
auto isolate_group = IsolateGroup::Current();
isolate_group->api_state()->FreePersistentHandle(
payload_.persistent_handle_);
}
}
MessageQueue::MessageQueue() {
head_ = nullptr;
tail_ = nullptr;
}
MessageQueue::~MessageQueue() {
// Ensure that all pending messages have been released.
Clear();
ASSERT(head_ == nullptr);
}
void MessageQueue::Enqueue(std::unique_ptr<Message> msg0, bool before_events) {
// TODO(mdempsky): Use unique_ptr internally?
Message* msg = msg0.release();
// Make sure messages are not reused.
ASSERT(msg->next_ == nullptr);
if (head_ == nullptr) {
// Only element in the queue.
ASSERT(tail_ == nullptr);
head_ = msg;
tail_ = msg;
} else {
ASSERT(tail_ != nullptr);
if (!before_events) {
// Append at the tail.
tail_->next_ = msg;
tail_ = msg;
} else {
ASSERT(msg->dest_port() == Message::kIllegalPort);
if (head_->dest_port() != Message::kIllegalPort) {
msg->next_ = head_;
head_ = msg;
} else {
Message* cur = head_;
while (cur->next_ != nullptr) {
if (cur->next_->dest_port() != Message::kIllegalPort) {
// Splice in the new message at the break.
msg->next_ = cur->next_;
cur->next_ = msg;
return;
}
cur = cur->next_;
}
// All pending messages are isolate library control messages. Append at
// the tail.
ASSERT(tail_ == cur);
ASSERT(tail_->dest_port() == Message::kIllegalPort);
tail_->next_ = msg;
tail_ = msg;
}
}
}
}
std::unique_ptr<Message> MessageQueue::Dequeue() {
Message* result = head_;
if (result != nullptr) {
head_ = result->next_;
// The following update to tail_ is not strictly needed.
if (head_ == nullptr) {
tail_ = nullptr;
}
#if defined(DEBUG)
result->next_ = result; // Make sure to trigger ASSERT in Enqueue.
#endif // DEBUG
return std::unique_ptr<Message>(result);
}
return nullptr;
}
void MessageQueue::Clear() {
std::unique_ptr<Message> cur(head_);
head_ = nullptr;
tail_ = nullptr;
while (cur != nullptr) {
std::unique_ptr<Message> next(cur->next_);
cur = std::move(next);
}
}
MessageQueue::Iterator::Iterator(const MessageQueue* queue) : next_(nullptr) {
Reset(queue);
}
MessageQueue::Iterator::~Iterator() {}
void MessageQueue::Iterator::Reset(const MessageQueue* queue) {
ASSERT(queue != nullptr);
next_ = queue->head_;
}
// returns false when there are no more messages left.
bool MessageQueue::Iterator::HasNext() {
return next_ != nullptr;
}
// Returns the current message and moves forward.
Message* MessageQueue::Iterator::Next() {
Message* current = next_;
next_ = next_->next_;
return current;
}
intptr_t MessageQueue::Length() const {
MessageQueue::Iterator it(this);
intptr_t length = 0;
while (it.HasNext()) {
it.Next();
length++;
}
return length;
}
} // namespace dart