| Index: runtime/vm/service.cc
|
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
|
| index a1564d215404ee04e966577e78a1dee88cf4d247..0b6b443a4dc19abce6ddd04355a6e5d348f9f47b 100644
|
| --- a/runtime/vm/service.cc
|
| +++ b/runtime/vm/service.cc
|
| @@ -954,7 +954,7 @@ static bool ContainsNonInstance(const Object& obj) {
|
| Object& element = Object::Handle();
|
| for (intptr_t i = 0; i < array.Length(); ++i) {
|
| element = array.At(i);
|
| - if (!element.IsInstance()) {
|
| + if (!(element.IsInstance() || element.IsNull())) {
|
| return true;
|
| }
|
| }
|
| @@ -964,13 +964,13 @@ static bool ContainsNonInstance(const Object& obj) {
|
| Object& element = Object::Handle();
|
| for (intptr_t i = 0; i < array.Length(); ++i) {
|
| element = array.At(i);
|
| - if (!element.IsInstance()) {
|
| + if (!(element.IsInstance() || element.IsNull())) {
|
| return true;
|
| }
|
| }
|
| return false;
|
| } else {
|
| - return !obj.IsInstance();
|
| + return !(obj.IsInstance() || obj.IsNull());
|
| }
|
| }
|
|
|
| @@ -1080,12 +1080,15 @@ 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)) {
|
| @@ -1094,13 +1097,13 @@ static bool HandleInstanceCommands(Isolate* isolate,
|
| js->num_arguments());
|
| return true;
|
| }
|
| - if (obj->IsNull()) {
|
| + if (kind == ObjectIdRing::kCollected) {
|
| PrintErrorWithKind(js, "EvalCollected",
|
| "attempt to evaluate against collected object\n",
|
| js->num_arguments());
|
| return true;
|
| }
|
| - if (obj->raw() == Object::sentinel().raw()) {
|
| + if (kind == ObjectIdRing::kExpired) {
|
| PrintErrorWithKind(js, "EvalExpired",
|
| "attempt to evaluate against expired object\n",
|
| js->num_arguments());
|
| @@ -1126,12 +1129,40 @@ static bool HandleInstanceCommands(Isolate* isolate,
|
| result.PrintJSON(js, true);
|
| 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);
|
| return true;
|
| } else if (strcmp(action, "retaining_path") == 0) {
|
| + if (kind == 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) {
|
| + 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",
|
| @@ -1140,6 +1171,20 @@ static bool HandleInstanceCommands(Isolate* isolate,
|
| }
|
| return HandleRetainingPath(isolate, obj, limit, js);
|
| } else if (strcmp(action, "inbound_references") == 0) {
|
| + if (kind == ObjectIdRing::kCollected) {
|
| + PrintErrorWithKind(
|
| + js, "InboundReferencesCollected",
|
| + "attempt to find inbound references for a collected object\n",
|
| + js->num_arguments());
|
| + return true;
|
| + }
|
| + if (kind == ObjectIdRing::kExpired) {
|
| + PrintErrorWithKind(
|
| + js, "InboundReferencesExpired",
|
| + "attempt to find inbound references for 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",
|
| @@ -1335,7 +1380,7 @@ static bool HandleClassesTypes(Isolate* isolate, const Class& cls,
|
| type.PrintJSON(js, false);
|
| return true;
|
| }
|
| - return HandleInstanceCommands(isolate, &type, js, 4);
|
| + return HandleInstanceCommands(isolate, &type, ObjectIdRing::kValid, js, 4);
|
| }
|
|
|
|
|
| @@ -1639,35 +1684,39 @@ static void PrintPseudoNull(JSONStream* js,
|
|
|
| static RawObject* LookupObjectId(Isolate* isolate,
|
| const char* arg,
|
| - bool* error) {
|
| - *error = false;
|
| + 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)) {
|
| - *error = true;
|
| + *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)) {
|
| - *error = true;
|
| - return Instance::null();
|
| + *kind = ObjectIdRing::kInvalid;
|
| + return Object::null();
|
| }
|
| - return ring->GetObjectForId(id);
|
| + return ring->GetObjectForId(id, kind);
|
| }
|
|
|
|
|
| @@ -1800,35 +1849,8 @@ static bool HandleObjects(Isolate* isolate, JSONStream* js) {
|
| }
|
| const char* arg = js->GetArgument(1);
|
|
|
| - // Handle special objects first.
|
| - if (strcmp(arg, "null") == 0) {
|
| - if (js->num_arguments() > 2) {
|
| - PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
|
| - js->num_arguments());
|
| - } else {
|
| - Instance::null_instance().PrintJSON(js, false);
|
| - }
|
| - return true;
|
| -
|
| - } else if (strcmp(arg, "not-initialized") == 0) {
|
| - if (js->num_arguments() > 2) {
|
| - PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
|
| - js->num_arguments());
|
| - } else {
|
| - Object::sentinel().PrintJSON(js, false);
|
| - }
|
| - return true;
|
| -
|
| - } else if (strcmp(arg, "being-initialized") == 0) {
|
| - if (js->num_arguments() > 2) {
|
| - PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
|
| - js->num_arguments());
|
| - } else {
|
| - Object::transition_sentinel().PrintJSON(js, false);
|
| - }
|
| - return true;
|
| -
|
| - } else if (strcmp(arg, "optimized-out") == 0) {
|
| + // Handle special non-objects first.
|
| + if (strcmp(arg, "optimized-out") == 0) {
|
| if (js->num_arguments() > 2) {
|
| PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
|
| js->num_arguments());
|
| @@ -1858,19 +1880,19 @@ static bool HandleObjects(Isolate* isolate, JSONStream* js) {
|
|
|
| // Lookup the object.
|
| Object& obj = Object::Handle(isolate);
|
| - bool error = false;
|
| - obj = LookupObjectId(isolate, arg, &error);
|
| - if (error) {
|
| + ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
|
| + obj = LookupObjectId(isolate, arg, &kind);
|
| + if (kind == ObjectIdRing::kInvalid) {
|
| PrintError(js, "unrecognized object id '%s'", arg);
|
| return true;
|
| }
|
| if (js->num_arguments() == 2) {
|
| // Print.
|
| - if (obj.IsNull()) {
|
| + if (kind == ObjectIdRing::kCollected) {
|
| // The object has been collected by the gc.
|
| PrintPseudoNull(js, "objects/collected", "<collected>");
|
| return true;
|
| - } else if (obj.raw() == Object::sentinel().raw()) {
|
| + } else if (kind == ObjectIdRing::kExpired) {
|
| // The object id has expired.
|
| PrintPseudoNull(js, "objects/expired", "<expired>");
|
| return true;
|
| @@ -1878,7 +1900,7 @@ static bool HandleObjects(Isolate* isolate, JSONStream* js) {
|
| obj.PrintJSON(js, false);
|
| return true;
|
| }
|
| - return HandleInstanceCommands(isolate, &obj, js, 2);
|
| + return HandleInstanceCommands(isolate, &obj, kind, js, 2);
|
| }
|
|
|
|
|
|
|