| Index: runtime/vm/service.cc
|
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
|
| index 6a27c19c85e6d08c67202e44d3ffb31221c8ea4b..ffb08c0f13ef4b7766f6da917e3e7a2b25250e6d 100644
|
| --- a/runtime/vm/service.cc
|
| +++ b/runtime/vm/service.cc
|
| @@ -2,6 +2,8 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| +#include "vm/debugger.h"
|
| +#include "vm/heap_histogram.h"
|
| #include "vm/isolate.h"
|
| #include "vm/message.h"
|
| #include "vm/object.h"
|
| @@ -10,6 +12,16 @@
|
|
|
| namespace dart {
|
|
|
| +typedef RawString* (*ServiceMessageHandler)(Isolate* isolate);
|
| +
|
| +struct ServiceMessageHandlerEntry {
|
| + const char* command;
|
| + ServiceMessageHandler handler;
|
| +};
|
| +
|
| +static ServiceMessageHandler FindServiceMessageHandler(const char* command);
|
| +
|
| +
|
| static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
|
| void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
|
| return reinterpret_cast<uint8_t*>(new_ptr);
|
| @@ -26,28 +38,133 @@ static void PostReply(const String& reply, Dart_Port reply_port) {
|
| }
|
|
|
|
|
| -static RawString* HandleIdMessage(Isolate* isolate, Dart_Port reply_port) {
|
| +void Service::HandleServiceMessage(Isolate* isolate, Dart_Port reply_port,
|
| + const Instance& msg) {
|
| + ASSERT(isolate != NULL);
|
| + ASSERT(reply_port != ILLEGAL_PORT);
|
| + ASSERT(!msg.IsNull());
|
| + ASSERT(msg.IsGrowableObjectArray());
|
| +
|
| + {
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + const GrowableObjectArray& message = GrowableObjectArray::Cast(msg);
|
| + // Message is a list with three entries.
|
| + ASSERT(message.Length() == 3);
|
| +
|
| + GrowableObjectArray& path = GrowableObjectArray::Handle();
|
| + GrowableObjectArray& option_keys = GrowableObjectArray::Handle();
|
| + GrowableObjectArray& option_values = GrowableObjectArray::Handle();
|
| + path ^= message.At(0);
|
| + option_keys ^= message.At(1);
|
| + option_values ^= message.At(2);
|
| +
|
| + ASSERT(!path.IsNull());
|
| + ASSERT(!option_keys.IsNull());
|
| + ASSERT(!option_values.IsNull());
|
| + // Path always has at least one entry in it.
|
| + ASSERT(path.Length() > 0);
|
| + // Same number of option keys as values.
|
| + ASSERT(option_keys.Length() == option_values.Length());
|
| +
|
| + String& pathSegment = String::Handle();
|
| + pathSegment ^= path.At(0);
|
| + ASSERT(!pathSegment.IsNull());
|
| +
|
| + ServiceMessageHandler handler =
|
| + FindServiceMessageHandler(pathSegment.ToCString());
|
| + String& reply = String::Handle();
|
| + reply ^= handler(isolate);
|
| + ASSERT(!reply.IsNull());
|
| + PostReply(reply, reply_port);
|
| + }
|
| +}
|
| +
|
| +
|
| +static RawString* HandleName(Isolate* isolate) {
|
| TextBuffer buffer(256);
|
| - buffer.Printf("{ \"id\": \"%s\" }", isolate->name());
|
| + JSONStream js(&buffer);
|
| + js.OpenObject();
|
| + js.PrintProperty("type", "IsolateName");
|
| + js.PrintProperty("id", static_cast<intptr_t>(isolate->main_port()));
|
| + js.PrintProperty("name", isolate->name());
|
| + js.CloseObject();
|
| return String::New(buffer.buf());
|
| }
|
|
|
|
|
| -void Service::HandleServiceMessage(Isolate* isolate, Dart_Port reply_port,
|
| - const Instance& message) {
|
| - ASSERT(isolate != NULL);
|
| - ASSERT(reply_port != ILLEGAL_PORT);
|
| - ASSERT(!message.IsNull());
|
| - ASSERT(message.IsString());
|
| +RawString* HandleStackTrace(Isolate* isolate) {
|
| + TextBuffer buffer(256);
|
| + JSONStream js(&buffer);
|
| + DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
|
| + js.OpenObject();
|
| + js.PrintProperty("type", "StackTrace");
|
| + js.OpenArray("members");
|
| + intptr_t n_frames = stack->Length();
|
| + String& url = String::Handle();
|
| + String& function = String::Handle();
|
| + for (int i = 0; i < n_frames; i++) {
|
| + ActivationFrame* frame = stack->ActivationFrameAt(i);
|
| + url ^= frame->SourceUrl();
|
| + function ^= frame->function().UserVisibleName();
|
| + js.OpenObject();
|
| + js.PrintProperty("name", function.ToCString());
|
| + js.PrintProperty("url", url.ToCString());
|
| + js.PrintProperty("line", frame->LineNumber());
|
| + js.PrintProperty("function", frame->function());
|
| + js.PrintProperty("code", frame->code());
|
| + js.CloseObject();
|
| + }
|
| + js.CloseArray();
|
| + js.CloseObject();
|
| + return String::New(buffer.buf());
|
| +}
|
|
|
| - String& reply = String::Handle();
|
|
|
| - // For now, assume service message is always an id check.
|
| - reply = HandleIdMessage(isolate, reply_port);
|
| +RawString* HandleObjectHistogram(Isolate* isolate) {
|
| + TextBuffer buffer(256);
|
| + JSONStream js(&buffer);
|
| + ObjectHistogram* histogram = Isolate::Current()->object_histogram();
|
| + if (histogram == NULL) {
|
| + js.OpenObject();
|
| + js.PrintProperty("type", "ObjectHistogram");
|
| + js.PrintProperty("error", "Run with --print_object_histogram");
|
| + js.CloseObject();
|
| + return String::New(buffer.buf());
|
| + }
|
| + histogram->PrintToJSONStream(&js);
|
| + return String::New(buffer.buf());
|
| +}
|
| +
|
| +
|
| +static ServiceMessageHandlerEntry __message_handlers[] = {
|
| + { "name", HandleName },
|
| + { "stacktrace", HandleStackTrace },
|
| + { "objecthistogram", HandleObjectHistogram},
|
| +};
|
| +
|
| +
|
| +static RawString* HandleFallthrough(Isolate* isolate) {
|
| + TextBuffer buffer(256);
|
| + JSONStream js(&buffer);
|
| + js.OpenObject();
|
| + js.PrintProperty("type", "error");
|
| + js.PrintProperty("text", "request not supported.");
|
| + js.CloseObject();
|
| + return String::New(buffer.buf());
|
| +}
|
|
|
| - ASSERT(!reply.IsNull());
|
|
|
| - PostReply(reply, reply_port);
|
| +static ServiceMessageHandler FindServiceMessageHandler(const char* command) {
|
| + intptr_t num_message_handlers = sizeof(__message_handlers) /
|
| + sizeof(__message_handlers[0]);
|
| + for (intptr_t i = 0; i < num_message_handlers; i++) {
|
| + const ServiceMessageHandlerEntry& entry = __message_handlers[i];
|
| + if (!strcmp(command, entry.command)) {
|
| + return entry.handler;
|
| + }
|
| + }
|
| + return HandleFallthrough;
|
| }
|
|
|
| } // namespace dart
|
|
|