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 |