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 |
77 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { | 125 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
78 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); | 126 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
79 return reinterpret_cast<uint8_t*>(new_ptr); | 127 return reinterpret_cast<uint8_t*>(new_ptr); |
80 } | 128 } |
81 | 129 |
82 static void PrintMissingParamError(JSONStream* js, | 130 static void PrintMissingParamError(JSONStream* js, |
83 const char* param) { | 131 const char* param) { |
84 js->PrintError(kInvalidParams, | 132 js->PrintError(kInvalidParams, |
85 "%s expects the '%s' parameter", js->method(), param); | 133 "%s expects the '%s' parameter", js->method(), param); |
86 } | 134 } |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
485 InvokeMethod(isolate, msg_instance); | 533 InvokeMethod(isolate, msg_instance); |
486 } | 534 } |
487 | 535 |
488 | 536 |
489 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { | 537 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { |
490 ASSERT(isolate != NULL); | 538 ASSERT(isolate != NULL); |
491 InvokeMethod(isolate, msg); | 539 InvokeMethod(isolate, msg); |
492 } | 540 } |
493 | 541 |
494 | 542 |
495 bool Service::NeedsEvents() { | 543 void Service::SendEvent(const char* stream_id, |
496 return ServiceIsolate::IsRunning(); | 544 const char* event_type, |
497 } | 545 const Object& event_message) { |
498 | |
499 | |
500 void Service::SendEvent(intptr_t eventType, | |
501 const Object& eventMessage) { | |
502 ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())); | 546 ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())); |
503 if (!ServiceIsolate::IsRunning()) { | 547 if (!ServiceIsolate::IsRunning()) { |
504 return; | 548 return; |
505 } | 549 } |
506 Isolate* isolate = Isolate::Current(); | 550 Isolate* isolate = Isolate::Current(); |
507 ASSERT(isolate != NULL); | 551 ASSERT(isolate != NULL); |
508 HANDLESCOPE(isolate); | 552 HANDLESCOPE(isolate); |
509 | 553 |
| 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 |
510 // Push the event to port_. | 560 // Push the event to port_. |
511 uint8_t* data = NULL; | 561 uint8_t* data = NULL; |
512 MessageWriter writer(&data, &allocator, false); | 562 MessageWriter writer(&data, &allocator, false); |
513 writer.WriteMessage(eventMessage); | 563 writer.WriteMessage(list); |
514 intptr_t len = writer.BytesWritten(); | 564 intptr_t len = writer.BytesWritten(); |
515 if (FLAG_trace_service) { | 565 if (FLAG_trace_service) { |
516 OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n", | 566 OS::Print( |
517 eventType, len); | 567 "vm-service: Pushing event of type %s to stream %s, len %" Pd "\n", |
| 568 event_type, stream_id, len); |
518 } | 569 } |
519 // TODO(turnidge): For now we ignore failure to send an event. Revisit? | 570 // TODO(turnidge): For now we ignore failure to send an event. Revisit? |
520 PortMap::PostMessage( | 571 PortMap::PostMessage( |
521 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); | 572 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); |
522 } | 573 } |
523 | 574 |
524 | 575 |
525 void Service::SendEvent(const String& meta, | 576 void Service::SendEventWithData(const char* stream_id, |
526 const uint8_t* data, | 577 const char* event_type, |
527 intptr_t size) { | 578 const String& meta, |
| 579 const uint8_t* data, |
| 580 intptr_t size) { |
528 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] | 581 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] |
529 const intptr_t meta_bytes = Utf8::Length(meta); | 582 const intptr_t meta_bytes = Utf8::Length(meta); |
530 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; | 583 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; |
531 const TypedData& message = TypedData::Handle( | 584 const TypedData& message = TypedData::Handle( |
532 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); | 585 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); |
533 intptr_t offset = 0; | 586 intptr_t offset = 0; |
534 // TODO(koda): Rename these methods SetHostUint64, etc. | 587 // TODO(koda): Rename these methods SetHostUint64, etc. |
535 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes)); | 588 message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes)); |
536 offset += sizeof(uint64_t); | 589 offset += sizeof(uint64_t); |
537 { | 590 { |
538 NoSafepointScope no_safepoint; | 591 NoSafepointScope no_safepoint; |
539 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes); | 592 meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes); |
540 offset += meta_bytes; | 593 offset += meta_bytes; |
541 } | 594 } |
542 // TODO(koda): It would be nice to avoid this copy (requires changes to | 595 // TODO(koda): It would be nice to avoid this copy (requires changes to |
543 // MessageWriter code). | 596 // MessageWriter code). |
544 { | 597 { |
545 NoSafepointScope no_safepoint; | 598 NoSafepointScope no_safepoint; |
546 memmove(message.DataAddr(offset), data, size); | 599 memmove(message.DataAddr(offset), data, size); |
547 offset += size; | 600 offset += size; |
548 } | 601 } |
549 ASSERT(offset == total_bytes); | 602 ASSERT(offset == total_bytes); |
550 // TODO(turnidge): Pass the real eventType here. | 603 SendEvent(stream_id, event_type, message); |
551 SendEvent(0, message); | |
552 } | 604 } |
553 | 605 |
554 | 606 |
555 void Service::HandleEvent(ServiceEvent* event) { | 607 void Service::HandleEvent(ServiceEvent* event) { |
556 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { | 608 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { |
557 return; | 609 return; |
558 } | 610 } |
559 JSONStream js; | 611 JSONStream js; |
| 612 const char* stream_id = event->stream_id(); |
| 613 ASSERT(stream_id != NULL); |
560 { | 614 { |
561 JSONObject jsobj(&js); | 615 JSONObject jsobj(&js); |
562 jsobj.AddProperty("event", event); | 616 jsobj.AddProperty("event", event); |
| 617 jsobj.AddProperty("streamId", stream_id); |
563 } | 618 } |
564 const String& message = String::Handle(String::New(js.ToCString())); | 619 const String& message = String::Handle(String::New(js.ToCString())); |
565 SendEvent(event->type(), message); | 620 SendEvent(stream_id, ServiceEvent::EventTypeToCString(event->type()), |
| 621 message); |
566 } | 622 } |
567 | 623 |
568 | 624 |
569 class EmbedderServiceHandler { | 625 class EmbedderServiceHandler { |
570 public: | 626 public: |
571 explicit EmbedderServiceHandler(const char* name) : name_(NULL), | 627 explicit EmbedderServiceHandler(const char* name) : name_(NULL), |
572 callback_(NULL), | 628 callback_(NULL), |
573 user_data_(NULL), | 629 user_data_(NULL), |
574 next_(NULL) { | 630 next_(NULL) { |
575 ASSERT(name != NULL); | 631 ASSERT(name != NULL); |
(...skipping 28 matching lines...) Expand all Loading... |
604 EmbedderServiceHandler* next_; | 660 EmbedderServiceHandler* next_; |
605 }; | 661 }; |
606 | 662 |
607 | 663 |
608 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, | 664 void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, |
609 JSONStream* js) { | 665 JSONStream* js) { |
610 ASSERT(handler != NULL); | 666 ASSERT(handler != NULL); |
611 Dart_ServiceRequestCallback callback = handler->callback(); | 667 Dart_ServiceRequestCallback callback = handler->callback(); |
612 ASSERT(callback != NULL); | 668 ASSERT(callback != NULL); |
613 const char* r = NULL; | 669 const char* r = NULL; |
614 const char* name = js->method(); | 670 const char* method = js->method(); |
615 const char** keys = js->param_keys(); | 671 const char** keys = js->param_keys(); |
616 const char** values = js->param_values(); | 672 const char** values = js->param_values(); |
617 r = callback(name, keys, values, js->num_params(), handler->user_data()); | 673 r = callback(method, keys, values, js->num_params(), handler->user_data()); |
618 ASSERT(r != NULL); | 674 ASSERT(r != NULL); |
619 // TODO(johnmccutchan): Allow for NULL returns? | 675 // TODO(johnmccutchan): Allow for NULL returns? |
620 TextBuffer* buffer = js->buffer(); | 676 TextBuffer* buffer = js->buffer(); |
621 buffer->AddString(r); | 677 buffer->AddString(r); |
622 free(const_cast<char*>(r)); | 678 free(const_cast<char*>(r)); |
623 } | 679 } |
624 | 680 |
625 | 681 |
626 void Service::RegisterIsolateEmbedderCallback( | 682 void Service::RegisterIsolateEmbedderCallback( |
627 const char* name, | 683 const char* name, |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 JSONObject jsobj(&js); | 820 JSONObject jsobj(&js); |
765 { | 821 { |
766 JSONObject event(&jsobj, "event"); | 822 JSONObject event(&jsobj, "event"); |
767 event.AddProperty("type", "ServiceEvent"); | 823 event.AddProperty("type", "ServiceEvent"); |
768 event.AddProperty("eventType", "_Echo"); | 824 event.AddProperty("eventType", "_Echo"); |
769 event.AddProperty("isolate", isolate); | 825 event.AddProperty("isolate", isolate); |
770 if (text != NULL) { | 826 if (text != NULL) { |
771 event.AddProperty("text", text); | 827 event.AddProperty("text", text); |
772 } | 828 } |
773 } | 829 } |
| 830 jsobj.AddProperty("streamId", "_Echo"); |
774 } | 831 } |
775 const String& message = String::Handle(String::New(js.ToCString())); | 832 const String& message = String::Handle(String::New(js.ToCString())); |
776 uint8_t data[] = {0, 128, 255}; | 833 uint8_t data[] = {0, 128, 255}; |
777 SendEvent(message, data, sizeof(data)); | 834 SendEventWithData("_Echo", "_Echo", message, data, sizeof(data)); |
778 } | 835 } |
779 | 836 |
780 | 837 |
781 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { | 838 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { |
782 Service::SendEchoEvent(isolate, js->LookupParam("text")); | 839 Service::SendEchoEvent(isolate, js->LookupParam("text")); |
783 JSONObject jsobj(js); | 840 JSONObject jsobj(js); |
784 return HandleCommonEcho(&jsobj, js); | 841 return HandleCommonEcho(&jsobj, js); |
785 } | 842 } |
786 | 843 |
787 | 844 |
(...skipping 1271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2059 NULL, | 2116 NULL, |
2060 }; | 2117 }; |
2061 | 2118 |
2062 | 2119 |
2063 static bool Resume(Isolate* isolate, JSONStream* js) { | 2120 static bool Resume(Isolate* isolate, JSONStream* js) { |
2064 const char* step_param = js->LookupParam("step"); | 2121 const char* step_param = js->LookupParam("step"); |
2065 if (isolate->message_handler()->paused_on_start()) { | 2122 if (isolate->message_handler()->paused_on_start()) { |
2066 isolate->message_handler()->set_pause_on_start(false); | 2123 isolate->message_handler()->set_pause_on_start(false); |
2067 JSONObject jsobj(js); | 2124 JSONObject jsobj(js); |
2068 jsobj.AddProperty("type", "Success"); | 2125 jsobj.AddProperty("type", "Success"); |
2069 { | 2126 if (Service::NeedsDebugEvents()) { |
2070 ServiceEvent event(isolate, ServiceEvent::kResume); | 2127 ServiceEvent event(isolate, ServiceEvent::kResume); |
2071 Service::HandleEvent(&event); | 2128 Service::HandleEvent(&event); |
2072 } | 2129 } |
2073 return true; | 2130 return true; |
2074 } | 2131 } |
2075 if (isolate->message_handler()->paused_on_exit()) { | 2132 if (isolate->message_handler()->paused_on_exit()) { |
2076 isolate->message_handler()->set_pause_on_exit(false); | 2133 isolate->message_handler()->set_pause_on_exit(false); |
2077 JSONObject jsobj(js); | 2134 JSONObject jsobj(js); |
2078 jsobj.AddProperty("type", "Success"); | 2135 jsobj.AddProperty("type", "Success"); |
2079 // We don't send a resume event because we will be exiting. | 2136 // We don't send a resume event because we will be exiting. |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2255 graph.Serialize(&stream); | 2312 graph.Serialize(&stream); |
2256 JSONStream js; | 2313 JSONStream js; |
2257 { | 2314 { |
2258 JSONObject jsobj(&js); | 2315 JSONObject jsobj(&js); |
2259 { | 2316 { |
2260 JSONObject event(&jsobj, "event"); | 2317 JSONObject event(&jsobj, "event"); |
2261 event.AddProperty("type", "ServiceEvent"); | 2318 event.AddProperty("type", "ServiceEvent"); |
2262 event.AddProperty("eventType", "_Graph"); | 2319 event.AddProperty("eventType", "_Graph"); |
2263 event.AddProperty("isolate", isolate); | 2320 event.AddProperty("isolate", isolate); |
2264 } | 2321 } |
| 2322 jsobj.AddProperty("streamId", "_Graph"); |
2265 } | 2323 } |
2266 const String& message = String::Handle(String::New(js.ToCString())); | 2324 const String& message = String::Handle(String::New(js.ToCString())); |
2267 SendEvent(message, buffer, stream.bytes_written()); | 2325 SendEventWithData("_Graph", "_Graph", message, |
| 2326 buffer, stream.bytes_written()); |
2268 } | 2327 } |
2269 | 2328 |
2270 | 2329 |
2271 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { | 2330 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { |
| 2331 if (!Service::NeedsDebugEvents()) { |
| 2332 return; |
| 2333 } |
2272 ServiceEvent event(isolate, ServiceEvent::kInspect); | 2334 ServiceEvent event(isolate, ServiceEvent::kInspect); |
2273 event.set_inspectee(&inspectee); | 2335 event.set_inspectee(&inspectee); |
2274 Service::HandleEvent(&event); | 2336 Service::HandleEvent(&event); |
2275 } | 2337 } |
2276 | 2338 |
2277 | 2339 |
2278 class ContainsAddressVisitor : public FindObjectVisitor { | 2340 class ContainsAddressVisitor : public FindObjectVisitor { |
2279 public: | 2341 public: |
2280 ContainsAddressVisitor(Isolate* isolate, uword addr) | 2342 ContainsAddressVisitor(Isolate* isolate, uword addr) |
2281 : FindObjectVisitor(isolate), addr_(addr) { } | 2343 : FindObjectVisitor(isolate), addr_(addr) { } |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2543 | 2605 |
2544 static const MethodParameter* set_name_params[] = { | 2606 static const MethodParameter* set_name_params[] = { |
2545 ISOLATE_PARAMETER, | 2607 ISOLATE_PARAMETER, |
2546 new MethodParameter("name", true), | 2608 new MethodParameter("name", true), |
2547 NULL, | 2609 NULL, |
2548 }; | 2610 }; |
2549 | 2611 |
2550 | 2612 |
2551 static bool SetName(Isolate* isolate, JSONStream* js) { | 2613 static bool SetName(Isolate* isolate, JSONStream* js) { |
2552 isolate->set_debugger_name(js->LookupParam("name")); | 2614 isolate->set_debugger_name(js->LookupParam("name")); |
2553 { | 2615 if (Service::NeedsIsolateEvents()) { |
2554 ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate); | 2616 ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate); |
2555 Service::HandleEvent(&event); | 2617 Service::HandleEvent(&event); |
2556 } | 2618 } |
2557 JSONObject jsobj(js); | 2619 JSONObject jsobj(js); |
2558 jsobj.AddProperty("type", "Success"); | 2620 jsobj.AddProperty("type", "Success"); |
2559 return true; | 2621 return true; |
2560 } | 2622 } |
2561 | 2623 |
2562 | 2624 |
2563 static ServiceMethodDescriptor service_methods_[] = { | 2625 static ServiceMethodDescriptor service_methods_[] = { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2646 ServiceMethodDescriptor& method = service_methods_[i]; | 2708 ServiceMethodDescriptor& method = service_methods_[i]; |
2647 if (strcmp(method_name, method.name) == 0) { | 2709 if (strcmp(method_name, method.name) == 0) { |
2648 return &method; | 2710 return &method; |
2649 } | 2711 } |
2650 } | 2712 } |
2651 return NULL; | 2713 return NULL; |
2652 } | 2714 } |
2653 | 2715 |
2654 | 2716 |
2655 } // namespace dart | 2717 } // namespace dart |
OLD | NEW |