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

Unified Diff: runtime/vm/service.cc

Issue 823403004: Begin migrating the vm service from a rest-style interface to a json-rpc style interface. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: remove old-style standalone tests. Created 5 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
« no previous file with comments | « runtime/vm/service.h ('k') | runtime/vm/service/message.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/service.cc
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index dc6835dc6d8823a32b3f85df536dbba688ac256c..c2a98074d645b9f52d85ef489559464b764ea36b 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -824,6 +824,7 @@ struct IsolateMessageHandlerEntry {
};
static IsolateMessageHandler FindIsolateMessageHandler(const char* command);
+static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command);
// A handler for a root (vm-global) request.
@@ -882,7 +883,6 @@ static void PrintError(JSONStream* js,
JSONObject jsobj(js);
jsobj.AddProperty("type", "Error");
- jsobj.AddProperty("id", "");
jsobj.AddProperty("message", buffer);
PrintArgumentsAndOptions(jsobj, js);
}
@@ -913,6 +913,60 @@ static void PrintErrorWithKind(JSONStream* js,
}
+void Service::HandleIsolateMessageNew(Isolate* isolate, const Array& msg) {
+ ASSERT(isolate != NULL);
+ ASSERT(!msg.IsNull());
+
+ {
+ StackZone zone(isolate);
+ HANDLESCOPE(isolate);
+
+ Instance& reply_port = Instance::Handle(isolate);
+ String& method = String::Handle(isolate);
+ Array& param_keys = Array::Handle(isolate);
+ Array& param_values = Array::Handle(isolate);
+ reply_port ^= msg.At(1);
+ method ^= msg.At(2);
+ param_keys ^= msg.At(3);
+ param_values ^= msg.At(4);
+
+ ASSERT(!method.IsNull());
+ ASSERT(!param_keys.IsNull());
+ ASSERT(!param_values.IsNull());
+ ASSERT(param_keys.Length() == param_values.Length());
+
+ if (!reply_port.IsSendPort()) {
+ FATAL("SendPort expected.");
+ }
+
+ IsolateMessageHandler handler =
+ FindIsolateMessageHandlerNew(method.ToCString());
+ {
+ JSONStream js;
+ js.SetupNew(zone.GetZone(), SendPort::Cast(reply_port).Id(),
+ method, param_keys, param_values);
+ if (handler == NULL) {
+ // Check for an embedder handler.
+ EmbedderServiceHandler* e_handler =
+ FindIsolateEmbedderHandler(method.ToCString());
+ if (e_handler != NULL) {
+ EmbedderHandleMessage(e_handler, &js);
+ } else {
+ PrintError(&js, "Unrecognized method: %s", method.ToCString());
+ }
+ js.PostReply();
+ } else {
+ if (handler(isolate, &js)) {
+ // Handler returns true if the reply is ready to be posted.
+ // TODO(johnmccutchan): Support asynchronous replies.
+ js.PostReply();
+ }
+ }
+ }
+ }
+}
+
+
void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
ASSERT(isolate != NULL);
ASSERT(!msg.IsNull());
@@ -924,6 +978,12 @@ void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
// Message is a list with five entries.
ASSERT(msg.Length() == 5);
+ Object& tmp = Object::Handle(isolate);
+ tmp = msg.At(2);
+ if (tmp.IsString()) {
+ return Service::HandleIsolateMessageNew(isolate, msg);
+ }
+
Instance& reply_port = Instance::Handle(isolate);
GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
Array& option_keys = Array::Handle(isolate);
@@ -986,16 +1046,11 @@ static bool HandleIsolate(Isolate* isolate, JSONStream* js) {
}
-static bool HandleStackTrace(Isolate* isolate, JSONStream* js) {
- if (js->num_arguments() > 1) {
- PrintError(js, "Command too long");
- return true;
- }
+static bool HandleIsolateGetStack(Isolate* isolate, JSONStream* js) {
DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
JSONObject jsobj(js);
- jsobj.AddProperty("type", "StackTrace");
- jsobj.AddProperty("id", "stacktrace");
- JSONArray jsarr(&jsobj, "members");
+ jsobj.AddProperty("type", "Stack");
+ JSONArray jsarr(&jsobj, "frames");
intptr_t num_frames = stack->Length();
for (intptr_t i = 0; i < num_frames; i++) {
ActivationFrame* frame = stack->FrameAt(i);
@@ -1195,16 +1250,309 @@ static bool ContainsNonInstance(const Object& obj) {
}
-static bool HandleInboundReferences(Isolate* isolate,
- Object* target,
- intptr_t limit,
- JSONStream* js) {
+static RawObject* LookupObjectId(Isolate* isolate,
+ const char* arg,
+ ObjectIdRing::LookupResult* kind) {
+ *kind = ObjectIdRing::kValid;
+ if (strncmp(arg, "int-", 4) == 0) {
+ arg += 4;
+ int64_t value = 0;
+ if (!OS::StringToInt64(arg, &value) ||
+ !Smi::IsValid(value)) {
+ *kind = ObjectIdRing::kInvalid;
+ return Object::null();
+ }
+ const Integer& obj =
+ Integer::Handle(isolate, Smi::New(static_cast<intptr_t>(value)));
+ return obj.raw();
+ } else if (strcmp(arg, "bool-true") == 0) {
+ return Bool::True().raw();
+ } else if (strcmp(arg, "bool-false") == 0) {
+ return Bool::False().raw();
+ } else if (strcmp(arg, "null") == 0) {
+ return Object::null();
+ } else if (strcmp(arg, "not-initialized") == 0) {
+ return Object::sentinel().raw();
+ } else if (strcmp(arg, "being-initialized") == 0) {
+ return Object::transition_sentinel().raw();
+ }
+
+ ObjectIdRing* ring = isolate->object_id_ring();
+ ASSERT(ring != NULL);
+ intptr_t id = -1;
+ if (!GetIntegerId(arg, &id)) {
+ *kind = ObjectIdRing::kInvalid;
+ return Object::null();
+ }
+ return ring->GetObjectForId(id, kind);
+}
+
+
+static RawObject* LookupHeapObjectLibraries(Isolate* isolate,
+ char** parts, int num_parts) {
+ // Library ids look like "libraries/35"
+ if (num_parts < 2) {
+ return Object::sentinel().raw();
+ }
+ const GrowableObjectArray& libs =
+ GrowableObjectArray::Handle(isolate->object_store()->libraries());
+ ASSERT(!libs.IsNull());
+ intptr_t id = 0;
+ if (!GetIntegerId(parts[1], &id)) {
+ return Object::sentinel().raw();
+ }
+ if ((id < 0) || (id >= libs.Length())) {
+ return Object::sentinel().raw();
+ }
+ Library& lib = Library::Handle();
+ lib ^= libs.At(id);
+ ASSERT(!lib.IsNull());
+ if (num_parts == 2) {
+ return lib.raw();
+ }
+ if (strcmp(parts[2], "scripts") == 0) {
+ // Script ids look like "libraries/35/scripts/library%2Furl.dart"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ const String& id = String::Handle(String::New(parts[3]));
+ ASSERT(!id.IsNull());
+ // The id is the url of the script % encoded, decode it.
+ const String& requested_url = String::Handle(String::DecodeIRI(id));
+ Script& script = Script::Handle();
+ String& script_url = String::Handle();
+ const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
+ ASSERT(!loaded_scripts.IsNull());
+ intptr_t i;
+ for (i = 0; i < loaded_scripts.Length(); i++) {
+ script ^= loaded_scripts.At(i);
+ ASSERT(!script.IsNull());
+ script_url ^= script.url();
+ if (script_url.Equals(requested_url)) {
+ return script.raw();
+ }
+ }
+ }
+
+ // Not found.
+ return Object::sentinel().raw();
+}
+
+static RawObject* LookupHeapObjectClasses(Isolate* isolate,
+ char** parts, int num_parts) {
+ // Class ids look like: "classes/17"
+ if (num_parts < 2) {
+ return Object::sentinel().raw();
+ }
+ ClassTable* table = isolate->class_table();
+ intptr_t id;
+ if (!GetIntegerId(parts[1], &id) ||
+ !table->IsValidIndex(id)) {
+ return Object::sentinel().raw();
+ }
+ Class& cls = Class::Handle(table->At(id));
+ if (num_parts == 2) {
+ return cls.raw();
+ }
+ if (strcmp(parts[2], "closures") == 0) {
+ // Closure ids look like: "classes/17/closures/11"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ intptr_t id;
+ if (!GetIntegerId(parts[3], &id)) {
+ return Object::sentinel().raw();
+ }
+ Function& func = Function::Handle();
+ func ^= cls.ClosureFunctionFromIndex(id);
+ if (func.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ return func.raw();
+
+ } else if (strcmp(parts[2], "fields") == 0) {
+ // Field ids look like: "classes/17/fields/11"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ intptr_t id;
+ if (!GetIntegerId(parts[3], &id)) {
+ return Object::sentinel().raw();
+ }
+ Field& field = Field::Handle(cls.FieldFromIndex(id));
+ if (field.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ return field.raw();
+
+ } else if (strcmp(parts[2], "functions") == 0) {
+ // Function ids look like: "classes/17/functions/11"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ const char* encoded_id = parts[3];
+ String& id = String::Handle(isolate, String::New(encoded_id));
+ id = String::DecodeIRI(id);
+ if (id.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ Function& func = Function::Handle(cls.LookupFunction(id));
+ if (func.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ return func.raw();
+
+ } else if (strcmp(parts[2], "implicit_closures") == 0) {
+ // Function ids look like: "classes/17/implicit_closures/11"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ intptr_t id;
+ if (!GetIntegerId(parts[3], &id)) {
+ return Object::sentinel().raw();
+ }
+ Function& func = Function::Handle();
+ func ^= cls.ImplicitClosureFunctionFromIndex(id);
+ if (func.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ return func.raw();
+
+ } else if (strcmp(parts[2], "dispatchers") == 0) {
+ // Dispatcher Function ids look like: "classes/17/dispatchers/11"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ intptr_t id;
+ if (!GetIntegerId(parts[3], &id)) {
+ return Object::sentinel().raw();
+ }
+ Function& func = Function::Handle();
+ func ^= cls.InvocationDispatcherFunctionFromIndex(id);
+ if (func.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ return func.raw();
+
+ } else if (strcmp(parts[2], "types") == 0) {
+ // Type ids look like: "classes/17/types/11"
+ if (num_parts != 4) {
+ return Object::sentinel().raw();
+ }
+ intptr_t id;
+ if (!GetIntegerId(parts[3], &id)) {
+ return Object::sentinel().raw();
+ }
+ Type& type = Type::Handle();
+ type ^= cls.CanonicalTypeFromIndex(id);
+ if (type.IsNull()) {
+ return Object::sentinel().raw();
+ }
+ return type.raw();
+ }
+
+ // Not found.
+ return Object::sentinel().raw();
+}
+
+
+static RawObject* LookupHeapObject(Isolate* isolate,
+ const char* id_original,
+ ObjectIdRing::LookupResult* result) {
+ char* id = isolate->current_zone()->MakeCopyOfString(id_original);
+
+ // Parse the id by splitting at each '/'.
+ const int MAX_PARTS = 8;
+ char* parts[MAX_PARTS];
+ int num_parts = 0;
+ int i = 0;
+ int start_pos = 0;
+ while (id[i] != '\0') {
+ if (id[i] == '/') {
+ id[i++] = '\0';
+ parts[num_parts++] = &id[start_pos];
+ if (num_parts == MAX_PARTS) {
+ break;
+ }
+ start_pos = i;
+ } else {
+ i++;
+ }
+ }
+ if (num_parts < MAX_PARTS) {
+ parts[num_parts++] = &id[start_pos];
+ }
+
+ if (result != NULL) {
+ *result = ObjectIdRing::kValid;
+ }
+
+ if (strcmp(parts[0], "objects") == 0) {
+ // Object ids look like "objects/1123"
+ Object& obj = Object::Handle(isolate);
+ ObjectIdRing::LookupResult lookup_result;
+ obj = LookupObjectId(isolate, parts[1], &lookup_result);
+ if (lookup_result != ObjectIdRing::kValid) {
+ if (result != NULL) {
+ *result = lookup_result;
+ }
+ return Object::sentinel().raw();
+ }
+ return obj.raw();
+
+ } else if (strcmp(parts[0], "libraries") == 0) {
+ return LookupHeapObjectLibraries(isolate, parts, num_parts);
+ } else if (strcmp(parts[0], "classes") == 0) {
+ return LookupHeapObjectClasses(isolate, parts, num_parts);
+ }
+
+ // Not found.
+ return Object::sentinel().raw();
+}
+
+
+static void PrintSentinel(JSONStream* js,
+ const char* id,
+ const char* preview) {
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "Sentinel");
+ jsobj.AddProperty("id", id);
+ jsobj.AddProperty("valueAsString", preview);
+}
+
+
+static SourceBreakpoint* LookupBreakpoint(Isolate* isolate, const char* id) {
+ size_t end_pos = strcspn(id, "/");
+ const char* rest = NULL;
+ if (end_pos < strlen(id)) {
+ rest = id + end_pos + 1; // +1 for '/'.
+ }
+ if (strncmp("breakpoints", id, end_pos) == 0) {
+ if (rest == NULL) {
+ return NULL;
+ }
+ intptr_t bpt_id = 0;
+ SourceBreakpoint* bpt = NULL;
+ if (GetIntegerId(rest, &bpt_id)) {
+ bpt = isolate->debugger()->GetBreakpointById(bpt_id);
+ }
+ return bpt;
+ }
+ return NULL;
+}
+
+
+
+
+static bool PrintInboundReferences(Isolate* isolate,
+ Object* target,
+ intptr_t limit,
+ JSONStream* js) {
ObjectGraph graph(isolate);
Array& path = Array::Handle(Array::New(limit * 2));
intptr_t length = graph.InboundReferences(target, path);
JSONObject jsobj(js);
jsobj.AddProperty("type", "InboundReferences");
- jsobj.AddProperty("id", "inbound_references");
{
JSONArray elements(&jsobj, "references");
Object& source = Object::Handle();
@@ -1244,16 +1592,61 @@ static bool HandleInboundReferences(Isolate* isolate,
}
-static bool HandleRetainingPath(Isolate* isolate,
- Object* obj,
- intptr_t limit,
- JSONStream* js) {
+static bool HandleIsolateGetInboundReferences(Isolate* isolate,
+ JSONStream* js) {
+ const char* target_id = js->LookupOption("targetId");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'targetId' option");
+ return true;
+ }
+ const char* limit_cstr = js->LookupOption("limit");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'limit' option");
+ return true;
+ }
+ intptr_t limit;
+ if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
+ PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+ return true;
+ }
+
+ Object& obj = Object::Handle(isolate);
+ ObjectIdRing::LookupResult lookup_result;
+ {
+ HANDLESCOPE(isolate);
+ obj = LookupHeapObject(isolate, target_id, &lookup_result);
+ }
+ if (obj.raw() == Object::sentinel().raw()) {
+ if (lookup_result == ObjectIdRing::kCollected) {
+ PrintErrorWithKind(
+ js, "InboundReferencesCollected",
+ "attempt to find a retaining path for a collected object\n",
+ js->num_arguments());
+ return true;
+ } else if (lookup_result == ObjectIdRing::kExpired) {
+ PrintErrorWithKind(
+ js, "InboundReferencesExpired",
+ "attempt to find a retaining path for an expired object\n",
+ js->num_arguments());
+ return true;
+ }
+ PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
+ target_id);
+ return true;
+ }
+ return PrintInboundReferences(isolate, &obj, limit, js);
+}
+
+
+static bool PrintRetainingPath(Isolate* isolate,
+ Object* obj,
+ intptr_t limit,
+ JSONStream* js) {
ObjectGraph graph(isolate);
Array& path = Array::Handle(Array::New(limit * 2));
intptr_t length = graph.RetainingPath(obj, path);
JSONObject jsobj(js);
jsobj.AddProperty("type", "RetainingPath");
- jsobj.AddProperty("id", "retaining_path");
jsobj.AddProperty("length", length);
JSONArray elements(&jsobj, "elements");
Object& element = Object::Handle();
@@ -1291,7 +1684,7 @@ static bool HandleRetainingPath(Isolate* isolate,
}
// We nil out the array after generating the response to prevent
- // reporting suprious references when looking for inbound references
+ // reporting spurious references when looking for inbound references
// after looking for a retaining path.
for (intptr_t i = 0; i < limit; ++i) {
path.SetAt(i * 2, Object::null_object());
@@ -1300,122 +1693,97 @@ static bool HandleRetainingPath(Isolate* isolate,
return true;
}
-
-// Takes an Object* only because RetainingPath temporarily clears it.
-static bool HandleInstanceCommands(Isolate* isolate,
- Object* obj,
- ObjectIdRing::LookupResult kind,
- JSONStream* js,
- intptr_t arg_pos) {
- ASSERT(js->num_arguments() > arg_pos);
- ASSERT(kind != ObjectIdRing::kInvalid);
- const char* action = js->GetArgument(arg_pos);
- if (strcmp(action, "eval") == 0) {
- if (js->num_arguments() > (arg_pos + 1)) {
- PrintError(js, "expected at most %" Pd " arguments but found %" Pd "\n",
- arg_pos + 1,
- js->num_arguments());
- return true;
- }
- if (kind == ObjectIdRing::kCollected) {
- PrintErrorWithKind(js, "EvalCollected",
- "attempt to evaluate against collected object\n",
- js->num_arguments());
- return true;
- }
- if (kind == ObjectIdRing::kExpired) {
- PrintErrorWithKind(js, "EvalExpired",
- "attempt to evaluate against expired object\n",
- js->num_arguments());
- return true;
- }
- if (ContainsNonInstance(*obj)) {
- PrintError(js, "attempt to evaluate against internal VM object\n");
- return true;
- }
- const char* expr = js->LookupOption("expr");
- if (expr == NULL) {
- PrintError(js, "eval expects an 'expr' option\n",
- js->num_arguments());
- return true;
- }
- const String& expr_str = String::Handle(isolate, String::New(expr));
- ASSERT(obj->IsInstance() || obj->IsNull());
- Instance& instance = Instance::Handle();
- instance ^= obj->raw();
- const Object& result =
- Object::Handle(instance.Evaluate(expr_str,
- Array::empty_array(),
- Array::empty_array()));
- result.PrintJSON(js, true);
+static bool HandleIsolateGetRetainingPath(Isolate* isolate,
+ JSONStream* js) {
+ const char* target_id = js->LookupOption("targetId");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'targetId' option");
return true;
- } else if (strcmp(action, "retained") == 0) {
- if (kind == ObjectIdRing::kCollected) {
- PrintErrorWithKind(
- js, "RetainedCollected",
- "attempt to calculate size retained by a collected object\n",
- js->num_arguments());
- return true;
- }
- if (kind == ObjectIdRing::kExpired) {
- PrintErrorWithKind(
- js, "RetainedExpired",
- "attempt to calculate size retained by an expired object\n",
- js->num_arguments());
- return true;
- }
- ObjectGraph graph(isolate);
- intptr_t retained_size = graph.SizeRetainedByInstance(*obj);
- const Object& result = Object::Handle(Integer::New(retained_size));
- result.PrintJSON(js, true);
+ }
+ const char* limit_cstr = js->LookupOption("limit");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'limit' option");
return true;
- } else if (strcmp(action, "retaining_path") == 0) {
- if (kind == ObjectIdRing::kCollected) {
+ }
+ intptr_t limit;
+ if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
+ PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+ return true;
+ }
+
+ Object& obj = Object::Handle(isolate);
+ ObjectIdRing::LookupResult lookup_result;
+ {
+ HANDLESCOPE(isolate);
+ obj = LookupHeapObject(isolate, target_id, &lookup_result);
+ }
+ if (obj.raw() == Object::sentinel().raw()) {
+ if (lookup_result == ObjectIdRing::kCollected) {
PrintErrorWithKind(
js, "RetainingPathCollected",
"attempt to find a retaining path for a collected object\n",
js->num_arguments());
return true;
- }
- if (kind == ObjectIdRing::kExpired) {
+ } else if (lookup_result == ObjectIdRing::kExpired) {
PrintErrorWithKind(
js, "RetainingPathExpired",
"attempt to find a retaining path for an expired object\n",
js->num_arguments());
return true;
}
- intptr_t limit;
- if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
- PrintError(js, "retaining_path expects a 'limit' option\n",
- js->num_arguments());
- return true;
- }
- return HandleRetainingPath(isolate, obj, limit, js);
- } else if (strcmp(action, "inbound_references") == 0) {
- if (kind == ObjectIdRing::kCollected) {
+ PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
+ target_id);
+ return true;
+ }
+ return PrintRetainingPath(isolate, &obj, limit, js);
+}
+
+
+static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) {
+ const char* target_id = js->LookupOption("targetId");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'targetId' option");
+ return true;
+ }
+ ObjectIdRing::LookupResult lookup_result;
+ Object& obj = Object::Handle(LookupHeapObject(isolate, target_id,
+ &lookup_result));
+ if (obj.raw() == Object::sentinel().raw()) {
+ if (lookup_result == ObjectIdRing::kCollected) {
PrintErrorWithKind(
- js, "InboundReferencesCollected",
- "attempt to find inbound references for a collected object\n",
+ js, "RetainedCollected",
+ "attempt to calculate size retained by a collected object\n",
js->num_arguments());
return true;
- }
- if (kind == ObjectIdRing::kExpired) {
+ } else if (lookup_result == ObjectIdRing::kExpired) {
PrintErrorWithKind(
- js, "InboundReferencesExpired",
- "attempt to find inbound references for an expired object\n",
+ js, "RetainedExpired",
+ "attempt to calculate size retained by an expired object\n",
js->num_arguments());
return true;
}
- intptr_t limit;
- if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
- PrintError(js, "inbound_references expects a 'limit' option\n",
- js->num_arguments());
- return true;
- }
- return HandleInboundReferences(isolate, obj, limit, js);
+ PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
+ target_id);
+ return true;
}
-
- PrintError(js, "unrecognized action '%s'\n", action);
+ if (obj.IsClass()) {
+ const Class& cls = Class::Cast(obj);
+ ObjectGraph graph(isolate);
+ intptr_t retained_size = graph.SizeRetainedByClass(cls.id());
+ const Object& result = Object::Handle(Integer::New(retained_size));
+ result.PrintJSON(js, true);
+ return true;
+ }
+ if (obj.IsInstance() || obj.IsNull()) {
+ // We don't use Instance::Cast here because it doesn't allow null.
+ ObjectGraph graph(isolate);
+ intptr_t retained_size = graph.SizeRetainedByInstance(obj);
+ const Object& result = Object::Handle(Integer::New(retained_size));
+ result.PrintJSON(js, true);
+ return true;
+ }
+ PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
+ "library, class, or instance", target_id);
return true;
}
@@ -1442,23 +1810,62 @@ static bool HandleClassesClosures(Isolate* isolate, const Class& cls,
}
-static bool HandleClassesEval(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- if (js->num_arguments() > 3) {
- PrintError(js, "Command too long");
+static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) {
+ const char* target_id = js->LookupOption("targetId");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'targetId' option");
return true;
}
- const char* expr = js->LookupOption("expr");
+ const char* expr = js->LookupOption("expression");
if (expr == NULL) {
- PrintError(js, "eval expects an 'expr' option\n",
- js->num_arguments());
+ PrintError(js, "Missing 'expression' option");
return true;
}
const String& expr_str = String::Handle(isolate, String::New(expr));
- const Object& result = Object::Handle(cls.Evaluate(expr_str,
- Array::empty_array(),
- Array::empty_array()));
- result.PrintJSON(js, true);
+ ObjectIdRing::LookupResult lookup_result;
+ Object& obj = Object::Handle(LookupHeapObject(isolate, target_id,
+ &lookup_result));
+ if (obj.raw() == Object::sentinel().raw()) {
+ if (lookup_result == ObjectIdRing::kCollected) {
+ PrintSentinel(js, "objects/collected", "<collected>");
+ } else if (lookup_result == ObjectIdRing::kExpired) {
+ PrintSentinel(js, "objects/expired", "<expired>");
+ } else {
+ PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
+ target_id);
+ }
+ return true;
+ }
+ if (obj.IsLibrary()) {
+ const Library& lib = Library::Cast(obj);
+ const Object& result = Object::Handle(lib.Evaluate(expr_str,
+ Array::empty_array(),
+ Array::empty_array()));
+ result.PrintJSON(js, true);
+ return true;
+ }
+ if (obj.IsClass()) {
+ const Class& cls = Class::Cast(obj);
+ const Object& result = Object::Handle(cls.Evaluate(expr_str,
+ Array::empty_array(),
+ Array::empty_array()));
+ result.PrintJSON(js, true);
+ return true;
+ }
+ if ((obj.IsInstance() || obj.IsNull()) &&
+ !ContainsNonInstance(obj)) {
+ // We don't use Instance::Cast here because it doesn't allow null.
+ Instance& instance = Instance::Handle(isolate);
+ instance ^= obj.raw();
+ const Object& result =
+ Object::Handle(instance.Evaluate(expr_str,
+ Array::empty_array(),
+ Array::empty_array()));
+ result.PrintJSON(js, true);
+ return true;
+ }
+ PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
+ "library, class, or instance", target_id);
return true;
}
@@ -1485,14 +1892,6 @@ static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls,
}
-static bool HandleClassesFunctionsCoverage(
- Isolate* isolate, const Function& func, JSONStream* js) {
- FunctionCoverageFilter filter(func);
- CodeCoverage::PrintJSON(isolate, js, &filter);
- return true;
-}
-
-
static bool HandleFunctionSetSource(
Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) {
if (js->LookupOption("source") == NULL) {
@@ -1546,9 +1945,7 @@ static bool HandleClassesFunctions(Isolate* isolate, const Class& cls,
return true;
} else {
const char* subcommand = js->GetArgument(4);
- if (strcmp(subcommand, "coverage") == 0) {
- return HandleClassesFunctionsCoverage(isolate, func, js);
- } else if (strcmp(subcommand, "set_source") == 0) {
+ if (strcmp(subcommand, "set_source") == 0) {
return HandleFunctionSetSource(isolate, cls, func, js);
} else {
PrintError(js, "Invalid sub command %s", subcommand);
@@ -1617,7 +2014,11 @@ static bool HandleClassesTypes(Isolate* isolate, const Class& cls,
}
return true;
}
- ASSERT(js->num_arguments() >= 4);
+ if (js->num_arguments() > 4) {
+ PrintError(js, "Command too long");
+ return true;
+ }
+ ASSERT(js->num_arguments() == 4);
intptr_t id;
if (!GetIntegerId(js->GetArgument(3), &id)) {
PrintError(js, "Must specify collection object id: types/id");
@@ -1629,24 +2030,7 @@ static bool HandleClassesTypes(Isolate* isolate, const Class& cls,
PrintError(js, "Canonical type %" Pd " not found", id);
return true;
}
- if (js->num_arguments() == 4) {
- type.PrintJSON(js, false);
- return true;
- }
- return HandleInstanceCommands(isolate, &type, ObjectIdRing::kValid, js, 4);
-}
-
-
-static bool HandleClassesRetained(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- if (js->num_arguments() != 3) {
- PrintError(js, "Command too long");
- return true;
- }
- ObjectGraph graph(isolate);
- intptr_t retained_size = graph.SizeRetainedByClass(cls.id());
- const Object& result = Object::Handle(Integer::New(retained_size));
- result.PrintJSON(js, true);
+ type.PrintJSON(js, false);
return true;
}
@@ -1683,18 +2067,30 @@ class GetInstancesVisitor : public ObjectGraph::Visitor {
};
-static bool HandleClassesInstances(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- if (js->num_arguments() != 3) {
- PrintError(js, "Command too long");
+static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) {
+ const char* target_id = js->LookupOption("classId");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'classId' option");
+ return true;
+ }
+ const char* limit_cstr = js->LookupOption("limit");
+ if (target_id == NULL) {
+ PrintError(js, "Missing 'limit' option");
return true;
}
intptr_t limit;
if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
- PrintError(js, "instances expects a 'limit' option\n",
- js->num_arguments());
+ PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+ return true;
+ }
+ const Object& obj =
+ Object::Handle(LookupHeapObject(isolate, target_id, NULL));
+ if (obj.raw() == Object::sentinel().raw() ||
+ !obj.IsClass()) {
+ PrintError(js, "Invalid 'classId' value: no class with id '%s'", target_id);
return true;
}
+ const Class& cls = Class::Cast(obj);
Array& storage = Array::Handle(Array::New(limit));
GetInstancesVisitor visitor(cls, storage);
ObjectGraph graph(isolate);
@@ -1717,15 +2113,6 @@ static bool HandleClassesInstances(Isolate* isolate, const Class& cls,
}
-static bool HandleClassesCoverage(Isolate* isolate,
- const Class& cls,
- JSONStream* stream) {
- ClassCoverageFilter cf(cls);
- CodeCoverage::PrintJSON(isolate, stream, &cf);
- return true;
-}
-
-
static bool HandleClasses(Isolate* isolate, JSONStream* js) {
if (js->num_arguments() == 1) {
ClassTable* table = isolate->class_table();
@@ -1750,9 +2137,7 @@ static bool HandleClasses(Isolate* isolate, JSONStream* js) {
return true;
} else if (js->num_arguments() >= 3) {
const char* second = js->GetArgument(2);
- if (strcmp(second, "eval") == 0) {
- return HandleClassesEval(isolate, cls, js);
- } else if (strcmp(second, "closures") == 0) {
+ if (strcmp(second, "closures") == 0) {
return HandleClassesClosures(isolate, cls, js);
} else if (strcmp(second, "fields") == 0) {
return HandleClassesFields(isolate, cls, js);
@@ -1764,12 +2149,6 @@ static bool HandleClasses(Isolate* isolate, JSONStream* js) {
return HandleClassesDispatchers(isolate, cls, js);
} else if (strcmp(second, "types") == 0) {
return HandleClassesTypes(isolate, cls, js);
- } else if (strcmp(second, "retained") == 0) {
- return HandleClassesRetained(isolate, cls, js);
- } else if (strcmp(second, "instances") == 0) {
- return HandleClassesInstances(isolate, cls, js);
- } else if (strcmp(second, "coverage") == 0) {
- return HandleClassesCoverage(isolate, cls, js);
} else {
PrintError(js, "Invalid sub collection %s", second);
return true;
@@ -1780,37 +2159,45 @@ static bool HandleClasses(Isolate* isolate, JSONStream* js) {
}
-static bool HandleLibrariesEval(Isolate* isolate, const Library& lib,
- JSONStream* js) {
- if (js->num_arguments() > 3) {
- PrintError(js, "Command too long");
+static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
+ if (!js->HasOption("targetId")) {
+ CodeCoverage::PrintJSON(isolate, js, NULL);
return true;
}
- const char* expr = js->LookupOption("expr");
- if (expr == NULL) {
- PrintError(js, "eval expects an 'expr' option\n",
- js->num_arguments());
+ const char* target_id = js->LookupOption("targetId");
+ Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL));
+ if (obj.raw() == Object::sentinel().raw()) {
+ PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
+ target_id);
return true;
}
- const String& expr_str = String::Handle(isolate, String::New(expr));
- const Object& result = Object::Handle(lib.Evaluate(expr_str,
- Array::empty_array(),
- Array::empty_array()));
- result.PrintJSON(js, true);
- return true;
-}
-
-
-static bool HandleLibrariesScriptsCoverage(
- Isolate* isolate, const Script& script, JSONStream* js) {
- ScriptCoverageFilter sf(script);
- CodeCoverage::PrintJSON(isolate, js, &sf);
+ if (obj.IsScript()) {
+ ScriptCoverageFilter sf(Script::Cast(obj));
+ CodeCoverage::PrintJSON(isolate, js, &sf);
+ return true;
+ }
+ if (obj.IsLibrary()) {
+ LibraryCoverageFilter lf(Library::Cast(obj));
+ CodeCoverage::PrintJSON(isolate, js, &lf);
+ return true;
+ }
+ if (obj.IsClass()) {
+ ClassCoverageFilter cf(Class::Cast(obj));
+ CodeCoverage::PrintJSON(isolate, js, &cf);
+ return true;
+ }
+ if (obj.IsFunction()) {
+ FunctionCoverageFilter ff(Function::Cast(obj));
+ CodeCoverage::PrintJSON(isolate, js, &ff);
+ return true;
+ }
+ PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
+ "script, library, class, or function", target_id);
return true;
}
-static bool HandleLibrariesScriptsSetBreakpoint(
- Isolate* isolate, const Script& script, JSONStream* js) {
+static bool HandleIsolateAddBreakpoint(Isolate* isolate, JSONStream* js) {
if (!js->HasOption("line")) {
PrintError(js, "Missing 'line' option");
return true;
@@ -1818,9 +2205,16 @@ static bool HandleLibrariesScriptsSetBreakpoint(
const char* line_option = js->LookupOption("line");
intptr_t line = -1;
if (!GetIntegerId(line_option, &line)) {
- PrintError(js, "Invalid 'line' value: %s", line_option);
+ PrintError(js, "Invalid 'line' value: %s is not an integer", line_option);
+ return true;
+ }
+ const char* script_id = js->LookupOption("script");
+ Object& obj = Object::Handle(LookupHeapObject(isolate, script_id, NULL));
+ if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
+ PrintError(js, "Invalid 'script' value: no script with id '%s'", script_id);
return true;
}
+ const Script& script = Script::Cast(obj);
const String& script_url = String::Handle(script.url());
SourceBreakpoint* bpt =
isolate->debugger()->SetBreakpointAtLine(script_url, line);
@@ -1833,6 +2227,30 @@ static bool HandleLibrariesScriptsSetBreakpoint(
}
+static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) {
+ if (!js->HasOption("breakpointId")) {
+ PrintError(js, "Missing 'breakpointId' option");
+ return true;
+ }
+ const char* bpt_id = js->LookupOption("breakpointId");
+ SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
+ if (bpt == NULL) {
+ fprintf(stderr, "ERROR1");
+ PrintError(js, "Invalid 'breakpointId' value: no breakpoint with id '%s'",
+ bpt_id);
+ return true;
+ }
+ isolate->debugger()->RemoveBreakpoint(bpt->id());
+
+ fprintf(stderr, "SUCCESS");
+ // TODO(turnidge): Consider whether the 'Success' type is proper.
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "Success");
+ jsobj.AddProperty("id", "");
+ return true;
+}
+
+
static bool HandleLibrariesScripts(Isolate* isolate,
const Library& lib,
JSONStream* js) {
@@ -1864,30 +2282,11 @@ static bool HandleLibrariesScripts(Isolate* isolate,
PrintError(js, "Script %s not found", requested_url.ToCString());
return true;
}
- if (js->num_arguments() == 4) {
- script.PrintJSON(js, false);
+ if (js->num_arguments() > 4) {
+ PrintError(js, "Command too long");
return true;
- } else {
- const char* subcollection = js->GetArgument(4);
- if (strcmp(subcollection, "coverage") == 0) {
- return HandleLibrariesScriptsCoverage(isolate, script, js);
- } else if (strcmp(subcollection, "setBreakpoint") == 0) {
- return HandleLibrariesScriptsSetBreakpoint(isolate, script, js);
- } else {
- PrintError(js, "Invalid sub collection %s", subcollection);
- return true;
- }
}
- UNREACHABLE();
- return true;
-}
-
-
-static bool HandleLibrariesCoverage(Isolate* isolate,
- const Library& lib,
- JSONStream* js) {
- LibraryCoverageFilter lf(lib);
- CodeCoverage::PrintJSON(isolate, js, &lf);
+ script.PrintJSON(js, false);
return true;
}
@@ -1909,12 +2308,8 @@ static bool HandleLibraries(Isolate* isolate, JSONStream* js) {
return true;
} else if (js->num_arguments() >= 3) {
const char* second = js->GetArgument(2);
- if (strcmp(second, "eval") == 0) {
- return HandleLibrariesEval(isolate, lib, js);
- } else if (strcmp(second, "scripts") == 0) {
+ if (strcmp(second, "scripts") == 0) {
return HandleLibrariesScripts(isolate, lib, js);
- } else if (strcmp(second, "coverage") == 0) {
- return HandleLibrariesCoverage(isolate, lib, js);
} else {
PrintError(js, "Invalid sub collection %s", second);
return true;
@@ -1925,54 +2320,6 @@ static bool HandleLibraries(Isolate* isolate, JSONStream* js) {
}
-static void PrintSentinel(JSONStream* js,
- const char* id,
- const char* preview) {
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "Sentinel");
- jsobj.AddProperty("id", id);
- jsobj.AddProperty("valueAsString", preview);
-}
-
-
-static RawObject* LookupObjectId(Isolate* isolate,
- const char* arg,
- ObjectIdRing::LookupResult* kind) {
- *kind = ObjectIdRing::kValid;
- if (strncmp(arg, "int-", 4) == 0) {
- arg += 4;
- int64_t value = 0;
- if (!OS::StringToInt64(arg, &value) ||
- !Smi::IsValid(value)) {
- *kind = ObjectIdRing::kInvalid;
- return Object::null();
- }
- const Integer& obj =
- Integer::Handle(isolate, Smi::New(static_cast<intptr_t>(value)));
- return obj.raw();
- } else if (strcmp(arg, "bool-true") == 0) {
- return Bool::True().raw();
- } else if (strcmp(arg, "bool-false") == 0) {
- return Bool::False().raw();
- } else if (strcmp(arg, "null") == 0) {
- return Object::null();
- } else if (strcmp(arg, "not-initialized") == 0) {
- return Object::sentinel().raw();
- } else if (strcmp(arg, "being-initialized") == 0) {
- return Object::transition_sentinel().raw();
- }
-
- ObjectIdRing* ring = isolate->object_id_ring();
- ASSERT(ring != NULL);
- intptr_t id = -1;
- if (!GetIntegerId(arg, &id)) {
- *kind = ObjectIdRing::kInvalid;
- return Object::null();
- }
- return ring->GetObjectForId(id, kind);
-}
-
-
static RawClass* GetMetricsClass(Isolate* isolate) {
const Library& prof_lib =
Library::Handle(isolate, Library::ProfilerLibrary());
@@ -2095,7 +2442,7 @@ static bool HandleMetrics(Isolate* isolate, JSONStream* js) {
static bool HandleObjects(Isolate* isolate, JSONStream* js) {
REQUIRE_COLLECTION_ID("objects");
- if (js->num_arguments() < 2) {
+ if (js->num_arguments() != 2) {
PrintError(js, "expected at least 2 arguments but found %" Pd "\n",
js->num_arguments());
return true;
@@ -2139,21 +2486,19 @@ static bool HandleObjects(Isolate* isolate, JSONStream* js) {
PrintError(js, "unrecognized object id '%s'", arg);
return true;
}
- if (js->num_arguments() == 2) {
- // Print.
- if (kind == ObjectIdRing::kCollected) {
- // The object has been collected by the gc.
- PrintSentinel(js, "objects/collected", "<collected>");
- return true;
- } else if (kind == ObjectIdRing::kExpired) {
- // The object id has expired.
- PrintSentinel(js, "objects/expired", "<expired>");
- return true;
- }
- obj.PrintJSON(js, false);
+
+ // Print.
+ if (kind == ObjectIdRing::kCollected) {
+ // The object has been collected by the gc.
+ PrintSentinel(js, "objects/collected", "<collected>");
+ return true;
+ } else if (kind == ObjectIdRing::kExpired) {
+ // The object id has expired.
+ PrintSentinel(js, "objects/expired", "<expired>");
return true;
}
- return HandleInstanceCommands(isolate, &obj, kind, js, 2);
+ obj.PrintJSON(js, false);
+ return true;
}
@@ -2193,9 +2538,8 @@ static bool HandleScripts(Isolate* isolate, JSONStream* js) {
}
-static bool HandleDebugResume(Isolate* isolate,
- const char* step_option,
- JSONStream* js) {
+static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) {
+ const char* step_option = js->LookupOption("step");
if (isolate->message_handler()->paused_on_start()) {
isolate->message_handler()->set_pause_on_start(false);
JSONObject jsobj(js);
@@ -2235,78 +2579,22 @@ static bool HandleDebugResume(Isolate* isolate,
}
-static bool HandleDebug(Isolate* isolate, JSONStream* js) {
- if (js->num_arguments() == 1) {
- PrintError(js, "Must specify a subcommand");
- return true;
- }
- const char* command = js->GetArgument(1);
- if (strcmp(command, "breakpoints") == 0) {
- if (js->num_arguments() == 2) {
- // Print breakpoint list.
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "BreakpointList");
- jsobj.AddProperty("id", "debug/breakpoints");
- JSONArray jsarr(&jsobj, "breakpoints");
- isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
- return true;
- } else {
- intptr_t id = 0;
- SourceBreakpoint* bpt = NULL;
- if (GetIntegerId(js->GetArgument(2), &id)) {
- bpt = isolate->debugger()->GetBreakpointById(id);
- }
- if (bpt == NULL) {
- PrintError(js, "Unrecognized breakpoint id: %s", js->GetArgument(2));
- return true;
- }
- if (js->num_arguments() == 3) {
- // Print individual breakpoint.
- bpt->PrintJSON(js);
- return true;
- } else if (js->num_arguments() == 4) {
- const char* sub_command = js->GetArgument(3);
- if (strcmp(sub_command, "clear") == 0) {
- // Clear this breakpoint.
- isolate->debugger()->RemoveBreakpoint(id);
+static bool HandleIsolateGetBreakpoints(Isolate* isolate, JSONStream* js) {
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "BreakpointList");
+ JSONArray jsarr(&jsobj, "breakpoints");
+ isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
+ return true;
+}
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "Success");
- jsobj.AddProperty("id", "");
- return true;
- } else {
- PrintError(js, "Unrecognized subcommand: %s", sub_command);
- return true;
- }
- } else {
- PrintError(js, "Command too long");
- return true;
- }
- }
- } else if (strcmp(command, "pause") == 0) {
- if (js->num_arguments() == 2) {
- // TODO(turnidge): Don't double-interrupt the isolate here.
- isolate->ScheduleInterrupts(Isolate::kApiInterrupt);
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "Success");
- jsobj.AddProperty("id", "");
- return true;
- } else {
- PrintError(js, "Command too long");
- return true;
- }
- } else if (strcmp(command, "resume") == 0) {
- if (js->num_arguments() == 2) {
- const char* step_option = js->LookupOption("step");
- return HandleDebugResume(isolate, step_option, js);
- } else {
- PrintError(js, "Command too long");
- return true;
- }
- } else {
- PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1));
- return true;
- }
+
+static bool HandleIsolatePause(Isolate* isolate, JSONStream* js) {
+ // TODO(turnidge): Don't double-interrupt the isolate here.
+ isolate->ScheduleInterrupts(Isolate::kApiInterrupt);
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "Success");
+ jsobj.AddProperty("id", "");
+ return true;
}
@@ -2373,37 +2661,30 @@ static bool HandleCode(Isolate* isolate, JSONStream* js) {
}
-static bool HandleProfile(Isolate* isolate, JSONStream* js) {
- if (js->num_arguments() == 2) {
- const char* sub_command = js->GetArgument(1);
- if (!strcmp(sub_command, "tag")) {
- {
- JSONObject miniProfile(js);
- miniProfile.AddProperty("type", "TagProfile");
- miniProfile.AddProperty("id", "profile/tag");
- isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile);
- }
- return true;
- } else {
- PrintError(js, "Unrecognized subcommand '%s'", sub_command);
- return true;
- }
- }
+static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
+ JSONObject miniProfile(js);
+ miniProfile.AddProperty("type", "TagProfile");
+ miniProfile.AddProperty("id", "profile/tag");
+ isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile);
+ return true;
+}
+
+static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
// A full profile includes disassembly of all Dart code objects.
// TODO(johnmccutchan): Add sub command to trigger full code dump.
bool full_profile = false;
const char* tags_option = js->LookupOption("tags");
Profiler::TagOrder tag_order = Profiler::kUserVM;
if (js->HasOption("tags")) {
- if (js->OptionIs("tags", "hide")) {
+ if (js->OptionIs("tags", "None")) {
tag_order = Profiler::kNoTags;
- } else if (js->OptionIs("tags", "uv")) {
+ } else if (js->OptionIs("tags", "UserVM")) {
tag_order = Profiler::kUserVM;
- } else if (js->OptionIs("tags", "u")) {
+ } else if (js->OptionIs("tags", "UserOnly")) {
tag_order = Profiler::kUser;
- } else if (js->OptionIs("tags", "vu")) {
+ } else if (js->OptionIs("tags", "VMUser")) {
tag_order = Profiler::kVMUser;
- } else if (js->OptionIs("tags", "v")) {
+ } else if (js->OptionIs("tags", "VMOnly")) {
tag_order = Profiler::kVM;
} else {
PrintError(js, "Invalid tags option value: %s\n", tags_option);
@@ -2414,19 +2695,11 @@ static bool HandleProfile(Isolate* isolate, JSONStream* js) {
return true;
}
-static bool HandleCoverage(Isolate* isolate, JSONStream* js) {
- CodeCoverage::PrintJSON(isolate, js, NULL);
- return true;
-}
-
-static bool HandleAllocationProfile(Isolate* isolate, JSONStream* js) {
+static bool HandleIsolateGetAllocationProfile(Isolate* isolate,
+ JSONStream* js) {
bool should_reset_accumulator = false;
bool should_collect = false;
- if (js->num_arguments() != 1) {
- PrintError(js, "Command too long");
- return true;
- }
if (js->HasOption("reset")) {
if (js->OptionIs("reset", "true")) {
should_reset_accumulator = true;
@@ -2509,13 +2782,13 @@ static bool HandleTypeArguments(Isolate* isolate, JSONStream* js) {
}
-static bool HandleHeapMap(Isolate* isolate, JSONStream* js) {
+static bool HandleIsolateGetHeapMap(Isolate* isolate, JSONStream* js) {
isolate->heap()->PrintHeapMapToJSONStream(isolate, js);
return true;
}
-static bool HandleGraph(Isolate* isolate, JSONStream* js) {
+static bool HandleIsolateRequestHeapSnapshot(Isolate* isolate, JSONStream* js) {
Service::SendGraphEvent(isolate);
// TODO(koda): Provide some id that ties this request to async response(s).
JSONObject jsobj(js);
@@ -2606,25 +2879,18 @@ static bool HandleMalformedObject(Isolate* isolate, JSONStream* js) {
static IsolateMessageHandlerEntry isolate_handlers[] = {
- { "_malformedjson", HandleMalformedJson },
- { "_malformedobject", HandleMalformedObject },
- { "_echo", HandleIsolateEcho },
- { "", HandleIsolate },
- { "address", HandleAddress },
- { "allocationprofile", HandleAllocationProfile },
- { "classes", HandleClasses },
- { "code", HandleCode },
- { "coverage", HandleCoverage },
- { "debug", HandleDebug },
- { "graph", HandleGraph },
- { "heapmap", HandleHeapMap },
- { "libraries", HandleLibraries },
- { "metrics", HandleMetrics },
- { "objects", HandleObjects },
- { "profile", HandleProfile },
- { "scripts", HandleScripts },
- { "stacktrace", HandleStackTrace },
- { "typearguments", HandleTypeArguments },
+ { "_malformedjson", HandleMalformedJson }, // debug
+ { "_malformedobject", HandleMalformedObject }, // debug
+ { "_echo", HandleIsolateEcho }, // debug
+ { "", HandleIsolate }, // getObject
+ { "address", HandleAddress }, // to do
+ { "classes", HandleClasses }, // getObject
+ { "code", HandleCode }, // getObject
+ { "libraries", HandleLibraries }, // getObject
+ { "metrics", HandleMetrics }, // to do - complex?
+ { "objects", HandleObjects }, // getObject
+ { "scripts", HandleScripts }, // getObject
+ { "typearguments", HandleTypeArguments }, // confusing
};
@@ -2644,6 +2910,79 @@ static IsolateMessageHandler FindIsolateMessageHandler(const char* command) {
}
+static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) {
+ const char* id = js->LookupOption("id");
+ if (id == NULL) {
+ // TODO(turnidge): Print the isolate here instead.
+ PrintError(js, "GetObject expects an 'id' parameter\n",
+ js->num_arguments());
+ return true;
+ }
+
+ // Handle heap objects.
+ ObjectIdRing::LookupResult lookup_result;
+ const Object& obj =
+ Object::Handle(LookupHeapObject(isolate, id, &lookup_result));
+ if (obj.raw() != Object::sentinel().raw()) {
+ // We found a heap object for this id. Return it.
+ obj.PrintJSON(js, false);
+ return true;
+ } else if (lookup_result == ObjectIdRing::kCollected) {
+ PrintSentinel(js, "objects/collected", "<collected>");
+ } else if (lookup_result == ObjectIdRing::kExpired) {
+ PrintSentinel(js, "objects/expired", "<expired>");
+ }
+
+ // Handle non-heap objects.
+ SourceBreakpoint* bpt = LookupBreakpoint(isolate, id);
+ if (bpt != NULL) {
+ bpt->PrintJSON(js);
+ return true;
+ }
+
+ PrintError(js, "Unrecognized object id: %s\n", id);
+ return true;
+}
+
+
+static IsolateMessageHandlerEntry isolate_handlers_new[] = {
+ { "getObject", HandleIsolateGetObject },
+ { "getBreakpoints", HandleIsolateGetBreakpoints },
+ { "pause", HandleIsolatePause },
+ { "resume", HandleIsolateResume },
+ { "getStack", HandleIsolateGetStack },
+ { "getCpuProfile", HandleIsolateGetCpuProfile },
+ { "getTagProfile", HandleIsolateGetTagProfile },
+ { "getAllocationProfile", HandleIsolateGetAllocationProfile },
+ { "getHeapMap", HandleIsolateGetHeapMap },
+ { "addBreakpoint", HandleIsolateAddBreakpoint },
+ { "removeBreakpoint", HandleIsolateRemoveBreakpoint },
+ { "getCoverage", HandleIsolateGetCoverage },
+ { "eval", HandleIsolateEval },
+ { "getRetainedSize", HandleIsolateGetRetainedSize },
+ { "getRetainingPath", HandleIsolateGetRetainingPath },
+ { "getInboundReferences", HandleIsolateGetInboundReferences },
+ { "getInstances", HandleIsolateGetInstances },
+ { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot },
+};
+
+
+static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command) {
+ intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
+ sizeof(isolate_handlers_new[0]);
+ for (intptr_t i = 0; i < num_message_handlers; i++) {
+ const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
+ if (strcmp(command, entry.command) == 0) {
+ return entry.handler;
+ }
+ }
+ if (FLAG_trace_service) {
+ OS::Print("Service has no isolate message handler for <%s>\n", command);
+ }
+ return NULL;
+}
+
+
void Service::HandleRootMessage(const Instance& msg) {
Isolate* isolate = Isolate::Current();
ASSERT(!msg.IsNull());
« no previous file with comments | « runtime/vm/service.h ('k') | runtime/vm/service/message.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698