Chromium Code Reviews| Index: runtime/vm/service.cc |
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc |
| index 4cbc5ddba46f142d49aa4c71cb4551b87d1c3ebb..0590c1589f84d62858bda9f3b93d029612ebad69 100644 |
| --- a/runtime/vm/service.cc |
| +++ b/runtime/vm/service.cc |
| @@ -5,6 +5,7 @@ |
| #include "vm/service.h" |
| #include "include/dart_api.h" |
| +#include "include/dart_native_api.h" |
| #include "platform/globals.h" |
| #include "vm/compiler.h" |
| @@ -74,32 +75,50 @@ EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; |
| struct ServiceMethodDescriptor; |
| ServiceMethodDescriptor* FindMethod(const char* method_name); |
| -// TODO(turnidge): Build a general framework later. For now, we have |
| -// a small set of well-known streams. |
| + |
| +// These are the set of streams known to the core VM. |
| +const char* const Service::kIsolateStreamId = "Isolate"; |
| +const char* const Service::kDebugStreamId = "Debug"; |
| +const char* const Service::kGCStreamId = "GC"; |
| +const char* const Service::kEchoStreamId = "_Echo"; |
| +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.
|
| + |
| + |
| bool Service::needs_isolate_events_ = false; |
| bool Service::needs_debug_events_ = false; |
| bool Service::needs_gc_events_ = false; |
| bool Service::needs_echo_events_ = false; |
| bool Service::needs_graph_events_ = false; |
| -void Service::ListenStream(const char* stream_id) { |
| +// Support for streams defined in embedders. |
| +Dart_ServiceStreamListenCallback Service::stream_listen_callback_ = NULL; |
| +Dart_ServiceStreamCancelCallback Service::stream_cancel_callback_ = NULL; |
| + |
| + |
| +bool Service::ListenStream(const char* stream_id) { |
| if (FLAG_trace_service) { |
| OS::Print("vm-service: starting stream '%s'\n", |
| stream_id); |
| } |
| - if (strcmp(stream_id, "Isolate") == 0) { |
| + if (strcmp(stream_id, kIsolateStreamId) == 0) { |
| needs_isolate_events_ = true; |
| - } else if (strcmp(stream_id, "Debug") == 0) { |
| + return true; |
| + } else if (strcmp(stream_id, kDebugStreamId) == 0) { |
| needs_debug_events_ = true; |
| - } else if (strcmp(stream_id, "GC") == 0) { |
| + return true; |
| + } else if (strcmp(stream_id, kGCStreamId) == 0) { |
| needs_gc_events_ = true; |
| - } else if (strcmp(stream_id, "_Echo") == 0) { |
| + return true; |
| + } else if (strcmp(stream_id, kEchoStreamId) == 0) { |
| needs_echo_events_ = true; |
| - } else if (strcmp(stream_id, "_Graph") == 0) { |
| + return true; |
| + } else if (strcmp(stream_id, kGraphStreamId) == 0) { |
| needs_graph_events_ = true; |
| - } else { |
| - UNREACHABLE(); |
| + return true; |
| + } else if (stream_listen_callback_) { |
| + return (*stream_listen_callback_)(stream_id); |
| } |
| + return false; |
| } |
| void Service::CancelStream(const char* stream_id) { |
| @@ -107,18 +126,18 @@ void Service::CancelStream(const char* stream_id) { |
| OS::Print("vm-service: stopping stream '%s'\n", |
| stream_id); |
| } |
| - if (strcmp(stream_id, "Isolate") == 0) { |
| + if (strcmp(stream_id, kIsolateStreamId) == 0) { |
| needs_isolate_events_ = false; |
| - } else if (strcmp(stream_id, "Debug") == 0) { |
| + } else if (strcmp(stream_id, kDebugStreamId) == 0) { |
| needs_debug_events_ = false; |
| - } else if (strcmp(stream_id, "GC") == 0) { |
| + } else if (strcmp(stream_id, kGCStreamId) == 0) { |
| needs_gc_events_ = false; |
| - } else if (strcmp(stream_id, "_Echo") == 0) { |
| + } else if (strcmp(stream_id, kEchoStreamId) == 0) { |
| needs_echo_events_ = false; |
| - } else if (strcmp(stream_id, "_Graph") == 0) { |
| + } else if (strcmp(stream_id, kGraphStreamId) == 0) { |
| needs_graph_events_ = false; |
| - } else { |
| - UNREACHABLE(); |
| + } else if (stream_cancel_callback_) { |
| + return (*stream_cancel_callback_)(stream_id); |
| } |
| } |
| @@ -578,6 +597,7 @@ void Service::SendEvent(const char* stream_id, |
| } |
| +// TODO(turnidge): Rewrite this method to use Post_CObject instead. |
| void Service::SendEventWithData(const char* stream_id, |
| const char* event_type, |
| const String& meta, |
| @@ -613,6 +633,9 @@ void Service::HandleEvent(ServiceEvent* event) { |
| if (ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) { |
| return; |
| } |
| + if (!ServiceIsolate::IsRunning()) { |
| + return; |
| + } |
| JSONStream js; |
| const char* stream_id = event->stream_id(); |
| ASSERT(stream_id != NULL); |
| @@ -621,9 +644,35 @@ void Service::HandleEvent(ServiceEvent* event) { |
| jsobj.AddProperty("event", event); |
| jsobj.AddProperty("streamId", stream_id); |
| } |
| - const String& message = String::Handle(String::New(js.ToCString())); |
| - SendEvent(stream_id, ServiceEvent::EventTypeToCString(event->type()), |
| - message); |
| + |
| + // Message is of the format [<stream id>, <json string>]. |
| + // |
| + // Build the event message in the C heap to avoid dart heap |
| + // allocation. This method can be called while we have acquired a |
| + // direct pointer to typed data, so we can't allocate here. |
| + Dart_CObject list_cobj; |
| + Dart_CObject* list_values[2]; |
| + list_cobj.type = Dart_CObject_kArray; |
| + list_cobj.value.as_array.length = 2; |
| + list_cobj.value.as_array.values = list_values; |
| + |
| + Dart_CObject stream_id_cobj; |
| + stream_id_cobj.type = Dart_CObject_kString; |
| + stream_id_cobj.value.as_string = const_cast<char*>(stream_id); |
| + list_values[0] = &stream_id_cobj; |
| + |
| + Dart_CObject json_cobj; |
| + json_cobj.type = Dart_CObject_kString; |
| + json_cobj.value.as_string = const_cast<char*>(js.ToCString()); |
| + list_values[1] = &json_cobj; |
| + |
| + if (FLAG_trace_service) { |
| + OS::Print( |
| + "vm-service: Pushing event of type %s to stream %s\n", |
| + event->KindAsCString(), stream_id); |
| + } |
| + |
| + Dart_PostCObject(ServiceIsolate::Port(), &list_cobj); |
| } |
| @@ -747,6 +796,14 @@ void Service::RegisterRootEmbedderCallback( |
| } |
| +void Service::SetEmbedderStreamCallbacks( |
| + Dart_ServiceStreamListenCallback listen_callback, |
| + Dart_ServiceStreamCancelCallback cancel_callback) { |
| + stream_listen_callback_ = listen_callback; |
| + stream_cancel_callback_ = cancel_callback; |
| +} |
| + |
| + |
| EmbedderServiceHandler* Service::FindRootEmbedderHandler( |
| const char* name) { |
| EmbedderServiceHandler* current = root_service_handler_head_; |
| @@ -830,11 +887,11 @@ void Service::SendEchoEvent(Isolate* isolate, const char* text) { |
| event.AddProperty("text", text); |
| } |
| } |
| - jsobj.AddProperty("streamId", "_Echo"); |
| + jsobj.AddProperty("streamId", kEchoStreamId); |
| } |
| const String& message = String::Handle(String::New(js.ToCString())); |
| uint8_t data[] = {0, 128, 255}; |
| - SendEventWithData("_Echo", "_Echo", message, data, sizeof(data)); |
| + SendEventWithData(kEchoStreamId, "_Echo", message, data, sizeof(data)); |
| } |
| @@ -2349,7 +2406,7 @@ void Service::SendGraphEvent(Isolate* isolate) { |
| event.AddProperty("chunkCount", num_chunks); |
| event.AddProperty("nodeCount", node_count); |
| } |
| - jsobj.AddProperty("streamId", "_Graph"); |
| + jsobj.AddProperty("streamId", kGraphStreamId); |
| } |
| const String& message = String::Handle(String::New(js.ToCString())); |
| @@ -2359,7 +2416,8 @@ void Service::SendGraphEvent(Isolate* isolate) { |
| ? stream.bytes_written() - (i * kChunkSize) |
| : kChunkSize; |
| - SendEventWithData("_Graph", "_Graph", message, chunk_start, chunk_size); |
| + SendEventWithData(kGraphStreamId, "_Graph", message, |
| + chunk_start, chunk_size); |
| } |
| } |
| @@ -2374,6 +2432,22 @@ void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) { |
| } |
| +void Service::SendEmbedderEvent(Isolate* isolate, |
| + const char* stream_id, |
| + const char* event_kind, |
| + const uint8_t* bytes, |
| + intptr_t bytes_len) { |
| + if (!Service::NeedsDebugEvents()) { |
| + return; |
| + } |
| + ServiceEvent event(isolate, ServiceEvent::kEmbedder); |
| + event.set_embedder_kind(event_kind); |
| + event.set_embedder_stream_id(stream_id); |
| + event.set_bytes(bytes, bytes_len); |
| + Service::HandleEvent(&event); |
| +} |
| + |
| + |
| class ContainsAddressVisitor : public FindObjectVisitor { |
| public: |
| ContainsAddressVisitor(Isolate* isolate, uword addr) |