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 "include/dart_native_api.h" | |
8 #include "platform/globals.h" | 9 #include "platform/globals.h" |
9 | 10 |
10 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
11 #include "vm/coverage.h" | 12 #include "vm/coverage.h" |
12 #include "vm/cpu.h" | 13 #include "vm/cpu.h" |
13 #include "vm/dart_api_impl.h" | 14 #include "vm/dart_api_impl.h" |
14 #include "vm/dart_entry.h" | 15 #include "vm/dart_entry.h" |
15 #include "vm/debugger.h" | 16 #include "vm/debugger.h" |
16 #include "vm/isolate.h" | 17 #include "vm/isolate.h" |
17 #include "vm/lockers.h" | 18 #include "vm/lockers.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 return zone->PrintToString("objects/%" Pd "", id); | 68 return zone->PrintToString("objects/%" Pd "", id); |
68 } | 69 } |
69 | 70 |
70 | 71 |
71 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs. | 72 // TODO(johnmccutchan): Unify embedder service handler lists and their APIs. |
72 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; | 73 EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; |
73 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; | 74 EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; |
74 struct ServiceMethodDescriptor; | 75 struct ServiceMethodDescriptor; |
75 ServiceMethodDescriptor* FindMethod(const char* method_name); | 76 ServiceMethodDescriptor* FindMethod(const char* method_name); |
76 | 77 |
77 // TODO(turnidge): Build a general framework later. For now, we have | 78 |
78 // a small set of well-known streams. | 79 // These are the set of streams known to the core VM. |
80 const char* const Service::kIsolateStreamId = "Isolate"; | |
81 const char* const Service::kDebugStreamId = "Debug"; | |
82 const char* const Service::kGCStreamId = "GC"; | |
83 const char* const Service::kEchoStreamId = "_Echo"; | |
84 const char* const Service::kGraphStreamId = "_Graph"; | |
Cutch
2015/07/13 14:10:29
Would be nice if we had an array of streams (with
turnidge
2015/07/13 22:50:36
Done.
| |
85 | |
86 | |
79 bool Service::needs_isolate_events_ = false; | 87 bool Service::needs_isolate_events_ = false; |
80 bool Service::needs_debug_events_ = false; | 88 bool Service::needs_debug_events_ = false; |
81 bool Service::needs_gc_events_ = false; | 89 bool Service::needs_gc_events_ = false; |
82 bool Service::needs_echo_events_ = false; | 90 bool Service::needs_echo_events_ = false; |
83 bool Service::needs_graph_events_ = false; | 91 bool Service::needs_graph_events_ = false; |
84 | 92 |
85 void Service::ListenStream(const char* stream_id) { | 93 // Support for streams defined in embedders. |
94 Dart_ServiceStreamListenCallback Service::stream_listen_callback_ = NULL; | |
95 Dart_ServiceStreamCancelCallback Service::stream_cancel_callback_ = NULL; | |
96 | |
97 | |
98 bool Service::ListenStream(const char* stream_id) { | |
86 if (FLAG_trace_service) { | 99 if (FLAG_trace_service) { |
87 OS::Print("vm-service: starting stream '%s'\n", | 100 OS::Print("vm-service: starting stream '%s'\n", |
88 stream_id); | 101 stream_id); |
89 } | 102 } |
90 if (strcmp(stream_id, "Isolate") == 0) { | 103 if (strcmp(stream_id, kIsolateStreamId) == 0) { |
91 needs_isolate_events_ = true; | 104 needs_isolate_events_ = true; |
92 } else if (strcmp(stream_id, "Debug") == 0) { | 105 return true; |
106 } else if (strcmp(stream_id, kDebugStreamId) == 0) { | |
93 needs_debug_events_ = true; | 107 needs_debug_events_ = true; |
94 } else if (strcmp(stream_id, "GC") == 0) { | 108 return true; |
109 } else if (strcmp(stream_id, kGCStreamId) == 0) { | |
95 needs_gc_events_ = true; | 110 needs_gc_events_ = true; |
96 } else if (strcmp(stream_id, "_Echo") == 0) { | 111 return true; |
112 } else if (strcmp(stream_id, kEchoStreamId) == 0) { | |
97 needs_echo_events_ = true; | 113 needs_echo_events_ = true; |
98 } else if (strcmp(stream_id, "_Graph") == 0) { | 114 return true; |
115 } else if (strcmp(stream_id, kGraphStreamId) == 0) { | |
99 needs_graph_events_ = true; | 116 needs_graph_events_ = true; |
100 } else { | 117 return true; |
101 UNREACHABLE(); | 118 } else if (stream_listen_callback_) { |
119 return (*stream_listen_callback_)(stream_id); | |
102 } | 120 } |
121 return false; | |
103 } | 122 } |
104 | 123 |
105 void Service::CancelStream(const char* stream_id) { | 124 void Service::CancelStream(const char* stream_id) { |
106 if (FLAG_trace_service) { | 125 if (FLAG_trace_service) { |
107 OS::Print("vm-service: stopping stream '%s'\n", | 126 OS::Print("vm-service: stopping stream '%s'\n", |
108 stream_id); | 127 stream_id); |
109 } | 128 } |
110 if (strcmp(stream_id, "Isolate") == 0) { | 129 if (strcmp(stream_id, kIsolateStreamId) == 0) { |
111 needs_isolate_events_ = false; | 130 needs_isolate_events_ = false; |
112 } else if (strcmp(stream_id, "Debug") == 0) { | 131 } else if (strcmp(stream_id, kDebugStreamId) == 0) { |
113 needs_debug_events_ = false; | 132 needs_debug_events_ = false; |
114 } else if (strcmp(stream_id, "GC") == 0) { | 133 } else if (strcmp(stream_id, kGCStreamId) == 0) { |
115 needs_gc_events_ = false; | 134 needs_gc_events_ = false; |
116 } else if (strcmp(stream_id, "_Echo") == 0) { | 135 } else if (strcmp(stream_id, kEchoStreamId) == 0) { |
117 needs_echo_events_ = false; | 136 needs_echo_events_ = false; |
118 } else if (strcmp(stream_id, "_Graph") == 0) { | 137 } else if (strcmp(stream_id, kGraphStreamId) == 0) { |
119 needs_graph_events_ = false; | 138 needs_graph_events_ = false; |
120 } else { | 139 } else if (stream_cancel_callback_) { |
121 UNREACHABLE(); | 140 return (*stream_cancel_callback_)(stream_id); |
122 } | 141 } |
123 } | 142 } |
124 | 143 |
125 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { | 144 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); | 145 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
127 return reinterpret_cast<uint8_t*>(new_ptr); | 146 return reinterpret_cast<uint8_t*>(new_ptr); |
128 } | 147 } |
129 | 148 |
130 static void PrintMissingParamError(JSONStream* js, | 149 static void PrintMissingParamError(JSONStream* js, |
131 const char* param) { | 150 const char* param) { |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
571 OS::Print( | 590 OS::Print( |
572 "vm-service: Pushing event of type %s to stream %s, len %" Pd "\n", | 591 "vm-service: Pushing event of type %s to stream %s, len %" Pd "\n", |
573 event_type, stream_id, len); | 592 event_type, stream_id, len); |
574 } | 593 } |
575 // TODO(turnidge): For now we ignore failure to send an event. Revisit? | 594 // TODO(turnidge): For now we ignore failure to send an event. Revisit? |
576 PortMap::PostMessage( | 595 PortMap::PostMessage( |
577 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); | 596 new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority)); |
578 } | 597 } |
579 | 598 |
580 | 599 |
600 // TODO(turnidge): Rewrite this method to use Post_CObject instead. | |
581 void Service::SendEventWithData(const char* stream_id, | 601 void Service::SendEventWithData(const char* stream_id, |
582 const char* event_type, | 602 const char* event_type, |
583 const String& meta, | 603 const String& meta, |
584 const uint8_t* data, | 604 const uint8_t* data, |
585 intptr_t size) { | 605 intptr_t size) { |
586 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] | 606 // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data] |
587 const intptr_t meta_bytes = Utf8::Length(meta); | 607 const intptr_t meta_bytes = Utf8::Length(meta); |
588 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; | 608 const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size; |
589 const TypedData& message = TypedData::Handle( | 609 const TypedData& message = TypedData::Handle( |
590 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); | 610 TypedData::New(kTypedDataUint8ArrayCid, total_bytes)); |
(...skipping 15 matching lines...) Expand all Loading... | |
606 } | 626 } |
607 ASSERT(offset == total_bytes); | 627 ASSERT(offset == total_bytes); |
608 SendEvent(stream_id, event_type, message); | 628 SendEvent(stream_id, event_type, message); |
609 } | 629 } |
610 | 630 |
611 | 631 |
612 void Service::HandleEvent(ServiceEvent* event) { | 632 void Service::HandleEvent(ServiceEvent* event) { |
613 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { | 633 if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { |
614 return; | 634 return; |
615 } | 635 } |
636 if (!ServiceIsolate::IsRunning()) { | |
637 return; | |
638 } | |
616 JSONStream js; | 639 JSONStream js; |
617 const char* stream_id = event->stream_id(); | 640 const char* stream_id = event->stream_id(); |
618 ASSERT(stream_id != NULL); | 641 ASSERT(stream_id != NULL); |
619 { | 642 { |
620 JSONObject jsobj(&js); | 643 JSONObject jsobj(&js); |
621 jsobj.AddProperty("event", event); | 644 jsobj.AddProperty("event", event); |
622 jsobj.AddProperty("streamId", stream_id); | 645 jsobj.AddProperty("streamId", stream_id); |
623 } | 646 } |
624 const String& message = String::Handle(String::New(js.ToCString())); | 647 |
625 SendEvent(stream_id, ServiceEvent::EventTypeToCString(event->type()), | 648 // Message is of the format [<stream id>, <json string>]. |
626 message); | 649 // |
650 // Build the event message in the C heap to avoid dart heap | |
651 // allocation. This method can be called while we have acquired a | |
652 // direct pointer to typed data, so we can't allocate here. | |
653 Dart_CObject list_cobj; | |
654 Dart_CObject* list_values[2]; | |
655 list_cobj.type = Dart_CObject_kArray; | |
656 list_cobj.value.as_array.length = 2; | |
657 list_cobj.value.as_array.values = list_values; | |
658 | |
659 Dart_CObject stream_id_cobj; | |
660 stream_id_cobj.type = Dart_CObject_kString; | |
661 stream_id_cobj.value.as_string = const_cast<char*>(stream_id); | |
662 list_values[0] = &stream_id_cobj; | |
663 | |
664 Dart_CObject json_cobj; | |
665 json_cobj.type = Dart_CObject_kString; | |
666 json_cobj.value.as_string = const_cast<char*>(js.ToCString()); | |
667 list_values[1] = &json_cobj; | |
668 | |
669 if (FLAG_trace_service) { | |
670 OS::Print( | |
671 "vm-service: Pushing event of type %s to stream %s\n", | |
672 event->KindAsCString(), stream_id); | |
673 } | |
674 | |
675 Dart_PostCObject(ServiceIsolate::Port(), &list_cobj); | |
627 } | 676 } |
628 | 677 |
629 | 678 |
630 class EmbedderServiceHandler { | 679 class EmbedderServiceHandler { |
631 public: | 680 public: |
632 explicit EmbedderServiceHandler(const char* name) : name_(NULL), | 681 explicit EmbedderServiceHandler(const char* name) : name_(NULL), |
633 callback_(NULL), | 682 callback_(NULL), |
634 user_data_(NULL), | 683 user_data_(NULL), |
635 next_(NULL) { | 684 next_(NULL) { |
636 ASSERT(name != NULL); | 685 ASSERT(name != NULL); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
740 handler = new EmbedderServiceHandler(name); | 789 handler = new EmbedderServiceHandler(name); |
741 handler->set_callback(callback); | 790 handler->set_callback(callback); |
742 handler->set_user_data(user_data); | 791 handler->set_user_data(user_data); |
743 | 792 |
744 // Insert into root_service_handler_head_ list. | 793 // Insert into root_service_handler_head_ list. |
745 handler->set_next(root_service_handler_head_); | 794 handler->set_next(root_service_handler_head_); |
746 root_service_handler_head_ = handler; | 795 root_service_handler_head_ = handler; |
747 } | 796 } |
748 | 797 |
749 | 798 |
799 void Service::SetEmbedderStreamCallbacks( | |
800 Dart_ServiceStreamListenCallback listen_callback, | |
801 Dart_ServiceStreamCancelCallback cancel_callback) { | |
802 stream_listen_callback_ = listen_callback; | |
803 stream_cancel_callback_ = cancel_callback; | |
804 } | |
805 | |
806 | |
750 EmbedderServiceHandler* Service::FindRootEmbedderHandler( | 807 EmbedderServiceHandler* Service::FindRootEmbedderHandler( |
751 const char* name) { | 808 const char* name) { |
752 EmbedderServiceHandler* current = root_service_handler_head_; | 809 EmbedderServiceHandler* current = root_service_handler_head_; |
753 while (current != NULL) { | 810 while (current != NULL) { |
754 if (strcmp(name, current->name()) == 0) { | 811 if (strcmp(name, current->name()) == 0) { |
755 return current; | 812 return current; |
756 } | 813 } |
757 current = current->next(); | 814 current = current->next(); |
758 } | 815 } |
759 return NULL; | 816 return NULL; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
823 JSONObject jsobj(&js); | 880 JSONObject jsobj(&js); |
824 { | 881 { |
825 JSONObject event(&jsobj, "event"); | 882 JSONObject event(&jsobj, "event"); |
826 event.AddProperty("type", "Event"); | 883 event.AddProperty("type", "Event"); |
827 event.AddProperty("kind", "_Echo"); | 884 event.AddProperty("kind", "_Echo"); |
828 event.AddProperty("isolate", isolate); | 885 event.AddProperty("isolate", isolate); |
829 if (text != NULL) { | 886 if (text != NULL) { |
830 event.AddProperty("text", text); | 887 event.AddProperty("text", text); |
831 } | 888 } |
832 } | 889 } |
833 jsobj.AddProperty("streamId", "_Echo"); | 890 jsobj.AddProperty("streamId", kEchoStreamId); |
834 } | 891 } |
835 const String& message = String::Handle(String::New(js.ToCString())); | 892 const String& message = String::Handle(String::New(js.ToCString())); |
836 uint8_t data[] = {0, 128, 255}; | 893 uint8_t data[] = {0, 128, 255}; |
837 SendEventWithData("_Echo", "_Echo", message, data, sizeof(data)); | 894 SendEventWithData(kEchoStreamId, "_Echo", message, data, sizeof(data)); |
838 } | 895 } |
839 | 896 |
840 | 897 |
841 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { | 898 static bool TriggerEchoEvent(Isolate* isolate, JSONStream* js) { |
842 if (Service::NeedsEchoEvents()) { | 899 if (Service::NeedsEchoEvents()) { |
843 Service::SendEchoEvent(isolate, js->LookupParam("text")); | 900 Service::SendEchoEvent(isolate, js->LookupParam("text")); |
844 } | 901 } |
845 JSONObject jsobj(js); | 902 JSONObject jsobj(js); |
846 return HandleCommonEcho(&jsobj, js); | 903 return HandleCommonEcho(&jsobj, js); |
847 } | 904 } |
(...skipping 1494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2342 { | 2399 { |
2343 JSONObject event(&jsobj, "event"); | 2400 JSONObject event(&jsobj, "event"); |
2344 event.AddProperty("type", "Event"); | 2401 event.AddProperty("type", "Event"); |
2345 event.AddProperty("kind", "_Graph"); | 2402 event.AddProperty("kind", "_Graph"); |
2346 event.AddProperty("isolate", isolate); | 2403 event.AddProperty("isolate", isolate); |
2347 | 2404 |
2348 event.AddProperty("chunkIndex", i); | 2405 event.AddProperty("chunkIndex", i); |
2349 event.AddProperty("chunkCount", num_chunks); | 2406 event.AddProperty("chunkCount", num_chunks); |
2350 event.AddProperty("nodeCount", node_count); | 2407 event.AddProperty("nodeCount", node_count); |
2351 } | 2408 } |
2352 jsobj.AddProperty("streamId", "_Graph"); | 2409 jsobj.AddProperty("streamId", kGraphStreamId); |
2353 } | 2410 } |
2354 | 2411 |
2355 const String& message = String::Handle(String::New(js.ToCString())); | 2412 const String& message = String::Handle(String::New(js.ToCString())); |
2356 | 2413 |
2357 uint8_t* chunk_start = buffer + (i * kChunkSize); | 2414 uint8_t* chunk_start = buffer + (i * kChunkSize); |
2358 intptr_t chunk_size = (i + 1 == num_chunks) | 2415 intptr_t chunk_size = (i + 1 == num_chunks) |
2359 ? stream.bytes_written() - (i * kChunkSize) | 2416 ? stream.bytes_written() - (i * kChunkSize) |
2360 : kChunkSize; | 2417 : kChunkSize; |
2361 | 2418 |
2362 SendEventWithData("_Graph", "_Graph", message, chunk_start, chunk_size); | 2419 SendEventWithData(kGraphStreamId, "_Graph", message, |
2420 chunk_start, chunk_size); | |
2363 } | 2421 } |
2364 } | 2422 } |
2365 | 2423 |
2366 | 2424 |
2367 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { | 2425 void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { |
2368 if (!Service::NeedsDebugEvents()) { | 2426 if (!Service::NeedsDebugEvents()) { |
2369 return; | 2427 return; |
2370 } | 2428 } |
2371 ServiceEvent event(isolate, ServiceEvent::kInspect); | 2429 ServiceEvent event(isolate, ServiceEvent::kInspect); |
2372 event.set_inspectee(&inspectee); | 2430 event.set_inspectee(&inspectee); |
2373 Service::HandleEvent(&event); | 2431 Service::HandleEvent(&event); |
2374 } | 2432 } |
2375 | 2433 |
2376 | 2434 |
2435 void Service::SendEmbedderEvent(Isolate* isolate, | |
2436 const char* stream_id, | |
2437 const char* event_kind, | |
2438 const uint8_t* bytes, | |
2439 intptr_t bytes_len) { | |
2440 if (!Service::NeedsDebugEvents()) { | |
2441 return; | |
2442 } | |
2443 ServiceEvent event(isolate, ServiceEvent::kEmbedder); | |
2444 event.set_embedder_kind(event_kind); | |
2445 event.set_embedder_stream_id(stream_id); | |
2446 event.set_bytes(bytes, bytes_len); | |
2447 Service::HandleEvent(&event); | |
2448 } | |
2449 | |
2450 | |
2377 class ContainsAddressVisitor : public FindObjectVisitor { | 2451 class ContainsAddressVisitor : public FindObjectVisitor { |
2378 public: | 2452 public: |
2379 ContainsAddressVisitor(Isolate* isolate, uword addr) | 2453 ContainsAddressVisitor(Isolate* isolate, uword addr) |
2380 : FindObjectVisitor(isolate), addr_(addr) { } | 2454 : FindObjectVisitor(isolate), addr_(addr) { } |
2381 virtual ~ContainsAddressVisitor() { } | 2455 virtual ~ContainsAddressVisitor() { } |
2382 | 2456 |
2383 virtual uword filter_addr() const { return addr_; } | 2457 virtual uword filter_addr() const { return addr_; } |
2384 | 2458 |
2385 virtual bool FindObject(RawObject* obj) const { | 2459 virtual bool FindObject(RawObject* obj) const { |
2386 // Free list elements are not real objects, so skip them. | 2460 // Free list elements are not real objects, so skip them. |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2847 ServiceMethodDescriptor& method = service_methods_[i]; | 2921 ServiceMethodDescriptor& method = service_methods_[i]; |
2848 if (strcmp(method_name, method.name) == 0) { | 2922 if (strcmp(method_name, method.name) == 0) { |
2849 return &method; | 2923 return &method; |
2850 } | 2924 } |
2851 } | 2925 } |
2852 return NULL; | 2926 return NULL; |
2853 } | 2927 } |
2854 | 2928 |
2855 | 2929 |
2856 } // namespace dart | 2930 } // namespace dart |
OLD | NEW |