Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1710)

Unified Diff: runtime/vm/service.cc

Issue 131973007: Allow root level requests in the vm service. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698