OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/service.h" | 5 #include "vm/service.h" |
6 | 6 |
| 7 #include "include/dart_api.h" |
| 8 |
| 9 #include "vm/compiler.h" |
7 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| 11 #include "vm/dart_api_impl.h" |
8 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
9 #include "vm/debugger.h" | 13 #include "vm/debugger.h" |
10 #include "vm/heap_histogram.h" | 14 #include "vm/heap_histogram.h" |
11 #include "vm/isolate.h" | 15 #include "vm/isolate.h" |
12 #include "vm/message.h" | 16 #include "vm/message.h" |
| 17 #include "vm/native_entry.h" |
| 18 #include "vm/native_arguments.h" |
13 #include "vm/object.h" | 19 #include "vm/object.h" |
14 #include "vm/object_id_ring.h" | 20 #include "vm/object_id_ring.h" |
15 #include "vm/object_store.h" | 21 #include "vm/object_store.h" |
16 #include "vm/port.h" | 22 #include "vm/port.h" |
17 #include "vm/profiler.h" | 23 #include "vm/profiler.h" |
| 24 #include "vm/symbols.h" |
| 25 |
18 | 26 |
19 namespace dart { | 27 namespace dart { |
20 | 28 |
21 typedef void (*ServiceMessageHandler)(Isolate* isolate, JSONStream* stream); | 29 struct ResourcesEntry { |
22 | 30 const char* path_; |
23 struct ServiceMessageHandlerEntry { | 31 const char* resource_; |
24 const char* command; | 32 int length_; |
25 ServiceMessageHandler handler; | |
26 }; | 33 }; |
27 | 34 |
28 static ServiceMessageHandler FindServiceMessageHandler(const char* command); | 35 extern ResourcesEntry __service_resources_[]; |
| 36 |
| 37 class Resources { |
| 38 public: |
| 39 static const int kNoSuchInstance = -1; |
| 40 static int ResourceLookup(const char* path, const char** resource) { |
| 41 ResourcesEntry* table = ResourceTable(); |
| 42 for (int i = 0; table[i].path_ != NULL; i++) { |
| 43 const ResourcesEntry& entry = table[i]; |
| 44 if (strcmp(path, entry.path_) == 0) { |
| 45 *resource = entry.resource_; |
| 46 ASSERT(entry.length_ > 0); |
| 47 return entry.length_; |
| 48 } |
| 49 } |
| 50 return kNoSuchInstance; |
| 51 } |
| 52 |
| 53 static const char* Path(int idx) { |
| 54 ASSERT(idx >= 0); |
| 55 ResourcesEntry* entry = At(idx); |
| 56 if (entry == NULL) { |
| 57 return NULL; |
| 58 } |
| 59 ASSERT(entry->path_ != NULL); |
| 60 return entry->path_; |
| 61 } |
| 62 |
| 63 static int Length(int idx) { |
| 64 ASSERT(idx >= 0); |
| 65 ResourcesEntry* entry = At(idx); |
| 66 if (entry == NULL) { |
| 67 return kNoSuchInstance; |
| 68 } |
| 69 ASSERT(entry->path_ != NULL); |
| 70 return entry->length_; |
| 71 } |
| 72 |
| 73 static const uint8_t* Resource(int idx) { |
| 74 ASSERT(idx >= 0); |
| 75 ResourcesEntry* entry = At(idx); |
| 76 if (entry == NULL) { |
| 77 return NULL; |
| 78 } |
| 79 return reinterpret_cast<const uint8_t*>(entry->resource_); |
| 80 } |
| 81 |
| 82 private: |
| 83 static ResourcesEntry* At(int idx) { |
| 84 ASSERT(idx >= 0); |
| 85 ResourcesEntry* table = ResourceTable(); |
| 86 for (int i = 0; table[i].path_ != NULL; i++) { |
| 87 if (idx == i) { |
| 88 return &table[i]; |
| 89 } |
| 90 } |
| 91 return NULL; |
| 92 } |
| 93 |
| 94 static ResourcesEntry* ResourceTable() { |
| 95 return &__service_resources_[0]; |
| 96 } |
| 97 |
| 98 DISALLOW_ALLOCATION(); |
| 99 DISALLOW_IMPLICIT_CONSTRUCTORS(Resources); |
| 100 }; |
29 | 101 |
30 | 102 |
31 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { | 103 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
32 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); | 104 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
33 return reinterpret_cast<uint8_t*>(new_ptr); | 105 return reinterpret_cast<uint8_t*>(new_ptr); |
34 } | 106 } |
35 | 107 |
36 | 108 |
| 109 static void SendServiceMessage(Dart_NativeArguments args) { |
| 110 NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| 111 Isolate* isolate = arguments->isolate(); |
| 112 StackZone zone(isolate); |
| 113 HANDLESCOPE(isolate); |
| 114 GET_NON_NULL_NATIVE_ARGUMENT(Instance, sp, arguments->NativeArgAt(0)); |
| 115 GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(1)); |
| 116 |
| 117 // Extract SendPort port id. |
| 118 const Object& sp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(sp)); |
| 119 if (sp_id_obj.IsError()) { |
| 120 Exceptions::PropagateError(Error::Cast(sp_id_obj)); |
| 121 } |
| 122 Integer& id = Integer::Handle(); |
| 123 id ^= sp_id_obj.raw(); |
| 124 Dart_Port sp_id = static_cast<Dart_Port>(id.AsInt64Value()); |
| 125 ASSERT(sp_id != ILLEGAL_PORT); |
| 126 |
| 127 // Serialize message. |
| 128 uint8_t* data = NULL; |
| 129 MessageWriter writer(&data, &allocator); |
| 130 writer.WriteMessage(message); |
| 131 |
| 132 // TODO(turnidge): Throw an exception when the return value is false? |
| 133 PortMap::PostMessage(new Message(sp_id, data, writer.BytesWritten(), |
| 134 Message::kOOBPriority)); |
| 135 } |
| 136 |
| 137 |
| 138 struct VmServiceNativeEntry { |
| 139 const char* name; |
| 140 int num_arguments; |
| 141 Dart_NativeFunction function; |
| 142 }; |
| 143 |
| 144 |
| 145 static VmServiceNativeEntry _VmServiceNativeEntries[] = { |
| 146 {"VMService_SendServiceMessage", 2, SendServiceMessage} |
| 147 }; |
| 148 |
| 149 |
| 150 static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name, |
| 151 int num_arguments, |
| 152 bool* auto_setup_scope) { |
| 153 const Object& obj = Object::Handle(Api::UnwrapHandle(name)); |
| 154 if (!obj.IsString()) { |
| 155 return NULL; |
| 156 } |
| 157 const char* function_name = obj.ToCString(); |
| 158 ASSERT(function_name != NULL); |
| 159 ASSERT(auto_setup_scope != NULL); |
| 160 *auto_setup_scope = true; |
| 161 intptr_t n = |
| 162 sizeof(_VmServiceNativeEntries) / sizeof(_VmServiceNativeEntries[0]); |
| 163 for (intptr_t i = 0; i < n; i++) { |
| 164 VmServiceNativeEntry entry = _VmServiceNativeEntries[i]; |
| 165 if (!strcmp(function_name, entry.name) && |
| 166 (num_arguments == entry.num_arguments)) { |
| 167 return entry.function; |
| 168 } |
| 169 } |
| 170 return NULL; |
| 171 } |
| 172 |
| 173 |
| 174 Isolate* Service::service_isolate_ = NULL; |
| 175 Dart_LibraryTagHandler Service::default_handler_ = NULL; |
| 176 Dart_Port Service::port_ = ILLEGAL_PORT; |
| 177 |
| 178 static Dart_Port ExtractPort(Dart_Handle receivePort) { |
| 179 HANDLESCOPE(Isolate::Current()); |
| 180 const Object& unwrapped_rp = Object::Handle(Api::UnwrapHandle(receivePort)); |
| 181 const Instance& rp = Instance::Cast(unwrapped_rp); |
| 182 // Extract RawReceivePort port id. |
| 183 const Object& rp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(rp)); |
| 184 if (rp_id_obj.IsError()) { |
| 185 return ILLEGAL_PORT; |
| 186 } |
| 187 ASSERT(rp_id_obj.IsSmi() || rp_id_obj.IsMint()); |
| 188 const Integer& id = Integer::Cast(rp_id_obj); |
| 189 return static_cast<Dart_Port>(id.AsInt64Value()); |
| 190 } |
| 191 |
| 192 |
| 193 Isolate* Service::GetServiceIsolate(void* callback_data) { |
| 194 if (service_isolate_ != NULL) { |
| 195 // Already initialized, return service isolate. |
| 196 return service_isolate_; |
| 197 } |
| 198 Dart_ServiceIsolateCreateCalback create_callback = |
| 199 Isolate::ServiceCreateCallback(); |
| 200 if (create_callback == NULL) { |
| 201 return NULL; |
| 202 } |
| 203 Isolate::SetCurrent(NULL); |
| 204 char* error = NULL; |
| 205 Isolate* isolate = reinterpret_cast<Isolate*>( |
| 206 create_callback(callback_data, &error)); |
| 207 if (isolate == NULL) { |
| 208 return NULL; |
| 209 } |
| 210 Isolate::SetCurrent(isolate); |
| 211 { |
| 212 // Install the dart:vmservice library. |
| 213 StackZone zone(isolate); |
| 214 HANDLESCOPE(isolate); |
| 215 Library& library = |
| 216 Library::Handle(isolate, isolate->object_store()->root_library()); |
| 217 // Isolate is empty. |
| 218 ASSERT(library.IsNull()); |
| 219 // Grab embedder tag handler. |
| 220 default_handler_ = isolate->library_tag_handler(); |
| 221 ASSERT(default_handler_ != NULL); |
| 222 // Temporarily install our own. |
| 223 isolate->set_library_tag_handler(LibraryTagHandler); |
| 224 // Get script resource. |
| 225 const char* resource = NULL; |
| 226 const char* path = "/vmservice.dart"; |
| 227 intptr_t r = Resources::ResourceLookup(path, &resource); |
| 228 ASSERT(r != Resources::kNoSuchInstance); |
| 229 ASSERT(resource != NULL); |
| 230 const String& source_str = String::Handle( |
| 231 String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r)); |
| 232 ASSERT(!source_str.IsNull()); |
| 233 const String& url_str = String::Handle(Symbols::DartVMService().raw()); |
| 234 library ^= Library::LookupLibrary(url_str); |
| 235 ASSERT(library.IsNull()); |
| 236 // Setup library. |
| 237 library = Library::New(url_str); |
| 238 library.Register(); |
| 239 const Script& script = Script::Handle( |
| 240 isolate, Script::New(url_str, source_str, RawScript::kLibraryTag)); |
| 241 library.SetLoadInProgress(); |
| 242 Dart_EnterScope(); // Need to enter scope for tag handler. |
| 243 const Error& error = Error::Handle(isolate, |
| 244 Compiler::Compile(library, script)); |
| 245 ASSERT(error.IsNull()); |
| 246 Dart_ExitScope(); |
| 247 library.SetLoaded(); |
| 248 // Install embedder default library tag handler again. |
| 249 isolate->set_library_tag_handler(default_handler_); |
| 250 default_handler_ = NULL; |
| 251 library.set_native_entry_resolver(VmServiceNativeResolver); |
| 252 } |
| 253 { |
| 254 // Boot the dart:vmservice library. |
| 255 Dart_EnterScope(); |
| 256 Dart_Handle result; |
| 257 Dart_Handle url_str = |
| 258 Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId)); |
| 259 Dart_Handle library = Dart_LookupLibrary(url_str); |
| 260 ASSERT(Dart_IsLibrary(library)); |
| 261 result = Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL); |
| 262 ASSERT(!Dart_IsError(result)); |
| 263 port_ = ExtractPort(result); |
| 264 ASSERT(port_ != ILLEGAL_PORT); |
| 265 Dart_ExitScope(); |
| 266 } |
| 267 Isolate::SetCurrent(NULL); |
| 268 service_isolate_ = reinterpret_cast<Isolate*>(isolate); |
| 269 return service_isolate_; |
| 270 } |
| 271 |
| 272 |
| 273 // These must be kept in sync with service/constants.dart |
| 274 #define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1 |
| 275 #define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2 |
| 276 |
| 277 |
| 278 static RawArray* MakeServiceControlMessage(Dart_Port port_id, intptr_t code, |
| 279 const String& name) { |
| 280 const Array& list = Array::Handle(Array::New(4)); |
| 281 ASSERT(!list.IsNull()); |
| 282 const Integer& code_int = Integer::Handle(Integer::New(code)); |
| 283 const Integer& port_int = Integer::Handle(Integer::New(port_id)); |
| 284 const Object& send_port = Object::Handle( |
| 285 DartLibraryCalls::NewSendPort(port_id)); |
| 286 ASSERT(!send_port.IsNull()); |
| 287 list.SetAt(0, code_int); |
| 288 list.SetAt(1, port_int); |
| 289 list.SetAt(2, send_port); |
| 290 list.SetAt(3, name); |
| 291 return list.raw(); |
| 292 } |
| 293 |
| 294 |
| 295 bool Service::SendIsolateStartupMessage() { |
| 296 if (!IsRunning()) { |
| 297 return false; |
| 298 } |
| 299 Isolate* isolate = Isolate::Current(); |
| 300 ASSERT(isolate != NULL); |
| 301 HANDLESCOPE(isolate); |
| 302 const String& name = String::Handle(String::New(isolate->name())); |
| 303 ASSERT(!name.IsNull()); |
| 304 const Array& list = Array::Handle( |
| 305 MakeServiceControlMessage(Dart_GetMainPortId(), |
| 306 VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID, |
| 307 name)); |
| 308 ASSERT(!list.IsNull()); |
| 309 uint8_t* data = NULL; |
| 310 MessageWriter writer(&data, &allocator); |
| 311 writer.WriteMessage(list); |
| 312 intptr_t len = writer.BytesWritten(); |
| 313 return PortMap::PostMessage( |
| 314 new Message(port_, data, len, Message::kNormalPriority)); |
| 315 } |
| 316 |
| 317 |
| 318 bool Service::SendIsolateShutdownMessage() { |
| 319 if (!IsRunning()) { |
| 320 return false; |
| 321 } |
| 322 Isolate* isolate = Isolate::Current(); |
| 323 ASSERT(isolate != NULL); |
| 324 HANDLESCOPE(isolate); |
| 325 const Array& list = Array::Handle( |
| 326 MakeServiceControlMessage(Dart_GetMainPortId(), |
| 327 VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID, |
| 328 String::Handle(String::null()))); |
| 329 ASSERT(!list.IsNull()); |
| 330 uint8_t* data = NULL; |
| 331 MessageWriter writer(&data, &allocator); |
| 332 writer.WriteMessage(list); |
| 333 intptr_t len = writer.BytesWritten(); |
| 334 return PortMap::PostMessage( |
| 335 new Message(port_, data, len, Message::kNormalPriority)); |
| 336 } |
| 337 |
| 338 |
| 339 bool Service::IsRunning() { |
| 340 return port_ != ILLEGAL_PORT; |
| 341 } |
| 342 |
| 343 |
| 344 Dart_Handle Service::GetSource(const char* name) { |
| 345 ASSERT(name != NULL); |
| 346 int i = 0; |
| 347 while (true) { |
| 348 const char* path = Resources::Path(i); |
| 349 if (path == NULL) { |
| 350 break; |
| 351 } |
| 352 ASSERT(*path != '\0'); |
| 353 // Skip the '/'. |
| 354 path++; |
| 355 if (strcmp(name, path) == 0) { |
| 356 const uint8_t* str = Resources::Resource(i); |
| 357 intptr_t length = Resources::Length(i); |
| 358 return Dart_NewStringFromUTF8(str, length); |
| 359 } |
| 360 i++; |
| 361 } |
| 362 return Dart_Null(); |
| 363 } |
| 364 |
| 365 |
| 366 Dart_Handle Service::LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, |
| 367 Dart_Handle url) { |
| 368 if (!Dart_IsLibrary(library)) { |
| 369 return Dart_NewApiError("not a library"); |
| 370 } |
| 371 if (!Dart_IsString(url)) { |
| 372 return Dart_NewApiError("url is not a string"); |
| 373 } |
| 374 const char* url_string = NULL; |
| 375 Dart_Handle result = Dart_StringToCString(url, &url_string); |
| 376 if (Dart_IsError(result)) { |
| 377 return result; |
| 378 } |
| 379 if (tag == Dart_kImportTag) { |
| 380 // Embedder handles all requests for external libraries. |
| 381 ASSERT(default_handler_ != NULL); |
| 382 return default_handler_(tag, library, url); |
| 383 } |
| 384 ASSERT((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl)); |
| 385 if (tag == Dart_kCanonicalizeUrl) { |
| 386 // url is already canonicalized. |
| 387 return url; |
| 388 } |
| 389 Dart_Handle source = GetSource(url_string); |
| 390 if (Dart_IsError(source)) { |
| 391 return source; |
| 392 } |
| 393 return Dart_LoadSource(library, url, source); |
| 394 } |
| 395 |
| 396 |
| 397 typedef void (*ServiceMessageHandler)(Isolate* isolate, JSONStream* stream); |
| 398 |
| 399 struct ServiceMessageHandlerEntry { |
| 400 const char* command; |
| 401 ServiceMessageHandler handler; |
| 402 }; |
| 403 |
| 404 static ServiceMessageHandler FindServiceMessageHandler(const char* command); |
| 405 |
37 static void PostReply(const String& reply, const Instance& reply_port) { | 406 static void PostReply(const String& reply, const Instance& reply_port) { |
38 const Object& id_obj = Object::Handle( | 407 const Object& id_obj = Object::Handle( |
39 DartLibraryCalls::PortGetId(reply_port)); | 408 DartLibraryCalls::PortGetId(reply_port)); |
40 if (id_obj.IsError()) { | 409 if (id_obj.IsError()) { |
41 Exceptions::PropagateError(Error::Cast(id_obj)); | 410 Exceptions::PropagateError(Error::Cast(id_obj)); |
42 } | 411 } |
43 const Integer& id = Integer::Cast(id_obj); | 412 const Integer& id = Integer::Cast(id_obj); |
44 Dart_Port port = static_cast<Dart_Port>(id.AsInt64Value()); | 413 Dart_Port port = static_cast<Dart_Port>(id.AsInt64Value()); |
45 ASSERT(port != ILLEGAL_PORT); | 414 ASSERT(port != ILLEGAL_PORT); |
46 | 415 |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 for (intptr_t i = 0; i < num_message_handlers; i++) { | 1018 for (intptr_t i = 0; i < num_message_handlers; i++) { |
650 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; | 1019 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; |
651 if (!strcmp(command, entry.command)) { | 1020 if (!strcmp(command, entry.command)) { |
652 return entry.handler; | 1021 return entry.handler; |
653 } | 1022 } |
654 } | 1023 } |
655 return HandleFallthrough; | 1024 return HandleFallthrough; |
656 } | 1025 } |
657 | 1026 |
658 } // namespace dart | 1027 } // namespace dart |
OLD | NEW |