1// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/message.h"
6
7#include <utility>
8
9#include "vm/dart_api_state.h"
10#include "vm/dart_entry.h"
11#include "vm/json_stream.h"
12#include "vm/object.h"
13#include "vm/port.h"
14
15namespace dart {
16
17const Dart_Port Message::kIllegalPort = 0;
18
19Message::Message(Dart_Port dest_port,
20 uint8_t* snapshot,
21 intptr_t snapshot_length,
22 MessageFinalizableData* finalizable_data,
23 Priority priority)
24 : dest_port_(dest_port),
25 payload_(snapshot),
26 snapshot_length_(snapshot_length),
27 finalizable_data_(finalizable_data),
28 priority_(priority) {
29 ASSERT(IsSnapshot());
30}
31
32Message::Message(Dart_Port dest_port, ObjectPtr raw_obj, Priority priority)
33 : dest_port_(dest_port), payload_(raw_obj), priority_(priority) {
34 ASSERT(!raw_obj->IsHeapObject() || raw_obj->untag()->InVMIsolateHeap());
35 ASSERT(IsRaw());
36}
37
38Message::Message(Dart_Port dest_port,
39 PersistentHandle* handle,
40 Priority priority)
41 : dest_port_(dest_port),
42 payload_(handle),
43 snapshot_length_(kPersistentHandleSnapshotLen),
44 priority_(priority) {
45 ASSERT(IsPersistentHandle());
46}
47
48Message::Message(PersistentHandle* handle, Priority priority)
49 : dest_port_(ILLEGAL_PORT),
50 payload_(handle),
51 snapshot_length_(kFinalizerSnapshotLen),
52 priority_(priority) {
53 ASSERT(IsFinalizerInvocationRequest());
54}
55
56Message::~Message() {
57 if (IsSnapshot()) {
58 free(payload_.snapshot_);
59 }
60 delete finalizable_data_;
61 if (IsPersistentHandle() || IsFinalizerInvocationRequest()) {
62 auto isolate_group = IsolateGroup::Current();
63 isolate_group->api_state()->FreePersistentHandle(
64 ref: payload_.persistent_handle_);
65 }
66}
67
68intptr_t Message::Id() const {
69 // Messages are allocated on the C heap. Use the raw address as the id.
70 return reinterpret_cast<intptr_t>(this);
71}
72
73const char* Message::PriorityAsString(Priority priority) {
74 switch (priority) {
75 case kNormalPriority:
76 return "Normal";
77 break;
78 case kOOBPriority:
79 return "OOB";
80 break;
81 default:
82 UNIMPLEMENTED();
83 return nullptr;
84 }
85}
86
87MessageQueue::MessageQueue() {
88 head_ = nullptr;
89 tail_ = nullptr;
90}
91
92MessageQueue::~MessageQueue() {
93 // Ensure that all pending messages have been released.
94 Clear();
95 ASSERT(head_ == nullptr);
96}
97
98void MessageQueue::Enqueue(std::unique_ptr<Message> msg0, bool before_events) {
99 // TODO(mdempsky): Use unique_ptr internally?
100 Message* msg = msg0.release();
101
102 // Make sure messages are not reused.
103 ASSERT(msg->next_ == nullptr);
104 if (head_ == nullptr) {
105 // Only element in the queue.
106 ASSERT(tail_ == nullptr);
107 head_ = msg;
108 tail_ = msg;
109 } else {
110 ASSERT(tail_ != nullptr);
111 if (!before_events) {
112 // Append at the tail.
113 tail_->next_ = msg;
114 tail_ = msg;
115 } else {
116 ASSERT(msg->dest_port() == Message::kIllegalPort);
117 if (head_->dest_port() != Message::kIllegalPort) {
118 msg->next_ = head_;
119 head_ = msg;
120 } else {
121 Message* cur = head_;
122 while (cur->next_ != nullptr) {
123 if (cur->next_->dest_port() != Message::kIllegalPort) {
124 // Splice in the new message at the break.
125 msg->next_ = cur->next_;
126 cur->next_ = msg;
127 return;
128 }
129 cur = cur->next_;
130 }
131 // All pending messages are isolate library control messages. Append at
132 // the tail.
133 ASSERT(tail_ == cur);
134 ASSERT(tail_->dest_port() == Message::kIllegalPort);
135 tail_->next_ = msg;
136 tail_ = msg;
137 }
138 }
139 }
140}
141
142std::unique_ptr<Message> MessageQueue::Dequeue() {
143 Message* result = head_;
144 if (result != nullptr) {
145 head_ = result->next_;
146 // The following update to tail_ is not strictly needed.
147 if (head_ == nullptr) {
148 tail_ = nullptr;
149 }
150#if defined(DEBUG)
151 result->next_ = result; // Make sure to trigger ASSERT in Enqueue.
152#endif // DEBUG
153 return std::unique_ptr<Message>(result);
154 }
155 return nullptr;
156}
157
158void MessageQueue::Clear() {
159 std::unique_ptr<Message> cur(head_);
160 head_ = nullptr;
161 tail_ = nullptr;
162 while (cur != nullptr) {
163 std::unique_ptr<Message> next(cur->next_);
164 cur = std::move(next);
165 }
166}
167
168MessageQueue::Iterator::Iterator(const MessageQueue* queue) : next_(nullptr) {
169 Reset(queue);
170}
171
172MessageQueue::Iterator::~Iterator() {}
173
174void MessageQueue::Iterator::Reset(const MessageQueue* queue) {
175 ASSERT(queue != nullptr);
176 next_ = queue->head_;
177}
178
179// returns false when there are no more messages left.
180bool MessageQueue::Iterator::HasNext() {
181 return next_ != nullptr;
182}
183
184// Returns the current message and moves forward.
185Message* MessageQueue::Iterator::Next() {
186 Message* current = next_;
187 next_ = next_->next_;
188 return current;
189}
190
191intptr_t MessageQueue::Length() const {
192 MessageQueue::Iterator it(this);
193 intptr_t length = 0;
194 while (it.HasNext()) {
195 it.Next();
196 length++;
197 }
198 return length;
199}
200
201Message* MessageQueue::FindMessageById(intptr_t id) {
202 MessageQueue::Iterator it(this);
203 while (it.HasNext()) {
204 Message* current = it.Next();
205 ASSERT(current != nullptr);
206 if (current->Id() == id) {
207 return current;
208 }
209 }
210 return nullptr;
211}
212
213void MessageQueue::PrintJSON(JSONStream* stream) {
214#ifndef PRODUCT
215 JSONArray messages(stream);
216
217 Object& msg_handler = Object::Handle();
218
219 MessageQueue::Iterator it(this);
220 intptr_t depth = 0;
221 while (it.HasNext()) {
222 Message* current = it.Next();
223 JSONObject message(&messages);
224 message.AddProperty(name: "type", s: "Message");
225 message.AddPropertyF("name", "Isolate Message (%" Px ")", current->Id());
226 message.AddPropertyF("messageObjectId", "messages/%" Px "", current->Id());
227 message.AddProperty(name: "size", i: current->Size());
228 message.AddProperty(name: "index", i: depth++);
229 message.AddPropertyF("_destinationPort", "%" Pd64 "",
230 static_cast<int64_t>(current->dest_port()));
231 message.AddProperty(name: "_priority",
232 s: Message::PriorityAsString(priority: current->priority()));
233 // TODO(johnmccutchan): Move port -> handler map out of Dart and into the
234 // VM, that way we can lookup the handler without invoking Dart code.
235 msg_handler = DartLibraryCalls::LookupHandler(port_id: current->dest_port());
236 if (msg_handler.IsClosure()) {
237 // Grab function from closure.
238 msg_handler = Closure::Cast(obj: msg_handler).function();
239 }
240 if (msg_handler.IsFunction()) {
241 const Function& function = Function::Cast(obj: msg_handler);
242 message.AddProperty(name: "handler", obj: function);
243
244 const Script& script = Script::Handle(ptr: function.script());
245 if (!script.IsNull()) {
246 message.AddLocation(script, token_pos: function.token_pos(),
247 end_token_pos: function.end_token_pos());
248 }
249 }
250 }
251#endif // !PRODUCT
252}
253
254} // namespace dart
255

source code of dart_sdk/runtime/vm/message.cc