| Index: runtime/vm/service.cc
|
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
|
| index cff1f2819d34e85f5dbb8a2a6533170a449116f1..54f5a5b9d2ccfef7a78b28b82000cb3a3e4238e3 100644
|
| --- a/runtime/vm/service.cc
|
| +++ b/runtime/vm/service.cc
|
| @@ -14,6 +14,7 @@
|
| #include "vm/object_id_ring.h"
|
| #include "vm/object_store.h"
|
| #include "vm/port.h"
|
| +#include "vm/profiler.h"
|
|
|
| namespace dart {
|
|
|
| @@ -251,7 +252,7 @@ static void HandleEcho(Isolate* isolate, JSONStream* js) {
|
| }
|
|
|
|
|
| -static bool GetIntegerId(const char* s, intptr_t* id) {
|
| +static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
|
| if ((s == NULL) || (*s == '\0')) {
|
| // Empty string.
|
| return false;
|
| @@ -262,7 +263,28 @@ static bool GetIntegerId(const char* s, intptr_t* id) {
|
| }
|
| intptr_t r = 0;
|
| char* end_ptr = NULL;
|
| - r = strtol(s, &end_ptr, 10);
|
| + r = strtol(s, &end_ptr, base);
|
| + if (end_ptr == s) {
|
| + // String was not advanced at all, cannot be valid.
|
| + return false;
|
| + }
|
| + *id = r;
|
| + return true;
|
| +}
|
| +
|
| +
|
| +static bool GetUnsignedIntegerId(const char* s, uintptr_t* id, int base = 10) {
|
| + if ((s == NULL) || (*s == '\0')) {
|
| + // Empty string.
|
| + return false;
|
| + }
|
| + if (id == NULL) {
|
| + // No id pointer.
|
| + return false;
|
| + }
|
| + uintptr_t r = 0;
|
| + char* end_ptr = NULL;
|
| + r = strtoul(s, &end_ptr, base);
|
| if (end_ptr == s) {
|
| // String was not advanced at all, cannot be valid.
|
| return false;
|
| @@ -290,8 +312,29 @@ static void HandleClassesClosures(Isolate* isolate, const Class& cls,
|
| }
|
|
|
|
|
| +static void HandleClassesDispatchers(Isolate* isolate, const Class& cls,
|
| + JSONStream* js) {
|
| + intptr_t id;
|
| + if (js->num_arguments() > 4) {
|
| + PrintError(js, "Command too long");
|
| + return;
|
| + }
|
| + if (!GetIntegerId(js->GetArgument(3), &id)) {
|
| + PrintError(js, "Must specify collection object id: dispatchers/id");
|
| + return;
|
| + }
|
| + Function& func = Function::Handle();
|
| + func ^= cls.InvocationDispatcherFunctionFromIndex(id);
|
| + if (func.IsNull()) {
|
| + PrintError(js, "Dispatcher %" Pd " is not a function.", id);
|
| + return;
|
| + }
|
| + func.PrintToJSONStream(js, false);
|
| +}
|
| +
|
| +
|
| static void HandleClassesFunctions(Isolate* isolate, const Class& cls,
|
| - JSONStream* js) {
|
| + JSONStream* js, bool implicit_closure) {
|
| const Array& functions =
|
| Array::Handle(cls.functions());
|
| intptr_t id;
|
| @@ -299,12 +342,28 @@ static void HandleClassesFunctions(Isolate* isolate, const Class& cls,
|
| PrintError(js, "Command too long");
|
| return;
|
| }
|
| - CHECK_COLLECTION_ID_BOUNDS("functions", functions.Length(),
|
| - js->GetArgument(3), id, js);
|
| + if (implicit_closure) {
|
| + CHECK_COLLECTION_ID_BOUNDS("implicit_closures", functions.Length(),
|
| + js->GetArgument(3), id, js);
|
| + } else {
|
| + CHECK_COLLECTION_ID_BOUNDS("functions", functions.Length(),
|
| + js->GetArgument(3), id, js);
|
| + }
|
| Function& function = Function::Handle();
|
| function ^= functions.At(id);
|
| ASSERT(!function.IsNull());
|
| - function.PrintToJSONStream(js, false);
|
| + if (!implicit_closure) {
|
| + function.PrintToJSONStream(js, false);
|
| + return;
|
| + }
|
| + if (!function.HasImplicitClosureFunction()) {
|
| + PrintError(js, "Function %" Pd " does not have an implicit closure.", id);
|
| + return;
|
| + }
|
| + Function& closure_function = Function::Handle();
|
| + closure_function ^= function.ImplicitClosureFunction();
|
| + ASSERT(!closure_function.IsNull());
|
| + closure_function.PrintToJSONStream(js, false);
|
| }
|
|
|
|
|
| @@ -354,7 +413,11 @@ static void HandleClasses(Isolate* isolate, JSONStream* js) {
|
| } else if (!strcmp(second, "fields")) {
|
| HandleClassesFields(isolate, cls, js);
|
| } else if (!strcmp(second, "functions")) {
|
| - HandleClassesFunctions(isolate, cls, js);
|
| + HandleClassesFunctions(isolate, cls, js, false);
|
| + } else if (!strcmp(second, "implicit_closures")) {
|
| + HandleClassesFunctions(isolate, cls, js, true);
|
| + } else if (!strcmp(second, "dispatchers")) {
|
| + HandleClassesDispatchers(isolate, cls, js);
|
| } else {
|
| PrintError(js, "Invalid sub collection %s", second);
|
| }
|
| @@ -521,9 +584,31 @@ static void HandleCpu(Isolate* isolate, JSONStream* js) {
|
| }
|
|
|
|
|
| +static void HandleCode(Isolate* isolate, JSONStream* js) {
|
| + REQUIRE_COLLECTION_ID("code");
|
| + uintptr_t pc;
|
| + if (!GetUnsignedIntegerId(js->GetArgument(1), &pc, 16)) {
|
| + PrintError(js, "Must specify code address: code/c0deadd0.");
|
| + return;
|
| + }
|
| + Code& code = Code::Handle(Code::LookupCode(pc));
|
| + if (code.IsNull()) {
|
| + PrintError(js, "Could not find code at %" Px "", pc);
|
| + return;
|
| + }
|
| + code.PrintToJSONStream(js, false);
|
| +}
|
| +
|
| +
|
| +static void HandleProfile(Isolate* isolate, JSONStream* js) {
|
| + Profiler::PrintToJSONStream(isolate, js, true);
|
| +}
|
| +
|
| +
|
| static ServiceMessageHandlerEntry __message_handlers[] = {
|
| { "_echo", HandleEcho },
|
| { "classes", HandleClasses },
|
| + { "code", HandleCode },
|
| { "cpu", HandleCpu },
|
| { "debug", HandleDebug },
|
| { "libraries", HandleLibraries },
|
| @@ -531,6 +616,7 @@ static ServiceMessageHandlerEntry __message_handlers[] = {
|
| { "name", HandleName },
|
| { "objecthistogram", HandleObjectHistogram},
|
| { "objects", HandleObjects },
|
| + { "profile", HandleProfile },
|
| { "scripts", HandleScripts },
|
| { "stacktrace", HandleStackTrace },
|
| };
|
|
|