Chromium Code Reviews| Index: runtime/vm/service.cc |
| =================================================================== |
| --- runtime/vm/service.cc (revision 31674) |
| +++ runtime/vm/service.cc (working copy) |
| @@ -18,115 +18,92 @@ |
| namespace dart { |
| -typedef void (*ServiceMessageHandler)(Isolate* isolate, JSONStream* stream); |
| +// A handler for a per-isolate request. These handlers must call |
| +// PostReply in order to respond to the request. |
| +typedef void (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream); |
|
Cutch
2014/01/09 23:03:23
Why not have the handler functions return true to
turnidge
2014/01/15 20:21:04
Done.
|
| -struct ServiceMessageHandlerEntry { |
| +struct IsolateMessageHandlerEntry { |
| const char* command; |
| - ServiceMessageHandler handler; |
| + IsolateMessageHandler handler; |
| }; |
| -static ServiceMessageHandler FindServiceMessageHandler(const char* command); |
| +static IsolateMessageHandler FindIsolateMessageHandler(const char* command); |
| +// A handler for a root (vm-global) request. These handlers do not |
| +// call PostReply. |
| +typedef void (*RootMessageHandler)(JSONStream* stream); |
| +struct RootMessageHandlerEntry { |
| + const char* command; |
| + RootMessageHandler handler; |
| +}; |
| + |
| +static RootMessageHandler FindRootMessageHandler(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); |
| } |
| -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); |
| +static void PostReply(JSONStream* js) { |
| + Dart_Port reply_port = js->reply_port(); |
| + ASSERT(reply_port != ILLEGAL_PORT); |
| + js->SetReplyPort(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->SetReplyPort(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()); |
| } |
| } |
| @@ -154,14 +131,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(); |
| @@ -183,59 +152,123 @@ |
| } |
| +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 { |
| + handler(isolate, &js); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| static void 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()); |
| + { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "IsolateName"); |
| + jsobj.AddProperty("id", static_cast<intptr_t>(isolate->main_port())); |
| + jsobj.AddProperty("name", isolate->name()); |
| + } |
| + PostReply(js); |
| } |
| static void HandleStackTrace(Isolate* isolate, JSONStream* js) { |
| - DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); |
| - JSONObject jsobj(js); |
| - jsobj.AddProperty("type", "StackTrace"); |
| - JSONArray jsarr(&jsobj, "members"); |
| - intptr_t n_frames = stack->Length(); |
| - String& function = String::Handle(); |
| - Script& script = Script::Handle(); |
| - for (int i = 0; i < n_frames; i++) { |
| - ActivationFrame* frame = stack->FrameAt(i); |
| - script ^= frame->SourceScript(); |
| - function ^= frame->function().UserVisibleName(); |
| - JSONObject jsobj(&jsarr); |
| - jsobj.AddProperty("name", function.ToCString()); |
| - jsobj.AddProperty("script", script); |
| - jsobj.AddProperty("line", frame->LineNumber()); |
| - jsobj.AddProperty("function", frame->function()); |
| - jsobj.AddProperty("code", frame->code()); |
| + { |
| + DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "StackTrace"); |
| + JSONArray jsarr(&jsobj, "members"); |
| + intptr_t n_frames = stack->Length(); |
| + String& function = String::Handle(); |
| + Script& script = Script::Handle(); |
| + for (int i = 0; i < n_frames; i++) { |
| + ActivationFrame* frame = stack->FrameAt(i); |
| + script ^= frame->SourceScript(); |
| + function ^= frame->function().UserVisibleName(); |
| + JSONObject jsobj(&jsarr); |
| + jsobj.AddProperty("name", function.ToCString()); |
| + jsobj.AddProperty("script", script); |
| + jsobj.AddProperty("line", frame->LineNumber()); |
| + jsobj.AddProperty("function", frame->function()); |
| + jsobj.AddProperty("code", frame->code()); |
| + } |
| } |
| + PostReply(js); |
| } |
| static void 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"); |
| + { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "Error"); |
| + jsobj.AddProperty("text", "Run with --print_object_histogram"); |
| + } |
| + PostReply(js); |
| return; |
| } |
| histogram->PrintToJSONStream(js); |
| + PostReply(js); |
| } |
| -static void HandleEcho(Isolate* isolate, JSONStream* js) { |
| - JSONObject jsobj(js); |
| - jsobj.AddProperty("type", "message"); |
| - PrintArgumentsAndOptions(jsobj, js); |
| +static void HandleIsolateEcho(Isolate* isolate, JSONStream* js) { |
| + { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "message"); |
| + PrintArgumentsAndOptions(jsobj, js); |
| + } |
| + PostReply(js); |
| } |
| // 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); \ |
| + PrintError(js, "Must specify collection object id: /%s/id", collection); \ |
| return; \ |
| } |
| @@ -299,19 +332,23 @@ |
| intptr_t id; |
| if (js->num_arguments() > 4) { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| return; |
| } |
| if (!GetIntegerId(js->GetArgument(3), &id)) { |
| PrintError(js, "Must specify collection object id: closures/id"); |
| + PostReply(js); |
| return; |
| } |
| Function& func = Function::Handle(); |
| func ^= cls.ClosureFunctionFromIndex(id); |
| if (func.IsNull()) { |
| PrintError(js, "Closure function %" Pd " not found", id); |
| + PostReply(js); |
| return; |
| } |
| func.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| @@ -320,19 +357,23 @@ |
| intptr_t id; |
| if (js->num_arguments() > 4) { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| return; |
| } |
| if (!GetIntegerId(js->GetArgument(3), &id)) { |
| PrintError(js, "Must specify collection object id: dispatchers/id"); |
| + PostReply(js); |
| return; |
| } |
| Function& func = Function::Handle(); |
| func ^= cls.InvocationDispatcherFunctionFromIndex(id); |
| if (func.IsNull()) { |
| PrintError(js, "Dispatcher %" Pd " not found", id); |
| + PostReply(js); |
| return; |
| } |
| func.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| @@ -341,19 +382,23 @@ |
| intptr_t id; |
| if (js->num_arguments() > 4) { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| return; |
| } |
| if (!GetIntegerId(js->GetArgument(3), &id)) { |
| PrintError(js, "Must specify collection object id: functions/id"); |
| + PostReply(js); |
| return; |
| } |
| Function& func = Function::Handle(); |
| func ^= cls.FunctionFromIndex(id); |
| if (func.IsNull()) { |
| PrintError(js, "Function %" Pd " not found", id); |
| + PostReply(js); |
| return; |
| } |
| func.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| @@ -362,19 +407,23 @@ |
| intptr_t id; |
| if (js->num_arguments() > 4) { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| return; |
| } |
| if (!GetIntegerId(js->GetArgument(3), &id)) { |
| PrintError(js, "Must specify collection object id: implicit_closures/id"); |
| + PostReply(js); |
| return; |
| } |
| Function& func = Function::Handle(); |
| func ^= cls.ImplicitClosureFunctionFromIndex(id); |
| if (func.IsNull()) { |
| PrintError(js, "Implicit closure function %" Pd " not found", id); |
| + PostReply(js); |
| return; |
| } |
| func.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| @@ -383,18 +432,22 @@ |
| intptr_t id; |
| if (js->num_arguments() > 4) { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| return; |
| } |
| if (!GetIntegerId(js->GetArgument(3), &id)) { |
| PrintError(js, "Must specify collection object id: fields/id"); |
| + PostReply(js); |
| return; |
| } |
| Field& field = Field::Handle(cls.FieldFromIndex(id)); |
| if (field.IsNull()) { |
| PrintError(js, "Field %" Pd " not found", id); |
| + PostReply(js); |
| return; |
| } |
| field.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| @@ -402,22 +455,26 @@ |
| if (js->num_arguments() == 1) { |
| ClassTable* table = isolate->class_table(); |
| table->PrintToJSONStream(js); |
| + PostReply(js); |
| return; |
| } |
| ASSERT(js->num_arguments() >= 2); |
| intptr_t id; |
| if (!GetIntegerId(js->GetArgument(1), &id)) { |
| PrintError(js, "Must specify collection object id: /classes/id"); |
| + PostReply(js); |
| return; |
| } |
| ClassTable* table = isolate->class_table(); |
| if (!table->IsValidIndex(id)) { |
| PrintError(js, "%" Pd " is not a valid class id.", id);; |
| + PostReply(js); |
| return; |
| } |
| Class& cls = Class::Handle(table->At(id)); |
| if (js->num_arguments() == 2) { |
| cls.PrintToJSONStream(js, false); |
| + PostReply(js); |
| return; |
| } else if (js->num_arguments() >= 3) { |
| const char* second = js->GetArgument(2); |
| @@ -433,6 +490,7 @@ |
| HandleClassesDispatchers(isolate, cls, js); |
| } else { |
| PrintError(js, "Invalid sub collection %s", second); |
| + PostReply(js); |
| } |
| return; |
| } |
| @@ -445,9 +503,11 @@ |
| const Library& lib = |
| Library::Handle(isolate->object_store()->root_library()); |
| lib.PrintToJSONStream(js, false); |
| + PostReply(js); |
| return; |
| } |
| - PrintGenericError(js); |
| + PrintError(js, "Command too long"); |
| + PostReply(js); |
| } |
| @@ -464,6 +524,7 @@ |
| lib ^= libs.At(id); |
| ASSERT(!lib.IsNull()); |
| lib.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| @@ -475,18 +536,20 @@ |
| intptr_t id = -1; |
| if (!GetIntegerId(js->GetArgument(1), &id)) { |
| Object::null_object().PrintToJSONStream(js, false); |
| + PostReply(js); |
| return; |
| } |
| Object& obj = Object::Handle(ring->GetObjectForId(id)); |
| obj.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| static void HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { |
| - JSONObject jsobj(js); |
| - jsobj.AddProperty("type", "ScriptList"); |
| { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "ScriptList"); |
| JSONArray members(&jsobj, "members"); |
| const GrowableObjectArray& libs = |
| GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| @@ -506,6 +569,7 @@ |
| } |
| } |
| } |
| + PostReply(js); |
| } |
| @@ -533,11 +597,13 @@ |
| url ^= script.url(); |
| if (url.Equals(requested_url)) { |
| script.PrintToJSONStream(js, false); |
| + PostReply(js); |
| return; |
| } |
| } |
| } |
| PrintError(js, "Cannot find script %s\n", requested_url.ToCString()); |
| + PostReply(js); |
| } |
| @@ -550,6 +616,7 @@ |
| HandleScriptsFetch(isolate, js); |
| } else { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| } |
| } |
| @@ -557,17 +624,21 @@ |
| static void HandleDebug(Isolate* isolate, JSONStream* js) { |
| if (js->num_arguments() == 1) { |
| PrintError(js, "Must specify a subcommand"); |
| + PostReply(js); |
| return; |
| } |
| const char* command = js->GetArgument(1); |
| if (!strcmp(command, "breakpoints")) { |
| if (js->num_arguments() == 2) { |
| // Print breakpoint list. |
| - JSONObject jsobj(js); |
| - jsobj.AddProperty("type", "BreakpointList"); |
| - JSONArray jsarr(&jsobj, "breakpoints"); |
| - isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); |
| - |
| + { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "BreakpointList"); |
| + JSONArray jsarr(&jsobj, "breakpoints"); |
| + isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); |
| + } |
| + PostReply(js); |
| + return; |
| } else if (js->num_arguments() == 3) { |
| // Print individual breakpoint. |
| intptr_t id = 0; |
| @@ -577,52 +648,55 @@ |
| } |
| if (bpt != NULL) { |
| bpt->PrintToJSONStream(js); |
| + PostReply(js); |
| + return; |
| } else { |
| PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2)); |
| + PostReply(js); |
| + return; |
| } |
| - |
| } else { |
| PrintError(js, "Command too long"); |
| + PostReply(js); |
| + return; |
| } |
| } else { |
| PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1)); |
| + PostReply(js); |
| + return; |
| } |
| } |
| -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) { |
| REQUIRE_COLLECTION_ID("code"); |
| uintptr_t pc; |
| if (!GetUnsignedIntegerId(js->GetArgument(1), &pc, 16)) { |
| PrintError(js, "Must specify code address: code/c0deadd0."); |
| + PostReply(js); |
| return; |
| } |
| Code& code = Code::Handle(Code::LookupCode(pc)); |
| if (code.IsNull()) { |
| PrintError(js, "Could not find code at %" Px "", pc); |
| + PostReply(js); |
| return; |
| } |
| code.PrintToJSONStream(js, false); |
| + PostReply(js); |
| } |
| static void HandleProfile(Isolate* isolate, JSONStream* js) { |
| Profiler::PrintToJSONStream(isolate, js, true); |
| + PostReply(js); |
| } |
| -static ServiceMessageHandlerEntry __message_handlers[] = { |
| - { "_echo", HandleEcho }, |
| +static IsolateMessageHandlerEntry isolate_handlers[] = { |
| + { "_echo", HandleIsolateEcho }, |
| { "classes", HandleClasses }, |
| { "code", HandleCode }, |
| - { "cpu", HandleCpu }, |
| { "debug", HandleDebug }, |
| { "libraries", HandleLibraries }, |
| { "library", HandleLibrary }, |
| @@ -635,24 +709,106 @@ |
| }; |
| -static void HandleFallthrough(Isolate* isolate, JSONStream* js) { |
| - JSONObject jsobj(js); |
| - jsobj.AddProperty("type", "Error"); |
| - jsobj.AddProperty("text", "request not understood."); |
| - PrintArgumentsAndOptions(jsobj, 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; |
| } |
| -static ServiceMessageHandler FindServiceMessageHandler(const char* command) { |
| - intptr_t num_message_handlers = sizeof(__message_handlers) / |
| - sizeof(__message_handlers[0]); |
| +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 { |
| + handler(&js); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| +static void HandleRootEcho(JSONStream* js) { |
| + { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "message"); |
| + PrintArgumentsAndOptions(jsobj, js); |
| + } |
| + PostReply(js); |
| +} |
| + |
| + |
| +static void HandleCpu(JSONStream* js) { |
| + { |
| + JSONObject jsobj(js); |
| + jsobj.AddProperty("type", "CPU"); |
| + jsobj.AddProperty("architecture", CPU::Id()); |
| + } |
| + PostReply(js); |
| +} |
| + |
| + |
| +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 |