| 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" | 7 #include "include/dart_api.h" |
| 8 #include "platform/globals.h" | 8 #include "platform/globals.h" |
| 9 | 9 |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 return zone->PrintToString("objects/%" Pd "", id); | 67 return zone->PrintToString("objects/%" Pd "", id); |
| 68 } | 68 } |
| 69 | 69 |
| 70 | 70 |
| 71 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs. | 71 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs. |
| 72 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; | 72 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; |
| 73 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; | 73 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; |
| 74 struct ServiceMethodDescriptor; | 74 struct ServiceMethodDescriptor; |
| 75 ServiceMethodDescriptor* FindMethod(const char* method_name); | 75 ServiceMethodDescriptor* FindMethod(const char* method_name); |
| 76 | 76 |
| 77 // TODO(turnidge): Build a general framework later. For now, we have | |
| 78 // a small set of well-known streams. | |
| 79 bool Service::needs_isolate_events_ = false; | |
| 80 bool Service::needs_debug_events_ = false; | |
| 81 bool Service::needs_gc_events_ = false; | |
| 82 bool Service::needs_echo_events_ = false; | |
| 83 bool Service::needs_graph_events_ = false; | |
| 84 | |
| 85 void Service::ListenStream(const char* stream_id) { | |
| 86 if (FLAG_trace_service) { | |
| 87 OS::Print("vm-service: starting stream '%s'\n", | |
| 88 stream_id); | |
| 89 } | |
| 90 if (strcmp(stream_id, "Isolate") == 0) { | |
| 91 needs_isolate_events_ = true; | |
| 92 } else if (strcmp(stream_id, "Debug") == 0) { | |
| 93 needs_debug_events_ = true; | |
| 94 } else if (strcmp(stream_id, "GC") == 0) { | |
| 95 needs_gc_events_ = true; | |
| 96 } else if (strcmp(stream_id, "_Echo") == 0) { | |
| 97 needs_echo_events_ = true; | |
| 98 } else if (strcmp(stream_id, "_Graph") == 0) { | |
| 99 needs_graph_events_ = true; | |
| 100 } else { | |
| 101 UNREACHABLE(); | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 void Service::CancelStream(const char* stream_id) { | |
| 106 if (FLAG_trace_service) { | |
| 107 OS::Print("vm-service: stopping stream '%s'\n", | |
| 108 stream_id); | |
| 109 } | |
| 110 if (strcmp(stream_id, "Isolate") == 0) { | |
| 111 needs_isolate_events_ = false; | |
| 112 } else if (strcmp(stream_id, "Debug") == 0) { | |
| 113 needs_debug_events_ = false; | |
| 114 } else if (strcmp(stream_id, "GC") == 0) { | |
| 115 needs_gc_events_ = false; | |
| 116 } else if (strcmp(stream_id, "_Echo") == 0) { | |
| 117 needs_echo_events_ = false; | |
| 118 } else if (strcmp(stream_id, "_Graph") == 0) { | |
| 119 needs_graph_events_ = false; | |
| 120 } else { | |
| 121 UNREACHABLE(); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { | 77 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
| 126 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); | 78 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
| 127 return reinterpret_cast<uint8_t*>(new_ptr); | 79 return reinterpret_cast<uint8_t*>(new_ptr); |
| 128 } | 80 } |
| 129 | 81 |
| 130 static void PrintMissingParamError(JSONStream* js, | 82 static void PrintMissingParamError(JSONStream* js, |
| 131 const char* param) { | 83 const char* param) { |
| 132 js->PrintError(kInvalidParams, | 84 js->PrintError(kInvalidParams, |
| 133 "%s expects the '%s' parameter", js->method(), param); | 85 "%s expects the '%s' parameter", js->method(), param); |
| 134 } | 86 } |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 InvokeMethod(isolate, msg_instance); | 485 InvokeMethod(isolate, msg_instance); |
| 534 } | 486 } |
| 535 | 487 |
| 536 | 488 |
| 537 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { | 489 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { |
| 538 ASSERT(isolate != NULL); | 490 ASSERT(isolate != NULL); |
| 539 InvokeMethod(isolate, msg); | 491 InvokeMethod(isolate, msg); |
| 540 } | 492 } |
| 541 | 493 |
| 542 | 494 |
| 543 void Service::SendEvent(const char* stream_id, | 495 bool Service::NeedsEvents() { |
| 544 const char* event_type, | 496 return ServiceIsolate::IsRunning(); |
| 545 const Object& event_message) { | 497 } |
| 498 |
| 499 |
| 500 void Service::SendEvent(intptr_t eventType, |
| 501 const Object& eventMessage) { |
| 546 ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())); | 502 ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())); |
| 547 if (!ServiceIsolate::IsRunning()) { | 503 if (!ServiceIsolate::IsRunning()) { |
| 548 return; | 504 return; |
| 549 } | 505 } |
| 550 Isolate* isolate = Isolate::Current(); | 506 Isolate* isolate = Isolate::Current(); |
| 551 ASSERT(isolate != NULL); | 507 ASSERT(isolate != NULL); |
| 552 HANDLESCOPE(isolate); | 508 HANDLESCOPE(isolate); |
| 553 | 509 |
| 554 const Array& list = Array::Handle(Array::New(2)); | |
| 555 ASSERT(!list.IsNull()); | |
| 556 const String& stream_id_str = String::Handle(String::New(stream_id)); | |
| 557 list.SetAt(0, stream_id_str); | |
| 558 list.SetAt(1, event_message); | |
| 559 | |
| 560 // Push the event to port_. | 510 // Push the event to port_. |
| 561 uint8_t* data = NULL; | 511 uint8_t* data = NULL; |
| 562 MessageWriter writer(&data, &allocator, false); | 512 MessageWriter writer(&data, &allocator, false); |
| 563 writer.WriteMessage(list); | 513 writer.WriteMessage(eventMessage); |
| 564 intptr_t len = writer.BytesWritten(); | 514 intptr_t len = writer.BytesWritten(); |
| 565 if (FLAG_trace_service) { | 515 if (FLAG_trace_service) { |
| 566 OS::Print( | 516 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n", |
| 567 "vm-service: Pushing event of type %s to stream %s, len %" Pd "\n", | 517 eventType, len); |
| 568 event_type, stream_id, len); | |
| 569 } | 518 } |
| 570 // TODO(turnidge): For now we ignore failure to send an event. Revisit? | 519 // TODO(turnidge): For now we ignore failure to send an event. Revisit? |
| 571 PortMap::PostMessage( | 520 PortMap::PostMessage( |
| 572 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); | 521 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); |
| 573 } | 522 } |
| 574 | 523 |
| 575 | 524 |
| 576 void Service::SendEventWithData(const char* stream_id, | 525 void Service::SendEvent(const String& meta, |
| 577 const char* event_type, | 526 const uint8_t* data, |
| 578 const String& meta, | 527 intptr_t size) { |
| 579 const uint8_t* data, | |
| 580 intptr_t size) { | |
| 581 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] | 528 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] |
| 582 const intptr_t meta_bytes = Utf8::Length(meta); | 529 const intptr_t meta_bytes = Utf8::Length(meta); |
| 583 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; | 530 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; |
| 584 const TypedData& message = TypedData::Handle( | 531 const TypedData& message = TypedData::Handle( |
| 585 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); | 532 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); |
| 586 intptr_t offset = 0; | 533 intptr_t offset = 0; |
| 587 // TODO(koda): Rename these methods SetHostUint64, etc. | 534 // TODO(koda): Rename these methods SetHostUint64, etc. |
| 588 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes)); | 535 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes)); |
| 589 offset += sizeof(uint64_t); | 536 offset += sizeof(uint64_t); |
| 590 { | 537 { |
| 591 NoSafepointScope no_safepoint; | 538 NoSafepointScope no_safepoint; |
| 592 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes); | 539 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes); |
| 593 offset += meta_bytes; | 540 offset += meta_bytes; |
| 594 } | 541 } |
| 595 // TODO(koda): It would be nice to avoid this copy (requires changes to | 542 // TODO(koda): It would be nice to avoid this copy (requires changes to |
| 596 // MessageWriter code). | 543 // MessageWriter code). |
| 597 { | 544 { |
| 598 NoSafepointScope no_safepoint; | 545 NoSafepointScope no_safepoint; |
| 599 memmove(message.DataAddr(offset), data, size); | 546 memmove(message.DataAddr(offset), data, size); |
| 600 offset += size; | 547 offset += size; |
| 601 } | 548 } |
| 602 ASSERT(offset == total_bytes); | 549 ASSERT(offset == total_bytes); |
| 603 SendEvent(stream_id, event_type, message); | 550 // TODO(turnidge): Pass the real eventType here. |
| 551 SendEvent(0, message); |
| 604 } | 552 } |
| 605 | 553 |
| 606 | 554 |
| 607 void Service::HandleEvent(ServiceEvent* event) { | 555 void Service::HandleEvent(ServiceEvent* event) { |
| 608 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { | 556 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { |
| 609 return; | 557 return; |
| 610 } | 558 } |
| 611 JSONStream js; | 559 JSONStream js; |
| 612 const char* stream_id = event->stream_id(); | |
| 613 ASSERT(stream_id != NULL); | |
| 614 { | 560 { |
| 615 JSONObject jsobj(&js); | 561 JSONObject jsobj(&js); |
| 616 jsobj.AddProperty("event", event); | 562 jsobj.AddProperty("event", event); |
| 617 jsobj.AddProperty("streamId", stream_id); | |
| 618 } | 563 } |
| 619 const String& message = String::Handle(String::New(js.ToCString())); | 564 const String& message = String::Handle(String::New(js.ToCString())); |
| 620 SendEvent(stream_id, ServiceEvent::EventTypeToCString(event->type()), | 565 SendEvent(event->type(), message); |
| 621 message); | |
| 622 } | 566 } |
| 623 | 567 |
| 624 | 568 |
| 625 class EmbedderServiceHandler { | 569 class EmbedderServiceHandler { |
| 626 public: | 570 public: |
| 627 explicit EmbedderServiceHandler(const char* name) : name_(NULL), | 571 explicit EmbedderServiceHandler(const char* name) : name_(NULL), |
| 628 callback_(NULL), | 572 callback_(NULL), |
| 629 user_data_(NULL), | 573 user_data_(NULL), |
| 630 next_(NULL) { | 574 next_(NULL) { |
| 631 ASSERT(name != NULL); | 575 ASSERT(name != NULL); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 660 EmbedderServiceHandler* next_; | 604 EmbedderServiceHandler* next_; |
| 661 }; | 605 }; |
| 662 | 606 |
| 663 | 607 |
| 664 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, | 608 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, |
| 665 JSONStream* js) { | 609 JSONStream* js) { |
| 666 ASSERT(handler != NULL); | 610 ASSERT(handler != NULL); |
| 667 Dart_ServiceRequestCallback callback = handler->callback(); | 611 Dart_ServiceRequestCallback callback = handler->callback(); |
| 668 ASSERT(callback != NULL); | 612 ASSERT(callback != NULL); |
| 669 const char* r = NULL; | 613 const char* r = NULL; |
| 670 const char* method = js->method(); | 614 const char* name = js->method(); |
| 671 const char** keys = js->param_keys(); | 615 const char** keys = js->param_keys(); |
| 672 const char** values = js->param_values(); | 616 const char** values = js->param_values(); |
| 673 r = callback(method, keys, values, js->num_params(), handler->user_data()); | 617 r = callback(name, keys, values, js->num_params(), handler->user_data()); |
| 674 ASSERT(r != NULL); | 618 ASSERT(r != NULL); |
| 675 // TODO(johnmccutchan): Allow for NULL returns? | 619 // TODO(johnmccutchan): Allow for NULL returns? |
| 676 TextBuffer* buffer = js->buffer(); | 620 TextBuffer* buffer = js->buffer(); |
| 677 buffer->AddString(r); | 621 buffer->AddString(r); |
| 678 free(const_cast<char*>(r)); | 622 free(const_cast<char*>(r)); |
| 679 } | 623 } |
| 680 | 624 |
| 681 | 625 |
| 682 void Service::RegisterIsolateEmbedderCallback( | 626 void Service::RegisterIsolateEmbedderCallback( |
| 683 const char* name, | 627 const char* name, |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 JSONObject jsobj(&js); | 764 JSONObject jsobj(&js); |
| 821 { | 765 { |
| 822 JSONObject event(&jsobj, "event"); | 766 JSONObject event(&jsobj, "event"); |
| 823 event.AddProperty("type", "ServiceEvent"); | 767 event.AddProperty("type", "ServiceEvent"); |
| 824 event.AddProperty("eventType", "_Echo"); | 768 event.AddProperty("eventType", "_Echo"); |
| 825 event.AddProperty("isolate", isolate); | 769 event.AddProperty("isolate", isolate); |
| 826 if (text != NULL) { | 770 if (text != NULL) { |
| 827 event.AddProperty("text", text); | 771 event.AddProperty("text", text); |
| 828 } | 772 } |
| 829 } | 773 } |
| 830 jsobj.AddProperty("streamId", "_Echo"); | |
| 831 } | 774 } |
| 832 const String& message = String::Handle(String::New(js.ToCString())); | 775 const String& message = String::Handle(String::New(js.ToCString())); |
| 833 uint8_t data[] = {0, 128, 255}; | 776 uint8_t data[] = {0, 128, 255}; |
| 834 SendEventWithData("_Echo", "_Echo", message, data, sizeof(data)); | 777 SendEvent(message, data, sizeof(data)); |
| 835 } | 778 } |
| 836 | 779 |
| 837 | 780 |
| 838 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { | 781 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { |
| 839 Service::SendEchoEvent(isolate, js->LookupParam("text")); | 782 Service::SendEchoEvent(isolate, js->LookupParam("text")); |
| 840 JSONObject jsobj(js); | 783 JSONObject jsobj(js); |
| 841 return HandleCommonEcho(&jsobj, js); | 784 return HandleCommonEcho(&jsobj, js); |
| 842 } | 785 } |
| 843 | 786 |
| 844 | 787 |
| (...skipping 1271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2116 NULL, | 2059 NULL, |
| 2117 }; | 2060 }; |
| 2118 | 2061 |
| 2119 | 2062 |
| 2120 static bool Resume(Isolate* isolate, JSONStream* js) { | 2063 static bool Resume(Isolate* isolate, JSONStream* js) { |
| 2121 const char* step_param = js->LookupParam("step"); | 2064 const char* step_param = js->LookupParam("step"); |
| 2122 if (isolate->message_handler()->paused_on_start()) { | 2065 if (isolate->message_handler()->paused_on_start()) { |
| 2123 isolate->message_handler()->set_pause_on_start(false); | 2066 isolate->message_handler()->set_pause_on_start(false); |
| 2124 JSONObject jsobj(js); | 2067 JSONObject jsobj(js); |
| 2125 jsobj.AddProperty("type", "Success"); | 2068 jsobj.AddProperty("type", "Success"); |
| 2126 if (Service::NeedsDebugEvents()) { | 2069 { |
| 2127 ServiceEvent event(isolate, ServiceEvent::kResume); | 2070 ServiceEvent event(isolate, ServiceEvent::kResume); |
| 2128 Service::HandleEvent(&event); | 2071 Service::HandleEvent(&event); |
| 2129 } | 2072 } |
| 2130 return true; | 2073 return true; |
| 2131 } | 2074 } |
| 2132 if (isolate->message_handler()->paused_on_exit()) { | 2075 if (isolate->message_handler()->paused_on_exit()) { |
| 2133 isolate->message_handler()->set_pause_on_exit(false); | 2076 isolate->message_handler()->set_pause_on_exit(false); |
| 2134 JSONObject jsobj(js); | 2077 JSONObject jsobj(js); |
| 2135 jsobj.AddProperty("type", "Success"); | 2078 jsobj.AddProperty("type", "Success"); |
| 2136 // We don't send a resume event because we will be exiting. | 2079 // We don't send a resume event because we will be exiting. |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2333 jsobj.AddProperty("streamId", "_Graph"); | 2276 jsobj.AddProperty("streamId", "_Graph"); |
| 2334 } | 2277 } |
| 2335 | 2278 |
| 2336 const String& message = String::Handle(String::New(js.ToCString())); | 2279 const String& message = String::Handle(String::New(js.ToCString())); |
| 2337 | 2280 |
| 2338 uint8_t* chunk_start = buffer + (i * kChunkSize); | 2281 uint8_t* chunk_start = buffer + (i * kChunkSize); |
| 2339 intptr_t chunk_size = (i + 1 == num_chunks) | 2282 intptr_t chunk_size = (i + 1 == num_chunks) |
| 2340 ? stream.bytes_written() - (i * kChunkSize) | 2283 ? stream.bytes_written() - (i * kChunkSize) |
| 2341 : kChunkSize; | 2284 : kChunkSize; |
| 2342 | 2285 |
| 2343 SendEventWithData("_Graph", "_Graph", message, chunk_start, chunk_size); | 2286 SendEvent(message, chunk_start, chunk_size); |
| 2344 } | 2287 } |
| 2345 } | 2288 } |
| 2346 | 2289 |
| 2347 | 2290 |
| 2348 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { | 2291 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { |
| 2349 if (!Service::NeedsDebugEvents()) { | |
| 2350 return; | |
| 2351 } | |
| 2352 ServiceEvent event(isolate, ServiceEvent::kInspect); | 2292 ServiceEvent event(isolate, ServiceEvent::kInspect); |
| 2353 event.set_inspectee(&inspectee); | 2293 event.set_inspectee(&inspectee); |
| 2354 Service::HandleEvent(&event); | 2294 Service::HandleEvent(&event); |
| 2355 } | 2295 } |
| 2356 | 2296 |
| 2357 | 2297 |
| 2358 class ContainsAddressVisitor : public FindObjectVisitor { | 2298 class ContainsAddressVisitor : public FindObjectVisitor { |
| 2359 public: | 2299 public: |
| 2360 ContainsAddressVisitor(Isolate* isolate, uword addr) | 2300 ContainsAddressVisitor(Isolate* isolate, uword addr) |
| 2361 : FindObjectVisitor(isolate), addr_(addr) { } | 2301 : FindObjectVisitor(isolate), addr_(addr) { } |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2623 | 2563 |
| 2624 static const MethodParameter* set_name_params[] = { | 2564 static const MethodParameter* set_name_params[] = { |
| 2625 ISOLATE_PARAMETER, | 2565 ISOLATE_PARAMETER, |
| 2626 new MethodParameter("name", true), | 2566 new MethodParameter("name", true), |
| 2627 NULL, | 2567 NULL, |
| 2628 }; | 2568 }; |
| 2629 | 2569 |
| 2630 | 2570 |
| 2631 static bool SetName(Isolate* isolate, JSONStream* js) { | 2571 static bool SetName(Isolate* isolate, JSONStream* js) { |
| 2632 isolate->set_debugger_name(js->LookupParam("name")); | 2572 isolate->set_debugger_name(js->LookupParam("name")); |
| 2633 if (Service::NeedsIsolateEvents()) { | 2573 { |
| 2634 ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate); | 2574 ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate); |
| 2635 Service::HandleEvent(&event); | 2575 Service::HandleEvent(&event); |
| 2636 } | 2576 } |
| 2637 JSONObject jsobj(js); | 2577 JSONObject jsobj(js); |
| 2638 jsobj.AddProperty("type", "Success"); | 2578 jsobj.AddProperty("type", "Success"); |
| 2639 return true; | 2579 return true; |
| 2640 } | 2580 } |
| 2641 | 2581 |
| 2642 | 2582 |
| 2643 static ServiceMethodDescriptor service_methods_[] = { | 2583 static ServiceMethodDescriptor service_methods_[] = { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2726 ServiceMethodDescriptor& method = service_methods_[i]; | 2666 ServiceMethodDescriptor& method = service_methods_[i]; |
| 2727 if (strcmp(method_name, method.name) == 0) { | 2667 if (strcmp(method_name, method.name) == 0) { |
| 2728 return &method; | 2668 return &method; |
| 2729 } | 2669 } |
| 2730 } | 2670 } |
| 2731 return NULL; | 2671 return NULL; |
| 2732 } | 2672 } |
| 2733 | 2673 |
| 2734 | 2674 |
| 2735 } // namespace dart | 2675 } // namespace dart |
| OLD | NEW |