Chromium Code Reviews| 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 |