| Index: runtime/vm/service.cc
|
| ===================================================================
|
| --- runtime/vm/service.cc (revision 31848)
|
| +++ runtime/vm/service.cc (working copy)
|
| @@ -106,7 +106,7 @@
|
| }
|
|
|
|
|
| -static void SendServiceMessage(Dart_NativeArguments args) {
|
| +static void SendIsolateServiceMessage(Dart_NativeArguments args) {
|
| NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| Isolate* isolate = arguments->isolate();
|
| StackZone zone(isolate);
|
| @@ -119,7 +119,7 @@
|
| if (sp_id_obj.IsError()) {
|
| Exceptions::PropagateError(Error::Cast(sp_id_obj));
|
| }
|
| - Integer& id = Integer::Handle();
|
| + Integer& id = Integer::Handle(isolate);
|
| id ^= sp_id_obj.raw();
|
| Dart_Port sp_id = static_cast<Dart_Port>(id.AsInt64Value());
|
| ASSERT(sp_id != ILLEGAL_PORT);
|
| @@ -135,6 +135,16 @@
|
| }
|
|
|
|
|
| +static void SendRootServiceMessage(Dart_NativeArguments args) {
|
| + NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| + Isolate* isolate = arguments->isolate();
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(0));
|
| + Service::HandleRootMessage(message);
|
| +}
|
| +
|
| +
|
| struct VmServiceNativeEntry {
|
| const char* name;
|
| int num_arguments;
|
| @@ -143,7 +153,8 @@
|
|
|
|
|
| static VmServiceNativeEntry _VmServiceNativeEntries[] = {
|
| - {"VMService_SendServiceMessage", 2, SendServiceMessage}
|
| + {"VMService_SendIsolateServiceMessage", 2, SendIsolateServiceMessage},
|
| + {"VMService_SendRootServiceMessage", 1, SendRootServiceMessage}
|
| };
|
|
|
|
|
| @@ -394,108 +405,96 @@
|
| }
|
|
|
|
|
| -typedef void (*ServiceMessageHandler)(Isolate* isolate, JSONStream* stream);
|
| +// A handler for a per-isolate request.
|
| +//
|
| +// If a handler returns true, the reply is complete and ready to be
|
| +// posted. If a handler returns false, then it is responsible for
|
| +// posting the reply (this can be used for asynchronous delegation of
|
| +// the response handling).
|
| +typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream);
|
|
|
| -struct ServiceMessageHandlerEntry {
|
| +struct IsolateMessageHandlerEntry {
|
| const char* command;
|
| - ServiceMessageHandler handler;
|
| + IsolateMessageHandler handler;
|
| };
|
|
|
| -static ServiceMessageHandler FindServiceMessageHandler(const char* command);
|
| +static IsolateMessageHandler FindIsolateMessageHandler(const char* command);
|
|
|
| -static void PostReply(const String& reply, const Instance& reply_port) {
|
| - const Object& id_obj = Object::Handle(
|
| - DartLibraryCalls::PortGetId(reply_port));
|
| - if (id_obj.IsError()) {
|
| - Exceptions::PropagateError(Error::Cast(id_obj));
|
| - }
|
| - const Integer& id = Integer::Cast(id_obj);
|
| - Dart_Port port = static_cast<Dart_Port>(id.AsInt64Value());
|
| - ASSERT(port != ILLEGAL_PORT);
|
|
|
| +// A handler for a root (vm-global) request.
|
| +//
|
| +// If a handler returns true, the reply is complete and ready to be
|
| +// posted. If a handler returns false, then it is responsible for
|
| +// posting the reply (this can be used for asynchronous delegation of
|
| +// the response handling).
|
| +typedef bool (*RootMessageHandler)(JSONStream* stream);
|
| +
|
| +struct RootMessageHandlerEntry {
|
| + const char* command;
|
| + RootMessageHandler handler;
|
| +};
|
| +
|
| +static RootMessageHandler FindRootMessageHandler(const char* command);
|
| +
|
| +
|
| +static void PostReply(JSONStream* js) {
|
| + Dart_Port reply_port = js->reply_port();
|
| + ASSERT(reply_port != ILLEGAL_PORT);
|
| + js->set_reply_port(ILLEGAL_PORT); // Prevent double replies.
|
| +
|
| + const String& reply = String::Handle(String::New(js->ToCString()));
|
| + ASSERT(!reply.IsNull());
|
| +
|
| uint8_t* data = NULL;
|
| MessageWriter writer(&data, &allocator);
|
| writer.WriteMessage(reply);
|
| - PortMap::PostMessage(new Message(port, data,
|
| + PortMap::PostMessage(new Message(reply_port, data,
|
| writer.BytesWritten(),
|
| Message::kNormalPriority));
|
| }
|
|
|
|
|
| -void Service::HandleServiceMessage(Isolate* isolate, const Instance& msg) {
|
| - ASSERT(isolate != NULL);
|
| - ASSERT(!msg.IsNull());
|
| - ASSERT(msg.IsGrowableObjectArray());
|
| +static void SetupJSONStream(JSONStream* js, Zone* zone,
|
| + const Instance& reply_port,
|
| + const GrowableObjectArray& path,
|
| + const GrowableObjectArray& option_keys,
|
| + const GrowableObjectArray& option_values) {
|
| + // Setup the reply port.
|
| + const Object& id_obj = Object::Handle(
|
| + DartLibraryCalls::PortGetId(reply_port));
|
| + if (id_obj.IsError()) {
|
| + Exceptions::PropagateError(Error::Cast(id_obj));
|
| + }
|
| + const Integer& id = Integer::Cast(id_obj);
|
| + Dart_Port port = static_cast<Dart_Port>(id.AsInt64Value());
|
| + ASSERT(port != ILLEGAL_PORT);
|
| + js->set_reply_port(port);
|
|
|
| - {
|
| - StackZone zone(isolate);
|
| - HANDLESCOPE(isolate);
|
| -
|
| - const GrowableObjectArray& message = GrowableObjectArray::Cast(msg);
|
| - // Message is a list with three entries.
|
| - ASSERT(message.Length() == 4);
|
| -
|
| - Instance& reply_port = Instance::Handle(isolate);
|
| - GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
|
| - GrowableObjectArray& option_keys = GrowableObjectArray::Handle(isolate);
|
| - GrowableObjectArray& option_values = GrowableObjectArray::Handle(isolate);
|
| - reply_port ^= message.At(0);
|
| - path ^= message.At(1);
|
| - option_keys ^= message.At(2);
|
| - option_values ^= message.At(3);
|
| -
|
| - 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());
|
| - ASSERT(handler != NULL);
|
| - {
|
| - JSONStream js;
|
| -
|
| - // Setup JSONStream arguments and options. The arguments and options
|
| - // are zone allocated and will be freed immediately after handling the
|
| - // message.
|
| - Zone* zoneAllocator = zone.GetZone();
|
| - const char** arguments = zoneAllocator->Alloc<const char*>(path.Length());
|
| - String& string_iterator = String::Handle();
|
| - for (intptr_t i = 0; i < path.Length(); i++) {
|
| - string_iterator ^= path.At(i);
|
| - arguments[i] =
|
| - zoneAllocator->MakeCopyOfString(string_iterator.ToCString());
|
| - }
|
| - js.SetArguments(arguments, path.Length());
|
| - if (option_keys.Length() > 0) {
|
| - const char** option_keys_native =
|
| - zoneAllocator->Alloc<const char*>(option_keys.Length());
|
| - const char** option_values_native =
|
| - zoneAllocator->Alloc<const char*>(option_keys.Length());
|
| - for (intptr_t i = 0; i < option_keys.Length(); i++) {
|
| - string_iterator ^= option_keys.At(i);
|
| - option_keys_native[i] =
|
| - zoneAllocator->MakeCopyOfString(string_iterator.ToCString());
|
| - string_iterator ^= option_values.At(i);
|
| - option_values_native[i] =
|
| - zoneAllocator->MakeCopyOfString(string_iterator.ToCString());
|
| - }
|
| - js.SetOptions(option_keys_native, option_values_native,
|
| - option_keys.Length());
|
| - }
|
| -
|
| - handler(isolate, &js);
|
| - const String& reply = String::Handle(String::New(js.ToCString()));
|
| - ASSERT(!reply.IsNull());
|
| - PostReply(reply, reply_port);
|
| + // Setup JSONStream arguments and options. The arguments and options
|
| + // are zone allocated and will be freed immediately after handling the
|
| + // message.
|
| + const char** arguments = zone->Alloc<const char*>(path.Length());
|
| + String& string_iterator = String::Handle();
|
| + for (intptr_t i = 0; i < path.Length(); i++) {
|
| + string_iterator ^= path.At(i);
|
| + arguments[i] = zone->MakeCopyOfString(string_iterator.ToCString());
|
| + }
|
| + js->SetArguments(arguments, path.Length());
|
| + if (option_keys.Length() > 0) {
|
| + const char** option_keys_native =
|
| + zone->Alloc<const char*>(option_keys.Length());
|
| + const char** option_values_native =
|
| + zone->Alloc<const char*>(option_keys.Length());
|
| + for (intptr_t i = 0; i < option_keys.Length(); i++) {
|
| + string_iterator ^= option_keys.At(i);
|
| + option_keys_native[i] =
|
| + zone->MakeCopyOfString(string_iterator.ToCString());
|
| + string_iterator ^= option_values.At(i);
|
| + option_values_native[i] =
|
| + zone->MakeCopyOfString(string_iterator.ToCString());
|
| }
|
| + js->SetOptions(option_keys_native, option_values_native,
|
| + option_keys.Length());
|
| }
|
| }
|
|
|
| @@ -523,14 +522,6 @@
|
| }
|
|
|
|
|
| -static void PrintGenericError(JSONStream* js) {
|
| - JSONObject jsobj(js);
|
| - jsobj.AddProperty("type", "Error");
|
| - jsobj.AddProperty("text", "Invalid request.");
|
| - PrintArgumentsAndOptions(jsobj, js);
|
| -}
|
| -
|
| -
|
| static void PrintError(JSONStream* js, const char* format, ...) {
|
| Isolate* isolate = Isolate::Current();
|
|
|
| @@ -552,15 +543,70 @@
|
| }
|
|
|
|
|
| -static void HandleName(Isolate* isolate, JSONStream* js) {
|
| +void Service::HandleIsolateMessage(Isolate* isolate, const Instance& msg) {
|
| + ASSERT(isolate != NULL);
|
| + ASSERT(!msg.IsNull());
|
| + ASSERT(msg.IsGrowableObjectArray());
|
| +
|
| + {
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| +
|
| + const GrowableObjectArray& message = GrowableObjectArray::Cast(msg);
|
| + // Message is a list with four entries.
|
| + ASSERT(message.Length() == 4);
|
| +
|
| + Instance& reply_port = Instance::Handle(isolate);
|
| + GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
|
| + GrowableObjectArray& option_keys = GrowableObjectArray::Handle(isolate);
|
| + GrowableObjectArray& option_values = GrowableObjectArray::Handle(isolate);
|
| + reply_port ^= message.At(0);
|
| + path ^= message.At(1);
|
| + option_keys ^= message.At(2);
|
| + option_values ^= message.At(3);
|
| +
|
| + 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());
|
| +
|
| + IsolateMessageHandler handler =
|
| + FindIsolateMessageHandler(pathSegment.ToCString());
|
| + {
|
| + JSONStream js;
|
| + SetupJSONStream(&js, zone.GetZone(),
|
| + reply_port, path, option_keys, option_values);
|
| + if (handler == NULL) {
|
| + PrintError(&js, "Unrecognized path");
|
| + PostReply(&js);
|
| + } else {
|
| + if (handler(isolate, &js)) {
|
| + // Handler returns true if the reply is ready to be posted.
|
| + PostReply(&js);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +static bool HandleName(Isolate* isolate, JSONStream* js) {
|
| JSONObject jsobj(js);
|
| jsobj.AddProperty("type", "IsolateName");
|
| jsobj.AddProperty("id", static_cast<intptr_t>(isolate->main_port()));
|
| jsobj.AddProperty("name", isolate->name());
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleStackTrace(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleStackTrace(Isolate* isolate, JSONStream* js) {
|
| DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
|
| JSONObject jsobj(js);
|
| jsobj.AddProperty("type", "StackTrace");
|
| @@ -579,45 +625,48 @@
|
| jsobj.AddProperty("function", frame->function());
|
| jsobj.AddProperty("code", frame->code());
|
| }
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleObjectHistogram(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleObjectHistogram(Isolate* isolate, JSONStream* js) {
|
| ObjectHistogram* histogram = Isolate::Current()->object_histogram();
|
| if (histogram == NULL) {
|
| JSONObject jsobj(js);
|
| jsobj.AddProperty("type", "Error");
|
| jsobj.AddProperty("text", "Run with --print_object_histogram");
|
| - return;
|
| + return true;
|
| }
|
| histogram->PrintToJSONStream(js);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleEcho(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleIsolateEcho(Isolate* isolate, JSONStream* js) {
|
| JSONObject jsobj(js);
|
| jsobj.AddProperty("type", "message");
|
| PrintArgumentsAndOptions(jsobj, js);
|
| + return true;
|
| }
|
|
|
|
|
| // Print an error message if there is no ID argument.
|
| -#define REQUIRE_COLLECTION_ID(collection) \
|
| - if (js->num_arguments() == 1) { \
|
| - PrintError(js, "Must specify collection object id: /%s/id", collection); \
|
| - return; \
|
| +#define REQUIRE_COLLECTION_ID(collection) \
|
| + if (js->num_arguments() == 1) { \
|
| + PrintError(js, "Must specify collection object id: /%s/id", collection); \
|
| + return true; \
|
| }
|
|
|
|
|
| #define CHECK_COLLECTION_ID_BOUNDS(collection, length, arg, id, js) \
|
| if (!GetIntegerId(arg, &id)) { \
|
| PrintError(js, "Must specify collection object id: %s/id", collection); \
|
| - return; \
|
| + return true; \
|
| } \
|
| if ((id < 0) || (id >= length)) { \
|
| PrintError(js, "%s id (%" Pd ") must be in [0, %" Pd ").", collection, id, \
|
| length); \
|
| - return; \
|
| + return true; \
|
| }
|
|
|
|
|
| @@ -663,164 +712,171 @@
|
| }
|
|
|
|
|
| -static void HandleClassesClosures(Isolate* isolate, const Class& cls,
|
| +static bool HandleClassesClosures(Isolate* isolate, const Class& cls,
|
| JSONStream* js) {
|
| intptr_t id;
|
| if (js->num_arguments() > 4) {
|
| PrintError(js, "Command too long");
|
| - return;
|
| + return true;
|
| }
|
| if (!GetIntegerId(js->GetArgument(3), &id)) {
|
| PrintError(js, "Must specify collection object id: closures/id");
|
| - return;
|
| + return true;
|
| }
|
| Function& func = Function::Handle();
|
| func ^= cls.ClosureFunctionFromIndex(id);
|
| if (func.IsNull()) {
|
| PrintError(js, "Closure function %" Pd " not found", id);
|
| - return;
|
| + return true;
|
| }
|
| func.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleClassesDispatchers(Isolate* isolate, const Class& cls,
|
| +static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls,
|
| JSONStream* js) {
|
| intptr_t id;
|
| if (js->num_arguments() > 4) {
|
| PrintError(js, "Command too long");
|
| - return;
|
| + return true;
|
| }
|
| if (!GetIntegerId(js->GetArgument(3), &id)) {
|
| PrintError(js, "Must specify collection object id: dispatchers/id");
|
| - return;
|
| + return true;
|
| }
|
| Function& func = Function::Handle();
|
| func ^= cls.InvocationDispatcherFunctionFromIndex(id);
|
| if (func.IsNull()) {
|
| PrintError(js, "Dispatcher %" Pd " not found", id);
|
| - return;
|
| + return true;
|
| }
|
| func.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleClassesFunctions(Isolate* isolate, const Class& cls,
|
| +static bool HandleClassesFunctions(Isolate* isolate, const Class& cls,
|
| JSONStream* js) {
|
| intptr_t id;
|
| if (js->num_arguments() > 4) {
|
| PrintError(js, "Command too long");
|
| - return;
|
| + return true;
|
| }
|
| if (!GetIntegerId(js->GetArgument(3), &id)) {
|
| PrintError(js, "Must specify collection object id: functions/id");
|
| - return;
|
| + return true;
|
| }
|
| Function& func = Function::Handle();
|
| func ^= cls.FunctionFromIndex(id);
|
| if (func.IsNull()) {
|
| PrintError(js, "Function %" Pd " not found", id);
|
| - return;
|
| + return true;
|
| }
|
| func.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleClassesImplicitClosures(Isolate* isolate, const Class& cls,
|
| +static bool HandleClassesImplicitClosures(Isolate* isolate, const Class& cls,
|
| JSONStream* js) {
|
| intptr_t id;
|
| if (js->num_arguments() > 4) {
|
| PrintError(js, "Command too long");
|
| - return;
|
| + return true;
|
| }
|
| if (!GetIntegerId(js->GetArgument(3), &id)) {
|
| PrintError(js, "Must specify collection object id: implicit_closures/id");
|
| - return;
|
| + return true;
|
| }
|
| Function& func = Function::Handle();
|
| func ^= cls.ImplicitClosureFunctionFromIndex(id);
|
| if (func.IsNull()) {
|
| PrintError(js, "Implicit closure function %" Pd " not found", id);
|
| - return;
|
| + return true;
|
| }
|
| func.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleClassesFields(Isolate* isolate, const Class& cls,
|
| +static bool HandleClassesFields(Isolate* isolate, const Class& cls,
|
| JSONStream* js) {
|
| intptr_t id;
|
| if (js->num_arguments() > 4) {
|
| PrintError(js, "Command too long");
|
| - return;
|
| + return true;
|
| }
|
| if (!GetIntegerId(js->GetArgument(3), &id)) {
|
| PrintError(js, "Must specify collection object id: fields/id");
|
| - return;
|
| + return true;
|
| }
|
| Field& field = Field::Handle(cls.FieldFromIndex(id));
|
| if (field.IsNull()) {
|
| PrintError(js, "Field %" Pd " not found", id);
|
| - return;
|
| + return true;
|
| }
|
| field.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleClasses(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleClasses(Isolate* isolate, JSONStream* js) {
|
| if (js->num_arguments() == 1) {
|
| ClassTable* table = isolate->class_table();
|
| table->PrintToJSONStream(js);
|
| - return;
|
| + return true;
|
| }
|
| ASSERT(js->num_arguments() >= 2);
|
| intptr_t id;
|
| if (!GetIntegerId(js->GetArgument(1), &id)) {
|
| PrintError(js, "Must specify collection object id: /classes/id");
|
| - return;
|
| + return true;
|
| }
|
| ClassTable* table = isolate->class_table();
|
| if (!table->IsValidIndex(id)) {
|
| PrintError(js, "%" Pd " is not a valid class id.", id);;
|
| - return;
|
| + return true;
|
| }
|
| Class& cls = Class::Handle(table->At(id));
|
| if (js->num_arguments() == 2) {
|
| cls.PrintToJSONStream(js, false);
|
| - return;
|
| + return true;
|
| } else if (js->num_arguments() >= 3) {
|
| const char* second = js->GetArgument(2);
|
| if (!strcmp(second, "closures")) {
|
| - HandleClassesClosures(isolate, cls, js);
|
| + return HandleClassesClosures(isolate, cls, js);
|
| } else if (!strcmp(second, "fields")) {
|
| - HandleClassesFields(isolate, cls, js);
|
| + return HandleClassesFields(isolate, cls, js);
|
| } else if (!strcmp(second, "functions")) {
|
| - HandleClassesFunctions(isolate, cls, js);
|
| + return HandleClassesFunctions(isolate, cls, js);
|
| } else if (!strcmp(second, "implicit_closures")) {
|
| - HandleClassesImplicitClosures(isolate, cls, js);
|
| + return HandleClassesImplicitClosures(isolate, cls, js);
|
| } else if (!strcmp(second, "dispatchers")) {
|
| - HandleClassesDispatchers(isolate, cls, js);
|
| + return HandleClassesDispatchers(isolate, cls, js);
|
| } else {
|
| PrintError(js, "Invalid sub collection %s", second);
|
| + return true;
|
| }
|
| - return;
|
| }
|
| UNREACHABLE();
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleLibrary(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleLibrary(Isolate* isolate, JSONStream* js) {
|
| if (js->num_arguments() == 1) {
|
| const Library& lib =
|
| Library::Handle(isolate->object_store()->root_library());
|
| lib.PrintToJSONStream(js, false);
|
| - return;
|
| + return true;
|
| }
|
| - PrintGenericError(js);
|
| + PrintError(js, "Command too long");
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleLibraries(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleLibraries(Isolate* isolate, JSONStream* js) {
|
| // TODO(johnmccutchan): Support fields and functions on libraries.
|
| REQUIRE_COLLECTION_ID("libraries");
|
| const GrowableObjectArray& libs =
|
| @@ -833,10 +889,11 @@
|
| lib ^= libs.At(id);
|
| ASSERT(!lib.IsNull());
|
| lib.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleObjects(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleObjects(Isolate* isolate, JSONStream* js) {
|
| REQUIRE_COLLECTION_ID("objects");
|
| ASSERT(js->num_arguments() >= 2);
|
| ObjectIdRing* ring = isolate->object_id_ring();
|
| @@ -844,41 +901,41 @@
|
| intptr_t id = -1;
|
| if (!GetIntegerId(js->GetArgument(1), &id)) {
|
| Object::null_object().PrintToJSONStream(js, false);
|
| - return;
|
| + return true;
|
| }
|
| Object& obj = Object::Handle(ring->GetObjectForId(id));
|
| obj.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
|
|
| -static void HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) {
|
| JSONObject jsobj(js);
|
| jsobj.AddProperty("type", "ScriptList");
|
| - {
|
| - JSONArray members(&jsobj, "members");
|
| - const GrowableObjectArray& libs =
|
| + JSONArray members(&jsobj, "members");
|
| + const GrowableObjectArray& libs =
|
| GrowableObjectArray::Handle(isolate->object_store()->libraries());
|
| - int num_libs = libs.Length();
|
| - Library &lib = Library::Handle();
|
| - Script& script = Script::Handle();
|
| - for (intptr_t i = 0; i < num_libs; i++) {
|
| - lib ^= libs.At(i);
|
| - ASSERT(!lib.IsNull());
|
| - ASSERT(Smi::IsValid(lib.index()));
|
| - const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
|
| - ASSERT(!loaded_scripts.IsNull());
|
| - intptr_t num_scripts = loaded_scripts.Length();
|
| - for (intptr_t i = 0; i < num_scripts; i++) {
|
| - script ^= loaded_scripts.At(i);
|
| - members.AddValue(script);
|
| - }
|
| + int num_libs = libs.Length();
|
| + Library &lib = Library::Handle();
|
| + Script& script = Script::Handle();
|
| + for (intptr_t i = 0; i < num_libs; i++) {
|
| + lib ^= libs.At(i);
|
| + ASSERT(!lib.IsNull());
|
| + ASSERT(Smi::IsValid(lib.index()));
|
| + const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
|
| + ASSERT(!loaded_scripts.IsNull());
|
| + intptr_t num_scripts = loaded_scripts.Length();
|
| + for (intptr_t i = 0; i < num_scripts; i++) {
|
| + script ^= loaded_scripts.At(i);
|
| + members.AddValue(script);
|
| }
|
| }
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleScriptsFetch(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleScriptsFetch(Isolate* isolate, JSONStream* js) {
|
| const GrowableObjectArray& libs =
|
| GrowableObjectArray::Handle(isolate->object_store()->libraries());
|
| int num_libs = libs.Length();
|
| @@ -902,31 +959,33 @@
|
| url ^= script.url();
|
| if (url.Equals(requested_url)) {
|
| script.PrintToJSONStream(js, false);
|
| - return;
|
| + return true;
|
| }
|
| }
|
| }
|
| PrintError(js, "Cannot find script %s\n", requested_url.ToCString());
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleScripts(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleScripts(Isolate* isolate, JSONStream* js) {
|
| if (js->num_arguments() == 1) {
|
| // Enumerate all scripts.
|
| - HandleScriptsEnumerate(isolate, js);
|
| + return HandleScriptsEnumerate(isolate, js);
|
| } else if (js->num_arguments() == 2) {
|
| // Fetch specific script.
|
| - HandleScriptsFetch(isolate, js);
|
| + return HandleScriptsFetch(isolate, js);
|
| } else {
|
| PrintError(js, "Command too long");
|
| + return true;
|
| }
|
| }
|
|
|
|
|
| -static void HandleDebug(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleDebug(Isolate* isolate, JSONStream* js) {
|
| if (js->num_arguments() == 1) {
|
| PrintError(js, "Must specify a subcommand");
|
| - return;
|
| + return true;
|
| }
|
| const char* command = js->GetArgument(1);
|
| if (!strcmp(command, "breakpoints")) {
|
| @@ -936,7 +995,7 @@
|
| jsobj.AddProperty("type", "BreakpointList");
|
| JSONArray jsarr(&jsobj, "breakpoints");
|
| isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
|
| -
|
| + return true;
|
| } else if (js->num_arguments() == 3) {
|
| // Print individual breakpoint.
|
| intptr_t id = 0;
|
| @@ -946,52 +1005,49 @@
|
| }
|
| if (bpt != NULL) {
|
| bpt->PrintToJSONStream(js);
|
| + return true;
|
| } else {
|
| PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2));
|
| + return true;
|
| }
|
| -
|
| } else {
|
| PrintError(js, "Command too long");
|
| + return true;
|
| }
|
| } else {
|
| PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1));
|
| + return true;
|
| }
|
| }
|
|
|
|
|
| -static void HandleCpu(Isolate* isolate, JSONStream* js) {
|
| - JSONObject jsobj(js);
|
| - jsobj.AddProperty("type", "CPU");
|
| - jsobj.AddProperty("architecture", CPU::Id());
|
| -}
|
| -
|
| -
|
| -static void HandleCode(Isolate* isolate, JSONStream* js) {
|
| +static bool 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;
|
| + return true;
|
| }
|
| Code& code = Code::Handle(Code::LookupCode(pc));
|
| if (code.IsNull()) {
|
| PrintError(js, "Could not find code at %" Px "", pc);
|
| - return;
|
| + return true;
|
| }
|
| code.PrintToJSONStream(js, false);
|
| + return true;
|
| }
|
|
|
|
|
| -static void HandleProfile(Isolate* isolate, JSONStream* js) {
|
| +static bool HandleProfile(Isolate* isolate, JSONStream* js) {
|
| Profiler::PrintToJSONStream(isolate, js, true);
|
| + return true;
|
| }
|
|
|
|
|
| -static ServiceMessageHandlerEntry __message_handlers[] = {
|
| - { "_echo", HandleEcho },
|
| +static IsolateMessageHandlerEntry isolate_handlers[] = {
|
| + { "_echo", HandleIsolateEcho },
|
| { "classes", HandleClasses },
|
| { "code", HandleCode },
|
| - { "cpu", HandleCpu },
|
| { "debug", HandleDebug },
|
| { "libraries", HandleLibraries },
|
| { "library", HandleLibrary },
|
| @@ -1004,24 +1060,105 @@
|
| };
|
|
|
|
|
| -static void HandleFallthrough(Isolate* isolate, JSONStream* js) {
|
| +static IsolateMessageHandler FindIsolateMessageHandler(const char* command) {
|
| + intptr_t num_message_handlers = sizeof(isolate_handlers) /
|
| + sizeof(isolate_handlers[0]);
|
| + for (intptr_t i = 0; i < num_message_handlers; i++) {
|
| + const IsolateMessageHandlerEntry& entry = isolate_handlers[i];
|
| + if (!strcmp(command, entry.command)) {
|
| + return entry.handler;
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void Service::HandleRootMessage(const Instance& msg) {
|
| + Isolate* isolate = Isolate::Current();
|
| + ASSERT(!msg.IsNull());
|
| + ASSERT(msg.IsGrowableObjectArray());
|
| +
|
| + {
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| +
|
| + const GrowableObjectArray& message = GrowableObjectArray::Cast(msg);
|
| + // Message is a list with four entries.
|
| + ASSERT(message.Length() == 4);
|
| +
|
| + Instance& reply_port = Instance::Handle(isolate);
|
| + GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
|
| + GrowableObjectArray& option_keys = GrowableObjectArray::Handle(isolate);
|
| + GrowableObjectArray& option_values = GrowableObjectArray::Handle(isolate);
|
| + reply_port ^= message.At(0);
|
| + path ^= message.At(1);
|
| + option_keys ^= message.At(2);
|
| + option_values ^= message.At(3);
|
| +
|
| + 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());
|
| +
|
| + RootMessageHandler handler =
|
| + FindRootMessageHandler(pathSegment.ToCString());
|
| + {
|
| + JSONStream js;
|
| + SetupJSONStream(&js, zone.GetZone(),
|
| + reply_port, path, option_keys, option_values);
|
| + if (handler == NULL) {
|
| + PrintError(&js, "Unrecognized path");
|
| + PostReply(&js);
|
| + } else {
|
| + if (handler(&js)) {
|
| + // Handler returns true if the reply is ready to be posted.
|
| + PostReply(&js);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +static bool HandleRootEcho(JSONStream* js) {
|
| JSONObject jsobj(js);
|
| - jsobj.AddProperty("type", "Error");
|
| - jsobj.AddProperty("text", "request not understood.");
|
| + jsobj.AddProperty("type", "message");
|
| PrintArgumentsAndOptions(jsobj, js);
|
| + return true;
|
| }
|
|
|
|
|
| -static ServiceMessageHandler FindServiceMessageHandler(const char* command) {
|
| - intptr_t num_message_handlers = sizeof(__message_handlers) /
|
| - sizeof(__message_handlers[0]);
|
| +static bool HandleCpu(JSONStream* js) {
|
| + JSONObject jsobj(js);
|
| + jsobj.AddProperty("type", "CPU");
|
| + jsobj.AddProperty("architecture", CPU::Id());
|
| + return true;
|
| +}
|
| +
|
| +
|
| +static RootMessageHandlerEntry root_handlers[] = {
|
| + { "_echo", HandleRootEcho },
|
| + { "cpu", HandleCpu },
|
| +};
|
| +
|
| +
|
| +static RootMessageHandler FindRootMessageHandler(const char* command) {
|
| + intptr_t num_message_handlers = sizeof(root_handlers) /
|
| + sizeof(root_handlers[0]);
|
| for (intptr_t i = 0; i < num_message_handlers; i++) {
|
| - const ServiceMessageHandlerEntry& entry = __message_handlers[i];
|
| + const RootMessageHandlerEntry& entry = root_handlers[i];
|
| if (!strcmp(command, entry.command)) {
|
| return entry.handler;
|
| }
|
| }
|
| - return HandleFallthrough;
|
| + return NULL;
|
| }
|
|
|
| } // namespace dart
|
|
|