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

Side by Side 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: fjkdls Created 5 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/service.h" 5 #include "vm/service.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 #include "platform/globals.h" 8 #include "platform/globals.h"
9 9
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 806 matching lines...) Expand 10 before | Expand all | Expand 10 after
817 // posting the reply (this can be used for asynchronous delegation of 817 // posting the reply (this can be used for asynchronous delegation of
818 // the response handling). 818 // the response handling).
819 typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream); 819 typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream);
820 820
821 struct IsolateMessageHandlerEntry { 821 struct IsolateMessageHandlerEntry {
822 const char* command; 822 const char* command;
823 IsolateMessageHandler handler; 823 IsolateMessageHandler handler;
824 }; 824 };
825 825
826 static IsolateMessageHandler FindIsolateMessageHandler(const char* command); 826 static IsolateMessageHandler FindIsolateMessageHandler(const char* command);
827 static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command);
827 828
828 829
829 // A handler for a root (vm-global) request. 830 // A handler for a root (vm-global) request.
830 // 831 //
831 // If a handler returns true, the reply is complete and ready to be 832 // If a handler returns true, the reply is complete and ready to be
832 // posted. If a handler returns false, then it is responsible for 833 // posted. If a handler returns false, then it is responsible for
833 // posting the reply (this can be used for asynchronous delegation of 834 // posting the reply (this can be used for asynchronous delegation of
834 // the response handling). 835 // the response handling).
835 typedef bool (*RootMessageHandler)(JSONStream* stream); 836 typedef bool (*RootMessageHandler)(JSONStream* stream);
836 837
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
875 va_end(args); 876 va_end(args);
876 877
877 char* buffer = isolate->current_zone()->Alloc<char>(len + 1); 878 char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
878 va_list args2; 879 va_list args2;
879 va_start(args2, format); 880 va_start(args2, format);
880 OS::VSNPrint(buffer, (len + 1), format, args2); 881 OS::VSNPrint(buffer, (len + 1), format, args2);
881 va_end(args2); 882 va_end(args2);
882 883
883 JSONObject jsobj(js); 884 JSONObject jsobj(js);
884 jsobj.AddProperty("type", "Error"); 885 jsobj.AddProperty("type", "Error");
885 jsobj.AddProperty("id", "");
886 jsobj.AddProperty("message", buffer); 886 jsobj.AddProperty("message", buffer);
887 PrintArgumentsAndOptions(jsobj, js); 887 PrintArgumentsAndOptions(jsobj, js);
888 } 888 }
889 889
890 890
891 static void PrintErrorWithKind(JSONStream* js, 891 static void PrintErrorWithKind(JSONStream* js,
892 const char* kind, 892 const char* kind,
893 const char* format, ...) { 893 const char* format, ...) {
894 Isolate* isolate = Isolate::Current(); 894 Isolate* isolate = Isolate::Current();
895 895
(...skipping 10 matching lines...) Expand all
906 906
907 JSONObject jsobj(js); 907 JSONObject jsobj(js);
908 jsobj.AddProperty("type", "Error"); 908 jsobj.AddProperty("type", "Error");
909 jsobj.AddProperty("id", ""); 909 jsobj.AddProperty("id", "");
910 jsobj.AddProperty("kind", kind); 910 jsobj.AddProperty("kind", kind);
911 jsobj.AddProperty("message", buffer); 911 jsobj.AddProperty("message", buffer);
912 PrintArgumentsAndOptions(jsobj, js); 912 PrintArgumentsAndOptions(jsobj, js);
913 } 913 }
914 914
915 915
916 void Service::HandleIsolateMessageNew(Isolate* isolate, const Array& msg) {
917 ASSERT(isolate != NULL);
918 ASSERT(!msg.IsNull());
919
920 {
921 StackZone zone(isolate);
922 HANDLESCOPE(isolate);
923
924 Instance& reply_port = Instance::Handle(isolate);
925 String& method = String::Handle(isolate);
926 Array& param_keys = Array::Handle(isolate);
927 Array& param_values = Array::Handle(isolate);
928 reply_port ^= msg.At(1);
929 method ^= msg.At(2);
930 param_keys ^= msg.At(3);
931 param_values ^= msg.At(4);
932
933 ASSERT(!method.IsNull());
934 ASSERT(!param_keys.IsNull());
935 ASSERT(!param_values.IsNull());
936 ASSERT(param_keys.Length() == param_values.Length());
937
938 if (!reply_port.IsSendPort()) {
939 FATAL("SendPort expected.");
940 }
941
942 IsolateMessageHandler handler =
943 FindIsolateMessageHandlerNew(method.ToCString());
944 {
945 JSONStream js;
946 js.SetupNew(zone.GetZone(), SendPort::Cast(reply_port).Id(),
947 method, param_keys, param_values);
948 if (handler == NULL) {
949 // Check for an embedder handler.
950 EmbedderServiceHandler* e_handler =
951 FindIsolateEmbedderHandler(method.ToCString());
952 if (e_handler != NULL) {
953 EmbedderHandleMessage(e_handler, &js);
954 } else {
955 PrintError(&js, "Unrecognized method: %s", method.ToCString());
956 }
957 js.PostReply();
958 } else {
959 if (handler(isolate, &js)) {
960 // Handler returns true if the reply is ready to be posted.
961 // TODO(johnmccutchan): Support asynchronous replies.
962 js.PostReply();
963 }
964 }
965 }
966 }
967 }
968
969
916 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) { 970 void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
917 ASSERT(isolate != NULL); 971 ASSERT(isolate != NULL);
918 ASSERT(!msg.IsNull()); 972 ASSERT(!msg.IsNull());
919 973
920 { 974 {
921 StackZone zone(isolate); 975 StackZone zone(isolate);
922 HANDLESCOPE(isolate); 976 HANDLESCOPE(isolate);
923 977
924 // Message is a list with five entries. 978 // Message is a list with five entries.
925 ASSERT(msg.Length() == 5); 979 ASSERT(msg.Length() == 5);
926 980
981 Object& tmp = Object::Handle(isolate);
982 tmp = msg.At(2);
983 if (tmp.IsString()) {
984 return Service::HandleIsolateMessageNew(isolate, msg);
985 }
986
927 Instance& reply_port = Instance::Handle(isolate); 987 Instance& reply_port = Instance::Handle(isolate);
928 GrowableObjectArray& path = GrowableObjectArray::Handle(isolate); 988 GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
929 Array& option_keys = Array::Handle(isolate); 989 Array& option_keys = Array::Handle(isolate);
930 Array& option_values = Array::Handle(isolate); 990 Array& option_values = Array::Handle(isolate);
931 reply_port ^= msg.At(1); 991 reply_port ^= msg.At(1);
932 path ^= msg.At(2); 992 path ^= msg.At(2);
933 option_keys ^= msg.At(3); 993 option_keys ^= msg.At(3);
934 option_values ^= msg.At(4); 994 option_values ^= msg.At(4);
935 995
936 ASSERT(!path.IsNull()); 996 ASSERT(!path.IsNull());
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
979 } 1039 }
980 } 1040 }
981 1041
982 1042
983 static bool HandleIsolate(Isolate* isolate, JSONStream* js) { 1043 static bool HandleIsolate(Isolate* isolate, JSONStream* js) {
984 isolate->PrintJSON(js, false); 1044 isolate->PrintJSON(js, false);
985 return true; 1045 return true;
986 } 1046 }
987 1047
988 1048
989 static bool HandleStackTrace(Isolate* isolate, JSONStream* js) { 1049 static bool HandleIsolateGetStack(Isolate* isolate, JSONStream* js) {
990 if (js->num_arguments() > 1) {
991 PrintError(js, "Command too long");
992 return true;
993 }
994 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); 1050 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
995 JSONObject jsobj(js); 1051 JSONObject jsobj(js);
996 jsobj.AddProperty("type", "StackTrace"); 1052 jsobj.AddProperty("type", "Stack");
997 jsobj.AddProperty("id", "stacktrace"); 1053 JSONArray jsarr(&jsobj, "frames");
998 JSONArray jsarr(&jsobj, "members");
999 intptr_t num_frames = stack->Length(); 1054 intptr_t num_frames = stack->Length();
1000 for (intptr_t i = 0; i < num_frames; i++) { 1055 for (intptr_t i = 0; i < num_frames; i++) {
1001 ActivationFrame* frame = stack->FrameAt(i); 1056 ActivationFrame* frame = stack->FrameAt(i);
1002 JSONObject jsobj(&jsarr); 1057 JSONObject jsobj(&jsarr);
1003 frame->PrintToJSONObject(&jsobj); 1058 frame->PrintToJSONObject(&jsobj);
1004 // TODO(turnidge): Implement depth differently -- differentiate 1059 // TODO(turnidge): Implement depth differently -- differentiate
1005 // inlined frames. 1060 // inlined frames.
1006 jsobj.AddProperty("depth", i); 1061 jsobj.AddProperty("depth", i);
1007 } 1062 }
1008 return true; 1063 return true;
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
1188 return true; 1243 return true;
1189 } 1244 }
1190 } 1245 }
1191 return false; 1246 return false;
1192 } else { 1247 } else {
1193 return !(obj.IsInstance() || obj.IsNull()); 1248 return !(obj.IsInstance() || obj.IsNull());
1194 } 1249 }
1195 } 1250 }
1196 1251
1197 1252
1198 static bool HandleInboundReferences(Isolate* isolate, 1253 static RawObject* LookupObjectId(Isolate* isolate,
1199 Object* target, 1254 const char* arg,
1200 intptr_t limit, 1255 ObjectIdRing::LookupResult* kind) {
1201 JSONStream* js) { 1256 *kind = ObjectIdRing::kValid;
1257 if (strncmp(arg, "int-", 4) == 0) {
1258 arg += 4;
1259 int64_t value = 0;
1260 if (!OS::StringToInt64(arg, &value) ||
1261 !Smi::IsValid(value)) {
1262 *kind = ObjectIdRing::kInvalid;
1263 return Object::null();
1264 }
1265 const Integer& obj =
1266 Integer::Handle(isolate, Smi::New(static_cast<intptr_t>(value)));
1267 return obj.raw();
1268 } else if (strcmp(arg, "bool-true") == 0) {
1269 return Bool::True().raw();
1270 } else if (strcmp(arg, "bool-false") == 0) {
1271 return Bool::False().raw();
1272 } else if (strcmp(arg, "null") == 0) {
1273 return Object::null();
1274 } else if (strcmp(arg, "not-initialized") == 0) {
1275 return Object::sentinel().raw();
1276 } else if (strcmp(arg, "being-initialized") == 0) {
1277 return Object::transition_sentinel().raw();
1278 }
1279
1280 ObjectIdRing* ring = isolate->object_id_ring();
1281 ASSERT(ring != NULL);
1282 intptr_t id = -1;
1283 if (!GetIntegerId(arg, &id)) {
1284 *kind = ObjectIdRing::kInvalid;
1285 return Object::null();
1286 }
1287 return ring->GetObjectForId(id, kind);
1288 }
1289
1290
1291 static RawObject* LookupHeapObject(Isolate* isolate,
1292 const char* id_original,
1293 ObjectIdRing::LookupResult* result) {
1294 char* id = isolate->current_zone()->MakeCopyOfString(id_original);
1295
1296 // Parse the id by splitting at each '/'.
1297 const int MAX_PARTS = 8;
1298 char* parts[MAX_PARTS];
1299 int num_parts = 0;
1300 int i = 0;
1301 int start_pos = 0;
1302 while (id[i] != '\0') {
1303 if (id[i] == '/') {
1304 id[i++] = '\0';
1305 parts[num_parts++] = &id[start_pos];
1306 if (num_parts == MAX_PARTS) {
1307 break;
1308 }
1309 start_pos = i;
1310 } else {
1311 i++;
1312 }
1313 }
1314 if (num_parts < MAX_PARTS) {
1315 parts[num_parts++] = &id[start_pos];
1316 }
1317
1318 if (result != NULL) {
1319 *result = ObjectIdRing::kValid;
1320 }
1321
1322 if (strcmp(parts[0], "objects") == 0) {
1323 // Object ids look like "objects/1123"
1324 Object& obj = Object::Handle(isolate);
1325 ObjectIdRing::LookupResult lookup_result;
1326 obj = LookupObjectId(isolate, parts[1], &lookup_result);
1327 if (lookup_result != ObjectIdRing::kValid) {
1328 if (result != NULL) {
1329 *result = lookup_result;
1330 }
1331 return Object::sentinel().raw();
1332 }
1333 return obj.raw();
1334
1335 } else if (strcmp(parts[0], "libraries") == 0) {
1336 // Library ids look like "libraries/35"
1337 if (num_parts < 2) {
1338 return Object::sentinel().raw();
1339 }
1340 const GrowableObjectArray& libs =
1341 GrowableObjectArray::Handle(isolate->object_store()->libraries());
1342 ASSERT(!libs.IsNull());
1343 intptr_t id = 0;
1344 if (!GetIntegerId(parts[1], &id)) {
1345 return Object::sentinel().raw();
1346 }
1347 if ((id < 0) || (id >= libs.Length())) {
1348 return Object::sentinel().raw();
1349 }
1350 Library& lib = Library::Handle();
1351 lib ^= libs.At(id);
1352 ASSERT(!lib.IsNull());
1353 if (num_parts == 2) {
1354 return lib.raw();
1355 }
1356 if (strcmp(parts[2], "scripts") == 0) {
1357 // Script ids look like "libraries/35/scripts/library%2Furl.dart"
1358 if (num_parts != 4) {
1359 return Object::sentinel().raw();
1360 }
1361 const String& id = String::Handle(String::New(parts[3]));
1362 ASSERT(!id.IsNull());
1363 // The id is the url of the script % encoded, decode it.
1364 const String& requested_url = String::Handle(String::DecodeIRI(id));
1365 Script& script = Script::Handle();
1366 String& script_url = String::Handle();
1367 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
1368 ASSERT(!loaded_scripts.IsNull());
1369 intptr_t i;
1370 for (i = 0; i < loaded_scripts.Length(); i++) {
1371 script ^= loaded_scripts.At(i);
1372 ASSERT(!script.IsNull());
1373 script_url ^= script.url();
1374 if (script_url.Equals(requested_url)) {
1375 return script.raw();
1376 }
1377 }
1378 }
1379 } else if (strcmp(parts[0], "classes") == 0) {
1380 // Class ids look like: "classes/17"
1381 if (num_parts < 2) {
1382 return Object::sentinel().raw();
1383 }
1384 ClassTable* table = isolate->class_table();
1385 intptr_t id;
1386 if (!GetIntegerId(parts[1], &id) ||
1387 !table->IsValidIndex(id)) {
1388 return Object::sentinel().raw();
1389 }
1390 Class& cls = Class::Handle(table->At(id));
1391 if (num_parts == 2) {
1392 return cls.raw();
1393 }
1394 if (strcmp(parts[2], "closures") == 0) {
1395 // Closure ids look like: "classes/17/closures/11"
Cutch 2015/02/02 22:20:04 I wonder if this function could be split up into s
turnidge 2015/02/02 22:44:05 Done.
1396 if (num_parts != 4) {
1397 return Object::sentinel().raw();
1398 }
1399 intptr_t id;
1400 if (!GetIntegerId(parts[3], &id)) {
1401 return Object::sentinel().raw();
1402 }
1403 Function& func = Function::Handle();
1404 func ^= cls.ClosureFunctionFromIndex(id);
1405 if (func.IsNull()) {
1406 return Object::sentinel().raw();
1407 }
1408 return func.raw();
1409
1410 } else if (strcmp(parts[2], "fields") == 0) {
1411 // Field ids look like: "classes/17/fields/11"
1412 if (num_parts != 4) {
1413 return Object::sentinel().raw();
1414 }
1415 intptr_t id;
1416 if (!GetIntegerId(parts[3], &id)) {
1417 return Object::sentinel().raw();
1418 }
1419 Field& field = Field::Handle(cls.FieldFromIndex(id));
1420 if (field.IsNull()) {
1421 return Object::sentinel().raw();
1422 }
1423 return field.raw();
1424
1425 } else if (strcmp(parts[2], "functions") == 0) {
1426 // Function ids look like: "classes/17/functions/11"
1427 if (num_parts != 4) {
1428 return Object::sentinel().raw();
1429 }
1430 const char* encoded_id = parts[3];
1431 String& id = String::Handle(isolate, String::New(encoded_id));
1432 id = String::DecodeIRI(id);
1433 if (id.IsNull()) {
1434 return Object::sentinel().raw();
1435 }
1436 Function& func = Function::Handle(cls.LookupFunction(id));
1437 if (func.IsNull()) {
1438 return Object::sentinel().raw();
1439 }
1440 return func.raw();
1441
1442 } else if (strcmp(parts[2], "implicit_closures") == 0) {
1443 // Function ids look like: "classes/17/implicit_closures/11"
1444 if (num_parts != 4) {
1445 return Object::sentinel().raw();
1446 }
1447 intptr_t id;
1448 if (!GetIntegerId(parts[3], &id)) {
1449 return Object::sentinel().raw();
1450 }
1451 Function& func = Function::Handle();
1452 func ^= cls.ImplicitClosureFunctionFromIndex(id);
1453 if (func.IsNull()) {
1454 return Object::sentinel().raw();
1455 }
1456 return func.raw();
1457
1458 } else if (strcmp(parts[2], "dispatchers") == 0) {
1459 // Dispatcher Function ids look like: "classes/17/dispatchers/11"
1460 if (num_parts != 4) {
1461 return Object::sentinel().raw();
1462 }
1463 intptr_t id;
1464 if (!GetIntegerId(parts[3], &id)) {
1465 return Object::sentinel().raw();
1466 }
1467 Function& func = Function::Handle();
1468 func ^= cls.InvocationDispatcherFunctionFromIndex(id);
1469 if (func.IsNull()) {
1470 return Object::sentinel().raw();
1471 }
1472 return func.raw();
1473
1474 } else if (strcmp(parts[2], "types") == 0) {
1475 // Type ids look like: "classes/17/types/11"
1476 if (num_parts != 4) {
1477 return Object::sentinel().raw();
1478 }
1479 intptr_t id;
1480 if (!GetIntegerId(parts[3], &id)) {
1481 return Object::sentinel().raw();
1482 }
1483 Type& type = Type::Handle();
1484 type ^= cls.CanonicalTypeFromIndex(id);
1485 if (type.IsNull()) {
1486 return Object::sentinel().raw();
1487 }
1488 return type.raw();
1489 }
1490 }
1491
1492 // Not found.
1493 return Object::sentinel().raw();
1494 }
1495
1496
1497 static void PrintSentinel(JSONStream* js,
1498 const char* id,
1499 const char* preview) {
1500 JSONObject jsobj(js);
1501 jsobj.AddProperty("type", "Sentinel");
1502 jsobj.AddProperty("id", id);
1503 jsobj.AddProperty("valueAsString", preview);
1504 }
1505
1506
1507 static SourceBreakpoint* LookupBreakpoint(Isolate* isolate, const char* id) {
1508 size_t end_pos = strcspn(id, "/");
1509 const char* rest = NULL;
1510 if (end_pos < strlen(id)) {
1511 rest = id + end_pos + 1; // +1 for '/'.
1512 }
1513 if (strncmp("breakpoints", id, end_pos) == 0) {
1514 if (rest == NULL) {
1515 return NULL;
1516 }
1517 intptr_t bpt_id = 0;
1518 SourceBreakpoint* bpt = NULL;
1519 if (GetIntegerId(rest, &bpt_id)) {
1520 bpt = isolate->debugger()->GetBreakpointById(bpt_id);
1521 }
1522 return bpt;
1523 }
1524 return NULL;
1525 }
1526
1527
1528
1529
1530 static bool PrintInboundReferences(Isolate* isolate,
1531 Object* target,
1532 intptr_t limit,
1533 JSONStream* js) {
1202 ObjectGraph graph(isolate); 1534 ObjectGraph graph(isolate);
1203 Array& path = Array::Handle(Array::New(limit * 2)); 1535 Array& path = Array::Handle(Array::New(limit * 2));
1204 intptr_t length = graph.InboundReferences(target, path); 1536 intptr_t length = graph.InboundReferences(target, path);
1205 JSONObject jsobj(js); 1537 JSONObject jsobj(js);
1206 jsobj.AddProperty("type", "InboundReferences"); 1538 jsobj.AddProperty("type", "InboundReferences");
1207 jsobj.AddProperty("id", "inbound_references");
1208 { 1539 {
1209 JSONArray elements(&jsobj, "references"); 1540 JSONArray elements(&jsobj, "references");
1210 Object& source = Object::Handle(); 1541 Object& source = Object::Handle();
1211 Smi& slot_offset = Smi::Handle(); 1542 Smi& slot_offset = Smi::Handle();
1212 Class& source_class = Class::Handle(); 1543 Class& source_class = Class::Handle();
1213 Field& field = Field::Handle(); 1544 Field& field = Field::Handle();
1214 Array& parent_field_map = Array::Handle(); 1545 Array& parent_field_map = Array::Handle();
1215 limit = Utils::Minimum(limit, length); 1546 limit = Utils::Minimum(limit, length);
1216 for (intptr_t i = 0; i < limit; ++i) { 1547 for (intptr_t i = 0; i < limit; ++i) {
1217 JSONObject jselement(&elements); 1548 JSONObject jselement(&elements);
(...skipping 19 matching lines...) Expand all
1237 // We nil out the array after generating the response to prevent 1568 // We nil out the array after generating the response to prevent
1238 // reporting suprious references when repeatedly looking for the 1569 // reporting suprious references when repeatedly looking for the
1239 // references to an object. 1570 // references to an object.
1240 path.SetAt(i * 2, Object::null_object()); 1571 path.SetAt(i * 2, Object::null_object());
1241 } 1572 }
1242 } 1573 }
1243 return true; 1574 return true;
1244 } 1575 }
1245 1576
1246 1577
1247 static bool HandleRetainingPath(Isolate* isolate, 1578 static bool HandleIsolateGetInboundReferences(Isolate* isolate,
1248 Object* obj, 1579 JSONStream* js) {
1249 intptr_t limit, 1580 const char* target_id = js->LookupOption("targetId");
1250 JSONStream* js) { 1581 if (target_id == NULL) {
1582 PrintError(js, "Missing 'targetId' option");
1583 return true;
1584 }
1585 const char* limit_cstr = js->LookupOption("limit");
1586 if (target_id == NULL) {
1587 PrintError(js, "Missing 'limit' option");
1588 return true;
1589 }
1590 intptr_t limit;
1591 if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
1592 PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
1593 return true;
1594 }
1595
1596 Object& obj = Object::Handle(isolate);
1597 ObjectIdRing::LookupResult lookup_result;
1598 {
1599 HANDLESCOPE(isolate);
1600 obj = LookupHeapObject(isolate, target_id, &lookup_result);
1601 }
1602 if (obj.raw() == Object::sentinel().raw()) {
1603 if (lookup_result == ObjectIdRing::kCollected) {
1604 PrintErrorWithKind(
1605 js, "InboundReferencesCollected",
1606 "attempt to find a retaining path for a collected object\n",
1607 js->num_arguments());
1608 return true;
1609 } else if (lookup_result == ObjectIdRing::kExpired) {
1610 PrintErrorWithKind(
1611 js, "InboundReferencesExpired",
1612 "attempt to find a retaining path for an expired object\n",
1613 js->num_arguments());
1614 return true;
1615 }
1616 PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
1617 target_id);
1618 return true;
1619 }
1620 return PrintInboundReferences(isolate, &obj, limit, js);
1621 }
1622
1623
1624 static bool PrintRetainingPath(Isolate* isolate,
1625 Object* obj,
1626 intptr_t limit,
1627 JSONStream* js) {
1251 ObjectGraph graph(isolate); 1628 ObjectGraph graph(isolate);
1252 Array& path = Array::Handle(Array::New(limit * 2)); 1629 Array& path = Array::Handle(Array::New(limit * 2));
1253 intptr_t length = graph.RetainingPath(obj, path); 1630 intptr_t length = graph.RetainingPath(obj, path);
1254 JSONObject jsobj(js); 1631 JSONObject jsobj(js);
1255 jsobj.AddProperty("type", "RetainingPath"); 1632 jsobj.AddProperty("type", "RetainingPath");
1256 jsobj.AddProperty("id", "retaining_path");
1257 jsobj.AddProperty("length", length); 1633 jsobj.AddProperty("length", length);
1258 JSONArray elements(&jsobj, "elements"); 1634 JSONArray elements(&jsobj, "elements");
1259 Object& element = Object::Handle(); 1635 Object& element = Object::Handle();
1260 Object& parent = Object::Handle(); 1636 Object& parent = Object::Handle();
1261 Smi& offset_from_parent = Smi::Handle(); 1637 Smi& offset_from_parent = Smi::Handle();
1262 Class& parent_class = Class::Handle(); 1638 Class& parent_class = Class::Handle();
1263 Array& parent_field_map = Array::Handle(); 1639 Array& parent_field_map = Array::Handle();
1264 Field& field = Field::Handle(); 1640 Field& field = Field::Handle();
1265 limit = Utils::Minimum(limit, length); 1641 limit = Utils::Minimum(limit, length);
1266 for (intptr_t i = 0; i < limit; ++i) { 1642 for (intptr_t i = 0; i < limit; ++i) {
(...skipping 17 matching lines...) Expand all
1284 intptr_t offset = offset_from_parent.Value(); 1660 intptr_t offset = offset_from_parent.Value();
1285 if (offset > 0 && offset < parent_field_map.Length()) { 1661 if (offset > 0 && offset < parent_field_map.Length()) {
1286 field ^= parent_field_map.At(offset); 1662 field ^= parent_field_map.At(offset);
1287 jselement.AddProperty("parentField", field); 1663 jselement.AddProperty("parentField", field);
1288 } 1664 }
1289 } 1665 }
1290 } 1666 }
1291 } 1667 }
1292 1668
1293 // We nil out the array after generating the response to prevent 1669 // We nil out the array after generating the response to prevent
1294 // reporting suprious references when looking for inbound references 1670 // reporting spurious references when looking for inbound references
1295 // after looking for a retaining path. 1671 // after looking for a retaining path.
1296 for (intptr_t i = 0; i < limit; ++i) { 1672 for (intptr_t i = 0; i < limit; ++i) {
1297 path.SetAt(i * 2, Object::null_object()); 1673 path.SetAt(i * 2, Object::null_object());
1298 } 1674 }
1299 1675
1300 return true; 1676 return true;
1301 } 1677 }
1302 1678
1679 static bool HandleIsolateGetRetainingPath(Isolate* isolate,
1680 JSONStream* js) {
1681 const char* target_id = js->LookupOption("targetId");
1682 if (target_id == NULL) {
1683 PrintError(js, "Missing 'targetId' option");
1684 return true;
1685 }
1686 const char* limit_cstr = js->LookupOption("limit");
1687 if (target_id == NULL) {
1688 PrintError(js, "Missing 'limit' option");
1689 return true;
1690 }
1691 intptr_t limit;
1692 if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
1693 PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
1694 return true;
1695 }
1303 1696
1304 // Takes an Object* only because RetainingPath temporarily clears it. 1697 Object& obj = Object::Handle(isolate);
1305 static bool HandleInstanceCommands(Isolate* isolate, 1698 ObjectIdRing::LookupResult lookup_result;
1306 Object* obj, 1699 {
1307 ObjectIdRing::LookupResult kind, 1700 HANDLESCOPE(isolate);
1308 JSONStream* js, 1701 obj = LookupHeapObject(isolate, target_id, &lookup_result);
1309 intptr_t arg_pos) { 1702 }
1310 ASSERT(js->num_arguments() > arg_pos); 1703 if (obj.raw() == Object::sentinel().raw()) {
1311 ASSERT(kind != ObjectIdRing::kInvalid); 1704 if (lookup_result == ObjectIdRing::kCollected) {
1312 const char* action = js->GetArgument(arg_pos); 1705 PrintErrorWithKind(
1313 if (strcmp(action, "eval") == 0) { 1706 js, "RetainingPathCollected",
1314 if (js->num_arguments() > (arg_pos + 1)) { 1707 "attempt to find a retaining path for a collected object\n",
1315 PrintError(js, "expected at most %" Pd " arguments but found %" Pd "\n", 1708 js->num_arguments());
1316 arg_pos + 1, 1709 return true;
1317 js->num_arguments()); 1710 } else if (lookup_result == ObjectIdRing::kExpired) {
1711 PrintErrorWithKind(
1712 js, "RetainingPathExpired",
1713 "attempt to find a retaining path for an expired object\n",
1714 js->num_arguments());
1318 return true; 1715 return true;
1319 } 1716 }
1320 if (kind == ObjectIdRing::kCollected) { 1717 PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
1321 PrintErrorWithKind(js, "EvalCollected", 1718 target_id);
1322 "attempt to evaluate against collected object\n",
1323 js->num_arguments());
1324 return true;
1325 }
1326 if (kind == ObjectIdRing::kExpired) {
1327 PrintErrorWithKind(js, "EvalExpired",
1328 "attempt to evaluate against expired object\n",
1329 js->num_arguments());
1330 return true;
1331 }
1332 if (ContainsNonInstance(*obj)) {
1333 PrintError(js, "attempt to evaluate against internal VM object\n");
1334 return true;
1335 }
1336 const char* expr = js->LookupOption("expr");
1337 if (expr == NULL) {
1338 PrintError(js, "eval expects an 'expr' option\n",
1339 js->num_arguments());
1340 return true;
1341 }
1342 const String& expr_str = String::Handle(isolate, String::New(expr));
1343 ASSERT(obj->IsInstance() || obj->IsNull());
1344 Instance& instance = Instance::Handle();
1345 instance ^= obj->raw();
1346 const Object& result =
1347 Object::Handle(instance.Evaluate(expr_str,
1348 Array::empty_array(),
1349 Array::empty_array()));
1350 result.PrintJSON(js, true);
1351 return true; 1719 return true;
1352 } else if (strcmp(action, "retained") == 0) { 1720 }
1353 if (kind == ObjectIdRing::kCollected) { 1721 return PrintRetainingPath(isolate, &obj, limit, js);
1722 }
1723
1724
1725 static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) {
1726 const char* target_id = js->LookupOption("targetId");
1727 if (target_id == NULL) {
1728 PrintError(js, "Missing 'targetId' option");
1729 return true;
1730 }
1731 ObjectIdRing::LookupResult lookup_result;
1732 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id,
1733 &lookup_result));
1734 if (obj.raw() == Object::sentinel().raw()) {
1735 if (lookup_result == ObjectIdRing::kCollected) {
1354 PrintErrorWithKind( 1736 PrintErrorWithKind(
1355 js, "RetainedCollected", 1737 js, "RetainedCollected",
1356 "attempt to calculate size retained by a collected object\n", 1738 "attempt to calculate size retained by a collected object\n",
1357 js->num_arguments()); 1739 js->num_arguments());
1358 return true; 1740 return true;
1359 } 1741 } else if (lookup_result == ObjectIdRing::kExpired) {
1360 if (kind == ObjectIdRing::kExpired) {
1361 PrintErrorWithKind( 1742 PrintErrorWithKind(
1362 js, "RetainedExpired", 1743 js, "RetainedExpired",
1363 "attempt to calculate size retained by an expired object\n", 1744 "attempt to calculate size retained by an expired object\n",
1364 js->num_arguments()); 1745 js->num_arguments());
1365 return true; 1746 return true;
1366 } 1747 }
1748 PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
1749 target_id);
1750 return true;
1751 }
1752 if (obj.IsClass()) {
1753 const Class& cls = Class::Cast(obj);
1367 ObjectGraph graph(isolate); 1754 ObjectGraph graph(isolate);
1368 intptr_t retained_size = graph.SizeRetainedByInstance(*obj); 1755 intptr_t retained_size = graph.SizeRetainedByClass(cls.id());
1369 const Object& result = Object::Handle(Integer::New(retained_size)); 1756 const Object& result = Object::Handle(Integer::New(retained_size));
1370 result.PrintJSON(js, true); 1757 result.PrintJSON(js, true);
1371 return true; 1758 return true;
1372 } else if (strcmp(action, "retaining_path") == 0) {
1373 if (kind == ObjectIdRing::kCollected) {
1374 PrintErrorWithKind(
1375 js, "RetainingPathCollected",
1376 "attempt to find a retaining path for a collected object\n",
1377 js->num_arguments());
1378 return true;
1379 }
1380 if (kind == ObjectIdRing::kExpired) {
1381 PrintErrorWithKind(
1382 js, "RetainingPathExpired",
1383 "attempt to find a retaining path for an expired object\n",
1384 js->num_arguments());
1385 return true;
1386 }
1387 intptr_t limit;
1388 if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
1389 PrintError(js, "retaining_path expects a 'limit' option\n",
1390 js->num_arguments());
1391 return true;
1392 }
1393 return HandleRetainingPath(isolate, obj, limit, js);
1394 } else if (strcmp(action, "inbound_references") == 0) {
1395 if (kind == ObjectIdRing::kCollected) {
1396 PrintErrorWithKind(
1397 js, "InboundReferencesCollected",
1398 "attempt to find inbound references for a collected object\n",
1399 js->num_arguments());
1400 return true;
1401 }
1402 if (kind == ObjectIdRing::kExpired) {
1403 PrintErrorWithKind(
1404 js, "InboundReferencesExpired",
1405 "attempt to find inbound references for an expired object\n",
1406 js->num_arguments());
1407 return true;
1408 }
1409 intptr_t limit;
1410 if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
1411 PrintError(js, "inbound_references expects a 'limit' option\n",
1412 js->num_arguments());
1413 return true;
1414 }
1415 return HandleInboundReferences(isolate, obj, limit, js);
1416 } 1759 }
1417 1760 if (obj.IsInstance() || obj.IsNull()) {
1418 PrintError(js, "unrecognized action '%s'\n", action); 1761 // We don't use Instance::Cast here because it doesn't allow null.
1762 ObjectGraph graph(isolate);
1763 intptr_t retained_size = graph.SizeRetainedByInstance(obj);
1764 const Object& result = Object::Handle(Integer::New(retained_size));
1765 result.PrintJSON(js, true);
1766 return true;
1767 }
1768 PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
1769 "library, class, or instance", target_id);
1419 return true; 1770 return true;
1420 } 1771 }
1421 1772
1422 1773
1423 static bool HandleClassesClosures(Isolate* isolate, const Class& cls, 1774 static bool HandleClassesClosures(Isolate* isolate, const Class& cls,
1424 JSONStream* js) { 1775 JSONStream* js) {
1425 intptr_t id; 1776 intptr_t id;
1426 if (js->num_arguments() > 4) { 1777 if (js->num_arguments() > 4) {
1427 PrintError(js, "Command too long"); 1778 PrintError(js, "Command too long");
1428 return true; 1779 return true;
1429 } 1780 }
1430 if (!GetIntegerId(js->GetArgument(3), &id)) { 1781 if (!GetIntegerId(js->GetArgument(3), &id)) {
1431 PrintError(js, "Must specify collection object id: closures/id"); 1782 PrintError(js, "Must specify collection object id: closures/id");
1432 return true; 1783 return true;
1433 } 1784 }
1434 Function& func = Function::Handle(); 1785 Function& func = Function::Handle();
1435 func ^= cls.ClosureFunctionFromIndex(id); 1786 func ^= cls.ClosureFunctionFromIndex(id);
1436 if (func.IsNull()) { 1787 if (func.IsNull()) {
1437 PrintError(js, "Closure function %" Pd " not found", id); 1788 PrintError(js, "Closure function %" Pd " not found", id);
1438 return true; 1789 return true;
1439 } 1790 }
1440 func.PrintJSON(js, false); 1791 func.PrintJSON(js, false);
1441 return true; 1792 return true;
1442 } 1793 }
1443 1794
1444 1795
1445 static bool HandleClassesEval(Isolate* isolate, const Class& cls, 1796 static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) {
1446 JSONStream* js) { 1797 const char* target_id = js->LookupOption("targetId");
1447 if (js->num_arguments() > 3) { 1798 if (target_id == NULL) {
1448 PrintError(js, "Command too long"); 1799 PrintError(js, "Missing 'targetId' option");
1449 return true; 1800 return true;
1450 } 1801 }
1451 const char* expr = js->LookupOption("expr"); 1802 const char* expr = js->LookupOption("expression");
1452 if (expr == NULL) { 1803 if (expr == NULL) {
1453 PrintError(js, "eval expects an 'expr' option\n", 1804 PrintError(js, "Missing 'expression' option");
1454 js->num_arguments());
1455 return true; 1805 return true;
1456 } 1806 }
1457 const String& expr_str = String::Handle(isolate, String::New(expr)); 1807 const String& expr_str = String::Handle(isolate, String::New(expr));
1458 const Object& result = Object::Handle(cls.Evaluate(expr_str, 1808 ObjectIdRing::LookupResult lookup_result;
1459 Array::empty_array(), 1809 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id,
1460 Array::empty_array())); 1810 &lookup_result));
1461 result.PrintJSON(js, true); 1811 if (obj.raw() == Object::sentinel().raw()) {
1812 if (lookup_result == ObjectIdRing::kCollected) {
1813 PrintSentinel(js, "objects/collected", "<collected>");
1814 } else if (lookup_result == ObjectIdRing::kExpired) {
1815 PrintSentinel(js, "objects/expired", "<expired>");
1816 } else {
1817 PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
1818 target_id);
1819 }
1820 return true;
1821 }
1822 if (obj.IsLibrary()) {
1823 const Library& lib = Library::Cast(obj);
1824 const Object& result = Object::Handle(lib.Evaluate(expr_str,
1825 Array::empty_array(),
1826 Array::empty_array()));
1827 result.PrintJSON(js, true);
1828 return true;
1829 }
1830 if (obj.IsClass()) {
1831 const Class& cls = Class::Cast(obj);
1832 const Object& result = Object::Handle(cls.Evaluate(expr_str,
1833 Array::empty_array(),
1834 Array::empty_array()));
1835 result.PrintJSON(js, true);
1836 return true;
1837 }
1838 if ((obj.IsInstance() || obj.IsNull()) &&
1839 !ContainsNonInstance(obj)) {
1840 // We don't use Instance::Cast here because it doesn't allow null.
1841 Instance& instance = Instance::Handle(isolate);
1842 instance ^= obj.raw();
1843 const Object& result =
1844 Object::Handle(instance.Evaluate(expr_str,
1845 Array::empty_array(),
1846 Array::empty_array()));
1847 result.PrintJSON(js, true);
1848 return true;
1849 }
1850 PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
1851 "library, class, or instance", target_id);
1462 return true; 1852 return true;
1463 } 1853 }
1464 1854
1465 1855
1466 static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls, 1856 static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls,
1467 JSONStream* js) { 1857 JSONStream* js) {
1468 intptr_t id; 1858 intptr_t id;
1469 if (js->num_arguments() > 4) { 1859 if (js->num_arguments() > 4) {
1470 PrintError(js, "Command too long"); 1860 PrintError(js, "Command too long");
1471 return true; 1861 return true;
1472 } 1862 }
1473 if (!GetIntegerId(js->GetArgument(3), &id)) { 1863 if (!GetIntegerId(js->GetArgument(3), &id)) {
1474 PrintError(js, "Must specify collection object id: dispatchers/id"); 1864 PrintError(js, "Must specify collection object id: dispatchers/id");
1475 return true; 1865 return true;
1476 } 1866 }
1477 Function& func = Function::Handle(); 1867 Function& func = Function::Handle();
1478 func ^= cls.InvocationDispatcherFunctionFromIndex(id); 1868 func ^= cls.InvocationDispatcherFunctionFromIndex(id);
1479 if (func.IsNull()) { 1869 if (func.IsNull()) {
1480 PrintError(js, "Dispatcher %" Pd " not found", id); 1870 PrintError(js, "Dispatcher %" Pd " not found", id);
1481 return true; 1871 return true;
1482 } 1872 }
1483 func.PrintJSON(js, false); 1873 func.PrintJSON(js, false);
1484 return true; 1874 return true;
1485 } 1875 }
1486 1876
1487 1877
1488 static bool HandleClassesFunctionsCoverage(
1489 Isolate* isolate, const Function& func, JSONStream* js) {
1490 FunctionCoverageFilter filter(func);
1491 CodeCoverage::PrintJSON(isolate, js, &filter);
1492 return true;
1493 }
1494
1495
1496 static bool HandleFunctionSetSource( 1878 static bool HandleFunctionSetSource(
1497 Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) { 1879 Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) {
1498 if (js->LookupOption("source") == NULL) { 1880 if (js->LookupOption("source") == NULL) {
1499 PrintError(js, "set_source expects a 'source' option\n"); 1881 PrintError(js, "set_source expects a 'source' option\n");
1500 return true; 1882 return true;
1501 } 1883 }
1502 const String& source = 1884 const String& source =
1503 String::Handle(String::New(js->LookupOption("source"))); 1885 String::Handle(String::New(js->LookupOption("source")));
1504 const Object& result = Object::Handle( 1886 const Object& result = Object::Handle(
1505 Parser::ParseFunctionFromSource(cls, source)); 1887 Parser::ParseFunctionFromSource(cls, source));
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1539 Function& func = Function::Handle(cls.LookupFunction(id)); 1921 Function& func = Function::Handle(cls.LookupFunction(id));
1540 if (func.IsNull()) { 1922 if (func.IsNull()) {
1541 PrintError(js, "Function %s not found", encoded_id); 1923 PrintError(js, "Function %s not found", encoded_id);
1542 return true; 1924 return true;
1543 } 1925 }
1544 if (js->num_arguments() == 4) { 1926 if (js->num_arguments() == 4) {
1545 func.PrintJSON(js, false); 1927 func.PrintJSON(js, false);
1546 return true; 1928 return true;
1547 } else { 1929 } else {
1548 const char* subcommand = js->GetArgument(4); 1930 const char* subcommand = js->GetArgument(4);
1549 if (strcmp(subcommand, "coverage") == 0) { 1931 if (strcmp(subcommand, "set_source") == 0) {
1550 return HandleClassesFunctionsCoverage(isolate, func, js);
1551 } else if (strcmp(subcommand, "set_source") == 0) {
1552 return HandleFunctionSetSource(isolate, cls, func, js); 1932 return HandleFunctionSetSource(isolate, cls, func, js);
1553 } else { 1933 } else {
1554 PrintError(js, "Invalid sub command %s", subcommand); 1934 PrintError(js, "Invalid sub command %s", subcommand);
1555 return true; 1935 return true;
1556 } 1936 }
1557 } 1937 }
1558 UNREACHABLE(); 1938 UNREACHABLE();
1559 return true; 1939 return true;
1560 } 1940 }
1561 1941
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1610 jsobj.AddProperty("type", "TypeList"); 1990 jsobj.AddProperty("type", "TypeList");
1611 JSONArray members(&jsobj, "members"); 1991 JSONArray members(&jsobj, "members");
1612 const intptr_t num_types = cls.NumCanonicalTypes(); 1992 const intptr_t num_types = cls.NumCanonicalTypes();
1613 Type& type = Type::Handle(); 1993 Type& type = Type::Handle();
1614 for (intptr_t i = 0; i < num_types; i++) { 1994 for (intptr_t i = 0; i < num_types; i++) {
1615 type = cls.CanonicalTypeFromIndex(i); 1995 type = cls.CanonicalTypeFromIndex(i);
1616 members.AddValue(type); 1996 members.AddValue(type);
1617 } 1997 }
1618 return true; 1998 return true;
1619 } 1999 }
1620 ASSERT(js->num_arguments() >= 4); 2000 if (js->num_arguments() > 4) {
2001 PrintError(js, "Command too long");
2002 return true;
2003 }
2004 ASSERT(js->num_arguments() == 4);
1621 intptr_t id; 2005 intptr_t id;
1622 if (!GetIntegerId(js->GetArgument(3), &id)) { 2006 if (!GetIntegerId(js->GetArgument(3), &id)) {
1623 PrintError(js, "Must specify collection object id: types/id"); 2007 PrintError(js, "Must specify collection object id: types/id");
1624 return true; 2008 return true;
1625 } 2009 }
1626 Type& type = Type::Handle(); 2010 Type& type = Type::Handle();
1627 type ^= cls.CanonicalTypeFromIndex(id); 2011 type ^= cls.CanonicalTypeFromIndex(id);
1628 if (type.IsNull()) { 2012 if (type.IsNull()) {
1629 PrintError(js, "Canonical type %" Pd " not found", id); 2013 PrintError(js, "Canonical type %" Pd " not found", id);
1630 return true; 2014 return true;
1631 } 2015 }
1632 if (js->num_arguments() == 4) { 2016 type.PrintJSON(js, false);
1633 type.PrintJSON(js, false);
1634 return true;
1635 }
1636 return HandleInstanceCommands(isolate, &type, ObjectIdRing::kValid, js, 4);
1637 }
1638
1639
1640 static bool HandleClassesRetained(Isolate* isolate, const Class& cls,
1641 JSONStream* js) {
1642 if (js->num_arguments() != 3) {
1643 PrintError(js, "Command too long");
1644 return true;
1645 }
1646 ObjectGraph graph(isolate);
1647 intptr_t retained_size = graph.SizeRetainedByClass(cls.id());
1648 const Object& result = Object::Handle(Integer::New(retained_size));
1649 result.PrintJSON(js, true);
1650 return true; 2017 return true;
1651 } 2018 }
1652 2019
1653 2020
1654 class GetInstancesVisitor : public ObjectGraph::Visitor { 2021 class GetInstancesVisitor : public ObjectGraph::Visitor {
1655 public: 2022 public:
1656 GetInstancesVisitor(const Class& cls, const Array& storage) 2023 GetInstancesVisitor(const Class& cls, const Array& storage)
1657 : cls_(cls), storage_(storage), count_(0) {} 2024 : cls_(cls), storage_(storage), count_(0) {}
1658 2025
1659 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { 2026 virtual Direction VisitObject(ObjectGraph::StackIterator* it) {
(...skipping 16 matching lines...) Expand all
1676 2043
1677 intptr_t count() const { return count_; } 2044 intptr_t count() const { return count_; }
1678 2045
1679 private: 2046 private:
1680 const Class& cls_; 2047 const Class& cls_;
1681 const Array& storage_; 2048 const Array& storage_;
1682 intptr_t count_; 2049 intptr_t count_;
1683 }; 2050 };
1684 2051
1685 2052
1686 static bool HandleClassesInstances(Isolate* isolate, const Class& cls, 2053 static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) {
1687 JSONStream* js) { 2054 const char* target_id = js->LookupOption("classId");
1688 if (js->num_arguments() != 3) { 2055 if (target_id == NULL) {
1689 PrintError(js, "Command too long"); 2056 PrintError(js, "Missing 'classId' option");
2057 return true;
2058 }
2059 const char* limit_cstr = js->LookupOption("limit");
2060 if (target_id == NULL) {
2061 PrintError(js, "Missing 'limit' option");
1690 return true; 2062 return true;
1691 } 2063 }
1692 intptr_t limit; 2064 intptr_t limit;
1693 if (!GetIntegerId(js->LookupOption("limit"), &limit)) { 2065 if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
1694 PrintError(js, "instances expects a 'limit' option\n", 2066 PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
1695 js->num_arguments());
1696 return true; 2067 return true;
1697 } 2068 }
2069 const Object& obj =
2070 Object::Handle(LookupHeapObject(isolate, target_id, NULL));
2071 if (obj.raw() == Object::sentinel().raw() ||
2072 !obj.IsClass()) {
2073 PrintError(js, "Invalid 'classId' value: no class with id '%s'", target_id);
2074 return true;
2075 }
2076 const Class& cls = Class::Cast(obj);
1698 Array& storage = Array::Handle(Array::New(limit)); 2077 Array& storage = Array::Handle(Array::New(limit));
1699 GetInstancesVisitor visitor(cls, storage); 2078 GetInstancesVisitor visitor(cls, storage);
1700 ObjectGraph graph(isolate); 2079 ObjectGraph graph(isolate);
1701 graph.IterateObjects(&visitor); 2080 graph.IterateObjects(&visitor);
1702 intptr_t count = visitor.count(); 2081 intptr_t count = visitor.count();
1703 if (count < limit) { 2082 if (count < limit) {
1704 // Truncate the list using utility method for GrowableObjectArray. 2083 // Truncate the list using utility method for GrowableObjectArray.
1705 GrowableObjectArray& wrapper = GrowableObjectArray::Handle( 2084 GrowableObjectArray& wrapper = GrowableObjectArray::Handle(
1706 GrowableObjectArray::New(storage)); 2085 GrowableObjectArray::New(storage));
1707 wrapper.SetLength(count); 2086 wrapper.SetLength(count);
1708 storage = Array::MakeArray(wrapper); 2087 storage = Array::MakeArray(wrapper);
1709 } 2088 }
1710 JSONObject jsobj(js); 2089 JSONObject jsobj(js);
1711 jsobj.AddProperty("type", "InstanceSet"); 2090 jsobj.AddProperty("type", "InstanceSet");
1712 jsobj.AddProperty("id", "instance_set"); 2091 jsobj.AddProperty("id", "instance_set");
1713 jsobj.AddProperty("totalCount", count); 2092 jsobj.AddProperty("totalCount", count);
1714 jsobj.AddProperty("sampleCount", storage.Length()); 2093 jsobj.AddProperty("sampleCount", storage.Length());
1715 jsobj.AddProperty("sample", storage); 2094 jsobj.AddProperty("sample", storage);
1716 return true; 2095 return true;
1717 } 2096 }
1718 2097
1719 2098
1720 static bool HandleClassesCoverage(Isolate* isolate,
1721 const Class& cls,
1722 JSONStream* stream) {
1723 ClassCoverageFilter cf(cls);
1724 CodeCoverage::PrintJSON(isolate, stream, &cf);
1725 return true;
1726 }
1727
1728
1729 static bool HandleClasses(Isolate* isolate, JSONStream* js) { 2099 static bool HandleClasses(Isolate* isolate, JSONStream* js) {
1730 if (js->num_arguments() == 1) { 2100 if (js->num_arguments() == 1) {
1731 ClassTable* table = isolate->class_table(); 2101 ClassTable* table = isolate->class_table();
1732 JSONObject jsobj(js); 2102 JSONObject jsobj(js);
1733 table->PrintToJSONObject(&jsobj); 2103 table->PrintToJSONObject(&jsobj);
1734 return true; 2104 return true;
1735 } 2105 }
1736 ASSERT(js->num_arguments() >= 2); 2106 ASSERT(js->num_arguments() >= 2);
1737 intptr_t id; 2107 intptr_t id;
1738 if (!GetIntegerId(js->GetArgument(1), &id)) { 2108 if (!GetIntegerId(js->GetArgument(1), &id)) {
1739 PrintError(js, "Must specify collection object id: /classes/id"); 2109 PrintError(js, "Must specify collection object id: /classes/id");
1740 return true; 2110 return true;
1741 } 2111 }
1742 ClassTable* table = isolate->class_table(); 2112 ClassTable* table = isolate->class_table();
1743 if (!table->IsValidIndex(id)) { 2113 if (!table->IsValidIndex(id)) {
1744 PrintError(js, "%" Pd " is not a valid class id.", id); 2114 PrintError(js, "%" Pd " is not a valid class id.", id);
1745 return true; 2115 return true;
1746 } 2116 }
1747 Class& cls = Class::Handle(table->At(id)); 2117 Class& cls = Class::Handle(table->At(id));
1748 if (js->num_arguments() == 2) { 2118 if (js->num_arguments() == 2) {
1749 cls.PrintJSON(js, false); 2119 cls.PrintJSON(js, false);
1750 return true; 2120 return true;
1751 } else if (js->num_arguments() >= 3) { 2121 } else if (js->num_arguments() >= 3) {
1752 const char* second = js->GetArgument(2); 2122 const char* second = js->GetArgument(2);
1753 if (strcmp(second, "eval") == 0) { 2123 if (strcmp(second, "closures") == 0) {
1754 return HandleClassesEval(isolate, cls, js);
1755 } else if (strcmp(second, "closures") == 0) {
1756 return HandleClassesClosures(isolate, cls, js); 2124 return HandleClassesClosures(isolate, cls, js);
1757 } else if (strcmp(second, "fields") == 0) { 2125 } else if (strcmp(second, "fields") == 0) {
1758 return HandleClassesFields(isolate, cls, js); 2126 return HandleClassesFields(isolate, cls, js);
1759 } else if (strcmp(second, "functions") == 0) { 2127 } else if (strcmp(second, "functions") == 0) {
1760 return HandleClassesFunctions(isolate, cls, js); 2128 return HandleClassesFunctions(isolate, cls, js);
1761 } else if (strcmp(second, "implicit_closures") == 0) { 2129 } else if (strcmp(second, "implicit_closures") == 0) {
1762 return HandleClassesImplicitClosures(isolate, cls, js); 2130 return HandleClassesImplicitClosures(isolate, cls, js);
1763 } else if (strcmp(second, "dispatchers") == 0) { 2131 } else if (strcmp(second, "dispatchers") == 0) {
1764 return HandleClassesDispatchers(isolate, cls, js); 2132 return HandleClassesDispatchers(isolate, cls, js);
1765 } else if (strcmp(second, "types") == 0) { 2133 } else if (strcmp(second, "types") == 0) {
1766 return HandleClassesTypes(isolate, cls, js); 2134 return HandleClassesTypes(isolate, cls, js);
1767 } else if (strcmp(second, "retained") == 0) {
1768 return HandleClassesRetained(isolate, cls, js);
1769 } else if (strcmp(second, "instances") == 0) {
1770 return HandleClassesInstances(isolate, cls, js);
1771 } else if (strcmp(second, "coverage") == 0) {
1772 return HandleClassesCoverage(isolate, cls, js);
1773 } else { 2135 } else {
1774 PrintError(js, "Invalid sub collection %s", second); 2136 PrintError(js, "Invalid sub collection %s", second);
1775 return true; 2137 return true;
1776 } 2138 }
1777 } 2139 }
1778 UNREACHABLE(); 2140 UNREACHABLE();
1779 return true; 2141 return true;
1780 } 2142 }
1781 2143
1782 2144
1783 static bool HandleLibrariesEval(Isolate* isolate, const Library& lib, 2145 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
1784 JSONStream* js) { 2146 if (!js->HasOption("targetId")) {
1785 if (js->num_arguments() > 3) { 2147 CodeCoverage::PrintJSON(isolate, js, NULL);
1786 PrintError(js, "Command too long");
1787 return true; 2148 return true;
1788 } 2149 }
1789 const char* expr = js->LookupOption("expr"); 2150 const char* target_id = js->LookupOption("targetId");
1790 if (expr == NULL) { 2151 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL));
1791 PrintError(js, "eval expects an 'expr' option\n", 2152 if (obj.raw() == Object::sentinel().raw()) {
1792 js->num_arguments()); 2153 PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
2154 target_id);
1793 return true; 2155 return true;
1794 } 2156 }
1795 const String& expr_str = String::Handle(isolate, String::New(expr)); 2157 if (obj.IsScript()) {
1796 const Object& result = Object::Handle(lib.Evaluate(expr_str, 2158 ScriptCoverageFilter sf(Script::Cast(obj));
1797 Array::empty_array(), 2159 CodeCoverage::PrintJSON(isolate, js, &sf);
1798 Array::empty_array())); 2160 return true;
1799 result.PrintJSON(js, true); 2161 }
2162 if (obj.IsLibrary()) {
2163 LibraryCoverageFilter lf(Library::Cast(obj));
2164 CodeCoverage::PrintJSON(isolate, js, &lf);
2165 return true;
2166 }
2167 if (obj.IsClass()) {
2168 ClassCoverageFilter cf(Class::Cast(obj));
2169 CodeCoverage::PrintJSON(isolate, js, &cf);
2170 return true;
2171 }
2172 if (obj.IsFunction()) {
2173 FunctionCoverageFilter ff(Function::Cast(obj));
2174 CodeCoverage::PrintJSON(isolate, js, &ff);
2175 return true;
2176 }
2177 PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
2178 "script, library, class, or function", target_id);
1800 return true; 2179 return true;
1801 } 2180 }
1802 2181
1803 2182
1804 static bool HandleLibrariesScriptsCoverage( 2183 static bool HandleIsolateAddBreakpoint(Isolate* isolate, JSONStream* js) {
1805 Isolate* isolate, const Script& script, JSONStream* js) {
1806 ScriptCoverageFilter sf(script);
1807 CodeCoverage::PrintJSON(isolate, js, &sf);
1808 return true;
1809 }
1810
1811
1812 static bool HandleLibrariesScriptsSetBreakpoint(
1813 Isolate* isolate, const Script& script, JSONStream* js) {
1814 if (!js->HasOption("line")) { 2184 if (!js->HasOption("line")) {
1815 PrintError(js, "Missing 'line' option"); 2185 PrintError(js, "Missing 'line' option");
1816 return true; 2186 return true;
1817 } 2187 }
1818 const char* line_option = js->LookupOption("line"); 2188 const char* line_option = js->LookupOption("line");
1819 intptr_t line = -1; 2189 intptr_t line = -1;
1820 if (!GetIntegerId(line_option, &line)) { 2190 if (!GetIntegerId(line_option, &line)) {
1821 PrintError(js, "Invalid 'line' value: %s", line_option); 2191 PrintError(js, "Invalid 'line' value: %s is not an integer", line_option);
1822 return true; 2192 return true;
1823 } 2193 }
2194 const char* script_id = js->LookupOption("script");
2195 Object& obj = Object::Handle(LookupHeapObject(isolate, script_id, NULL));
2196 if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
2197 PrintError(js, "Invalid 'script' value: no script with id '%s'", script_id);
2198 return true;
2199 }
2200 const Script& script = Script::Cast(obj);
1824 const String& script_url = String::Handle(script.url()); 2201 const String& script_url = String::Handle(script.url());
1825 SourceBreakpoint* bpt = 2202 SourceBreakpoint* bpt =
1826 isolate->debugger()->SetBreakpointAtLine(script_url, line); 2203 isolate->debugger()->SetBreakpointAtLine(script_url, line);
1827 if (bpt == NULL) { 2204 if (bpt == NULL) {
1828 PrintError(js, "Unable to set breakpoint at line %s", line_option); 2205 PrintError(js, "Unable to set breakpoint at line %s", line_option);
1829 return true; 2206 return true;
1830 } 2207 }
1831 bpt->PrintJSON(js); 2208 bpt->PrintJSON(js);
1832 return true; 2209 return true;
1833 } 2210 }
1834 2211
1835 2212
2213 static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) {
2214 if (!js->HasOption("breakpointId")) {
2215 PrintError(js, "Missing 'breakpointId' option");
2216 return true;
2217 }
2218 const char* bpt_id = js->LookupOption("breakpointId");
2219 SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
2220 if (bpt == NULL) {
2221 fprintf(stderr, "ERROR1");
2222 PrintError(js, "Invalid 'breakpointId' value: no breakpoint with id '%s'",
2223 bpt_id);
2224 return true;
2225 }
2226 isolate->debugger()->RemoveBreakpoint(bpt->id());
2227
2228 fprintf(stderr, "SUCCESS");
2229 // TODO(turnidge): Consider whether the 'Success' type is proper.
2230 JSONObject jsobj(js);
2231 jsobj.AddProperty("type", "Success");
2232 jsobj.AddProperty("id", "");
2233 return true;
2234 }
2235
2236
1836 static bool HandleLibrariesScripts(Isolate* isolate, 2237 static bool HandleLibrariesScripts(Isolate* isolate,
1837 const Library& lib, 2238 const Library& lib,
1838 JSONStream* js) { 2239 JSONStream* js) {
1839 if (js->num_arguments() > 5) { 2240 if (js->num_arguments() > 5) {
1840 PrintError(js, "Command too long"); 2241 PrintError(js, "Command too long");
1841 return true; 2242 return true;
1842 } else if (js->num_arguments() < 4) { 2243 } else if (js->num_arguments() < 4) {
1843 PrintError(js, "Must specify collection object id: scripts/id"); 2244 PrintError(js, "Must specify collection object id: scripts/id");
1844 return true; 2245 return true;
1845 } 2246 }
(...skipping 11 matching lines...) Expand all
1857 ASSERT(!script.IsNull()); 2258 ASSERT(!script.IsNull());
1858 script_url ^= script.url(); 2259 script_url ^= script.url();
1859 if (script_url.Equals(requested_url)) { 2260 if (script_url.Equals(requested_url)) {
1860 break; 2261 break;
1861 } 2262 }
1862 } 2263 }
1863 if (i == loaded_scripts.Length()) { 2264 if (i == loaded_scripts.Length()) {
1864 PrintError(js, "Script %s not found", requested_url.ToCString()); 2265 PrintError(js, "Script %s not found", requested_url.ToCString());
1865 return true; 2266 return true;
1866 } 2267 }
1867 if (js->num_arguments() == 4) { 2268 if (js->num_arguments() > 4) {
1868 script.PrintJSON(js, false); 2269 PrintError(js, "Command too long");
1869 return true; 2270 return true;
1870 } else {
1871 const char* subcollection = js->GetArgument(4);
1872 if (strcmp(subcollection, "coverage") == 0) {
1873 return HandleLibrariesScriptsCoverage(isolate, script, js);
1874 } else if (strcmp(subcollection, "setBreakpoint") == 0) {
1875 return HandleLibrariesScriptsSetBreakpoint(isolate, script, js);
1876 } else {
1877 PrintError(js, "Invalid sub collection %s", subcollection);
1878 return true;
1879 }
1880 } 2271 }
1881 UNREACHABLE(); 2272 script.PrintJSON(js, false);
1882 return true; 2273 return true;
1883 } 2274 }
1884 2275
1885
1886 static bool HandleLibrariesCoverage(Isolate* isolate,
1887 const Library& lib,
1888 JSONStream* js) {
1889 LibraryCoverageFilter lf(lib);
1890 CodeCoverage::PrintJSON(isolate, js, &lf);
1891 return true;
1892 }
1893
1894 2276
1895 static bool HandleLibraries(Isolate* isolate, JSONStream* js) { 2277 static bool HandleLibraries(Isolate* isolate, JSONStream* js) {
1896 // TODO(johnmccutchan): Support fields and functions on libraries. 2278 // TODO(johnmccutchan): Support fields and functions on libraries.
1897 REQUIRE_COLLECTION_ID("libraries"); 2279 REQUIRE_COLLECTION_ID("libraries");
1898 const GrowableObjectArray& libs = 2280 const GrowableObjectArray& libs =
1899 GrowableObjectArray::Handle(isolate->object_store()->libraries()); 2281 GrowableObjectArray::Handle(isolate->object_store()->libraries());
1900 ASSERT(!libs.IsNull()); 2282 ASSERT(!libs.IsNull());
1901 intptr_t id = 0; 2283 intptr_t id = 0;
1902 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1), 2284 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1),
1903 id, js); 2285 id, js);
1904 Library& lib = Library::Handle(); 2286 Library& lib = Library::Handle();
1905 lib ^= libs.At(id); 2287 lib ^= libs.At(id);
1906 ASSERT(!lib.IsNull()); 2288 ASSERT(!lib.IsNull());
1907 if (js->num_arguments() == 2) { 2289 if (js->num_arguments() == 2) {
1908 lib.PrintJSON(js, false); 2290 lib.PrintJSON(js, false);
1909 return true; 2291 return true;
1910 } else if (js->num_arguments() >= 3) { 2292 } else if (js->num_arguments() >= 3) {
1911 const char* second = js->GetArgument(2); 2293 const char* second = js->GetArgument(2);
1912 if (strcmp(second, "eval") == 0) { 2294 if (strcmp(second, "scripts") == 0) {
1913 return HandleLibrariesEval(isolate, lib, js);
1914 } else if (strcmp(second, "scripts") == 0) {
1915 return HandleLibrariesScripts(isolate, lib, js); 2295 return HandleLibrariesScripts(isolate, lib, js);
1916 } else if (strcmp(second, "coverage") == 0) {
1917 return HandleLibrariesCoverage(isolate, lib, js);
1918 } else { 2296 } else {
1919 PrintError(js, "Invalid sub collection %s", second); 2297 PrintError(js, "Invalid sub collection %s", second);
1920 return true; 2298 return true;
1921 } 2299 }
1922 } 2300 }
1923 UNREACHABLE(); 2301 UNREACHABLE();
1924 return true; 2302 return true;
1925 } 2303 }
1926 2304
1927 2305
1928 static void PrintSentinel(JSONStream* js,
1929 const char* id,
1930 const char* preview) {
1931 JSONObject jsobj(js);
1932 jsobj.AddProperty("type", "Sentinel");
1933 jsobj.AddProperty("id", id);
1934 jsobj.AddProperty("valueAsString", preview);
1935 }
1936
1937
1938 static RawObject* LookupObjectId(Isolate* isolate,
1939 const char* arg,
1940 ObjectIdRing::LookupResult* kind) {
1941 *kind = ObjectIdRing::kValid;
1942 if (strncmp(arg, "int-", 4) == 0) {
1943 arg += 4;
1944 int64_t value = 0;
1945 if (!OS::StringToInt64(arg, &value) ||
1946 !Smi::IsValid(value)) {
1947 *kind = ObjectIdRing::kInvalid;
1948 return Object::null();
1949 }
1950 const Integer& obj =
1951 Integer::Handle(isolate, Smi::New(static_cast<intptr_t>(value)));
1952 return obj.raw();
1953 } else if (strcmp(arg, "bool-true") == 0) {
1954 return Bool::True().raw();
1955 } else if (strcmp(arg, "bool-false") == 0) {
1956 return Bool::False().raw();
1957 } else if (strcmp(arg, "null") == 0) {
1958 return Object::null();
1959 } else if (strcmp(arg, "not-initialized") == 0) {
1960 return Object::sentinel().raw();
1961 } else if (strcmp(arg, "being-initialized") == 0) {
1962 return Object::transition_sentinel().raw();
1963 }
1964
1965 ObjectIdRing* ring = isolate->object_id_ring();
1966 ASSERT(ring != NULL);
1967 intptr_t id = -1;
1968 if (!GetIntegerId(arg, &id)) {
1969 *kind = ObjectIdRing::kInvalid;
1970 return Object::null();
1971 }
1972 return ring->GetObjectForId(id, kind);
1973 }
1974
1975
1976 static RawClass* GetMetricsClass(Isolate* isolate) { 2306 static RawClass* GetMetricsClass(Isolate* isolate) {
1977 const Library& prof_lib = 2307 const Library& prof_lib =
1978 Library::Handle(isolate, Library::ProfilerLibrary()); 2308 Library::Handle(isolate, Library::ProfilerLibrary());
1979 ASSERT(!prof_lib.IsNull()); 2309 ASSERT(!prof_lib.IsNull());
1980 const String& metrics_cls_name = 2310 const String& metrics_cls_name =
1981 String::Handle(isolate, String::New("Metrics")); 2311 String::Handle(isolate, String::New("Metrics"));
1982 ASSERT(!metrics_cls_name.IsNull()); 2312 ASSERT(!metrics_cls_name.IsNull());
1983 const Class& metrics_cls = 2313 const Class& metrics_cls =
1984 Class::Handle(isolate, prof_lib.LookupClass(metrics_cls_name)); 2314 Class::Handle(isolate, prof_lib.LookupClass(metrics_cls_name));
1985 ASSERT(!metrics_cls.IsNull()); 2315 ASSERT(!metrics_cls.IsNull());
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
2088 if (js->num_arguments() > 2) { 2418 if (js->num_arguments() > 2) {
2089 PrintError(js, "Command too long"); 2419 PrintError(js, "Command too long");
2090 return true; 2420 return true;
2091 } 2421 }
2092 return HandleMetric(isolate, js, arg); 2422 return HandleMetric(isolate, js, arg);
2093 } 2423 }
2094 2424
2095 2425
2096 static bool HandleObjects(Isolate* isolate, JSONStream* js) { 2426 static bool HandleObjects(Isolate* isolate, JSONStream* js) {
2097 REQUIRE_COLLECTION_ID("objects"); 2427 REQUIRE_COLLECTION_ID("objects");
2098 if (js->num_arguments() < 2) { 2428 if (js->num_arguments() != 2) {
2099 PrintError(js, "expected at least 2 arguments but found %" Pd "\n", 2429 PrintError(js, "expected at least 2 arguments but found %" Pd "\n",
2100 js->num_arguments()); 2430 js->num_arguments());
2101 return true; 2431 return true;
2102 } 2432 }
2103 const char* arg = js->GetArgument(1); 2433 const char* arg = js->GetArgument(1);
2104 2434
2105 // Handle special non-objects first. 2435 // Handle special non-objects first.
2106 if (strcmp(arg, "optimized-out") == 0) { 2436 if (strcmp(arg, "optimized-out") == 0) {
2107 if (js->num_arguments() > 2) { 2437 if (js->num_arguments() > 2) {
2108 PrintError(js, "expected at most 2 arguments but found %" Pd "\n", 2438 PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
(...skipping 23 matching lines...) Expand all
2132 } 2462 }
2133 2463
2134 // Lookup the object. 2464 // Lookup the object.
2135 Object& obj = Object::Handle(isolate); 2465 Object& obj = Object::Handle(isolate);
2136 ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid; 2466 ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
2137 obj = LookupObjectId(isolate, arg, &kind); 2467 obj = LookupObjectId(isolate, arg, &kind);
2138 if (kind == ObjectIdRing::kInvalid) { 2468 if (kind == ObjectIdRing::kInvalid) {
2139 PrintError(js, "unrecognized object id '%s'", arg); 2469 PrintError(js, "unrecognized object id '%s'", arg);
2140 return true; 2470 return true;
2141 } 2471 }
2142 if (js->num_arguments() == 2) { 2472
2143 // Print. 2473 // Print.
2144 if (kind == ObjectIdRing::kCollected) { 2474 if (kind == ObjectIdRing::kCollected) {
2145 // The object has been collected by the gc. 2475 // The object has been collected by the gc.
2146 PrintSentinel(js, "objects/collected", "<collected>"); 2476 PrintSentinel(js, "objects/collected", "<collected>");
2147 return true; 2477 return true;
2148 } else if (kind == ObjectIdRing::kExpired) { 2478 } else if (kind == ObjectIdRing::kExpired) {
2149 // The object id has expired. 2479 // The object id has expired.
2150 PrintSentinel(js, "objects/expired", "<expired>"); 2480 PrintSentinel(js, "objects/expired", "<expired>");
2151 return true;
2152 }
2153 obj.PrintJSON(js, false);
2154 return true; 2481 return true;
2155 } 2482 }
2156 return HandleInstanceCommands(isolate, &obj, kind, js, 2); 2483 obj.PrintJSON(js, false);
2484 return true;
2157 } 2485 }
2158 2486
2159 2487
2160 static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { 2488 static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) {
2161 JSONObject jsobj(js); 2489 JSONObject jsobj(js);
2162 jsobj.AddProperty("type", "ScriptList"); 2490 jsobj.AddProperty("type", "ScriptList");
2163 jsobj.AddProperty("id", "scripts"); 2491 jsobj.AddProperty("id", "scripts");
2164 JSONArray members(&jsobj, "members"); 2492 JSONArray members(&jsobj, "members");
2165 const GrowableObjectArray& libs = 2493 const GrowableObjectArray& libs =
2166 GrowableObjectArray::Handle(isolate->object_store()->libraries()); 2494 GrowableObjectArray::Handle(isolate->object_store()->libraries());
(...skipping 19 matching lines...) Expand all
2186 static bool HandleScripts(Isolate* isolate, JSONStream* js) { 2514 static bool HandleScripts(Isolate* isolate, JSONStream* js) {
2187 if (js->num_arguments() == 1) { 2515 if (js->num_arguments() == 1) {
2188 // Enumerate all scripts. 2516 // Enumerate all scripts.
2189 return HandleScriptsEnumerate(isolate, js); 2517 return HandleScriptsEnumerate(isolate, js);
2190 } 2518 }
2191 PrintError(js, "Command too long"); 2519 PrintError(js, "Command too long");
2192 return true; 2520 return true;
2193 } 2521 }
2194 2522
2195 2523
2196 static bool HandleDebugResume(Isolate* isolate, 2524 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) {
2197 const char* step_option, 2525 const char* step_option = js->LookupOption("step");
2198 JSONStream* js) {
2199 if (isolate->message_handler()->paused_on_start()) { 2526 if (isolate->message_handler()->paused_on_start()) {
2200 isolate->message_handler()->set_pause_on_start(false); 2527 isolate->message_handler()->set_pause_on_start(false);
2201 JSONObject jsobj(js); 2528 JSONObject jsobj(js);
2202 jsobj.AddProperty("type", "Success"); 2529 jsobj.AddProperty("type", "Success");
2203 jsobj.AddProperty("id", ""); 2530 jsobj.AddProperty("id", "");
2204 return true; 2531 return true;
2205 } 2532 }
2206 if (isolate->message_handler()->paused_on_exit()) { 2533 if (isolate->message_handler()->paused_on_exit()) {
2207 isolate->message_handler()->set_pause_on_exit(false); 2534 isolate->message_handler()->set_pause_on_exit(false);
2208 JSONObject jsobj(js); 2535 JSONObject jsobj(js);
(...skipping 19 matching lines...) Expand all
2228 jsobj.AddProperty("type", "Success"); 2555 jsobj.AddProperty("type", "Success");
2229 jsobj.AddProperty("id", ""); 2556 jsobj.AddProperty("id", "");
2230 return true; 2557 return true;
2231 } 2558 }
2232 2559
2233 PrintError(js, "VM was not paused"); 2560 PrintError(js, "VM was not paused");
2234 return true; 2561 return true;
2235 } 2562 }
2236 2563
2237 2564
2238 static bool HandleDebug(Isolate* isolate, JSONStream* js) { 2565 static bool HandleIsolateGetBreakpoints(Isolate* isolate, JSONStream* js) {
2239 if (js->num_arguments() == 1) { 2566 JSONObject jsobj(js);
2240 PrintError(js, "Must specify a subcommand"); 2567 jsobj.AddProperty("type", "BreakpointList");
2241 return true; 2568 JSONArray jsarr(&jsobj, "breakpoints");
2242 } 2569 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
2243 const char* command = js->GetArgument(1); 2570 return true;
2244 if (strcmp(command, "breakpoints") == 0) {
2245 if (js->num_arguments() == 2) {
2246 // Print breakpoint list.
2247 JSONObject jsobj(js);
2248 jsobj.AddProperty("type", "BreakpointList");
2249 jsobj.AddProperty("id", "debug/breakpoints");
2250 JSONArray jsarr(&jsobj, "breakpoints");
2251 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
2252 return true;
2253 } else {
2254 intptr_t id = 0;
2255 SourceBreakpoint* bpt = NULL;
2256 if (GetIntegerId(js->GetArgument(2), &id)) {
2257 bpt = isolate->debugger()->GetBreakpointById(id);
2258 }
2259 if (bpt == NULL) {
2260 PrintError(js, "Unrecognized breakpoint id: %s", js->GetArgument(2));
2261 return true;
2262 }
2263 if (js->num_arguments() == 3) {
2264 // Print individual breakpoint.
2265 bpt->PrintJSON(js);
2266 return true;
2267 } else if (js->num_arguments() == 4) {
2268 const char* sub_command = js->GetArgument(3);
2269 if (strcmp(sub_command, "clear") == 0) {
2270 // Clear this breakpoint.
2271 isolate->debugger()->RemoveBreakpoint(id);
2272
2273 JSONObject jsobj(js);
2274 jsobj.AddProperty("type", "Success");
2275 jsobj.AddProperty("id", "");
2276 return true;
2277 } else {
2278 PrintError(js, "Unrecognized subcommand: %s", sub_command);
2279 return true;
2280 }
2281 } else {
2282 PrintError(js, "Command too long");
2283 return true;
2284 }
2285 }
2286 } else if (strcmp(command, "pause") == 0) {
2287 if (js->num_arguments() == 2) {
2288 // TODO(turnidge): Don't double-interrupt the isolate here.
2289 isolate->ScheduleInterrupts(Isolate::kApiInterrupt);
2290 JSONObject jsobj(js);
2291 jsobj.AddProperty("type", "Success");
2292 jsobj.AddProperty("id", "");
2293 return true;
2294 } else {
2295 PrintError(js, "Command too long");
2296 return true;
2297 }
2298 } else if (strcmp(command, "resume") == 0) {
2299 if (js->num_arguments() == 2) {
2300 const char* step_option = js->LookupOption("step");
2301 return HandleDebugResume(isolate, step_option, js);
2302 } else {
2303 PrintError(js, "Command too long");
2304 return true;
2305 }
2306 } else {
2307 PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1));
2308 return true;
2309 }
2310 } 2571 }
2311 2572
2312 2573
2574 static bool HandleIsolatePause(Isolate* isolate, JSONStream* js) {
2575 // TODO(turnidge): Don't double-interrupt the isolate here.
2576 isolate->ScheduleInterrupts(Isolate::kApiInterrupt);
2577 JSONObject jsobj(js);
2578 jsobj.AddProperty("type", "Success");
2579 jsobj.AddProperty("id", "");
2580 return true;
2581 }
2582
2583
2313 static bool HandleNullCode(uintptr_t pc, JSONStream* js) { 2584 static bool HandleNullCode(uintptr_t pc, JSONStream* js) {
2314 // TODO(turnidge): Consider adding/using Object::null_code() for 2585 // TODO(turnidge): Consider adding/using Object::null_code() for
2315 // consistent "type". 2586 // consistent "type".
2316 Object::null_object().PrintJSON(js, false); 2587 Object::null_object().PrintJSON(js, false);
2317 return true; 2588 return true;
2318 } 2589 }
2319 2590
2320 2591
2321 static bool HandleCode(Isolate* isolate, JSONStream* js) { 2592 static bool HandleCode(Isolate* isolate, JSONStream* js) {
2322 REQUIRE_COLLECTION_ID("code"); 2593 REQUIRE_COLLECTION_ID("code");
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
2366 Code& code = Code::Handle(Code::FindCode(pc, timestamp)); 2637 Code& code = Code::Handle(Code::FindCode(pc, timestamp));
2367 if (!code.IsNull()) { 2638 if (!code.IsNull()) {
2368 code.PrintJSON(js, false); 2639 code.PrintJSON(js, false);
2369 return true; 2640 return true;
2370 } 2641 }
2371 PrintError(js, "Could not find code with id: %s", command); 2642 PrintError(js, "Could not find code with id: %s", command);
2372 return true; 2643 return true;
2373 } 2644 }
2374 2645
2375 2646
2376 static bool HandleProfile(Isolate* isolate, JSONStream* js) { 2647 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
2377 if (js->num_arguments() == 2) { 2648 JSONObject miniProfile(js);
2378 const char* sub_command = js->GetArgument(1); 2649 miniProfile.AddProperty("type", "TagProfile");
2379 if (!strcmp(sub_command, "tag")) { 2650 miniProfile.AddProperty("id", "profile/tag");
2380 { 2651 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile);
2381 JSONObject miniProfile(js); 2652 return true;
2382 miniProfile.AddProperty("type", "TagProfile"); 2653 }
2383 miniProfile.AddProperty("id", "profile/tag"); 2654
2384 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile); 2655 static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
2385 }
2386 return true;
2387 } else {
2388 PrintError(js, "Unrecognized subcommand '%s'", sub_command);
2389 return true;
2390 }
2391 }
2392 // A full profile includes disassembly of all Dart code objects. 2656 // A full profile includes disassembly of all Dart code objects.
2393 // TODO(johnmccutchan): Add sub command to trigger full code dump. 2657 // TODO(johnmccutchan): Add sub command to trigger full code dump.
2394 bool full_profile = false; 2658 bool full_profile = false;
2395 const char* tags_option = js->LookupOption("tags"); 2659 const char* tags_option = js->LookupOption("tags");
2396 Profiler::TagOrder tag_order = Profiler::kUserVM; 2660 Profiler::TagOrder tag_order = Profiler::kUserVM;
2397 if (js->HasOption("tags")) { 2661 if (js->HasOption("tags")) {
2398 if (js->OptionIs("tags", "hide")) { 2662 if (js->OptionIs("tags", "None")) {
2399 tag_order = Profiler::kNoTags; 2663 tag_order = Profiler::kNoTags;
2400 } else if (js->OptionIs("tags", "uv")) { 2664 } else if (js->OptionIs("tags", "UserVM")) {
2401 tag_order = Profiler::kUserVM; 2665 tag_order = Profiler::kUserVM;
2402 } else if (js->OptionIs("tags", "u")) { 2666 } else if (js->OptionIs("tags", "UserOnly")) {
2403 tag_order = Profiler::kUser; 2667 tag_order = Profiler::kUser;
2404 } else if (js->OptionIs("tags", "vu")) { 2668 } else if (js->OptionIs("tags", "VMUser")) {
2405 tag_order = Profiler::kVMUser; 2669 tag_order = Profiler::kVMUser;
2406 } else if (js->OptionIs("tags", "v")) { 2670 } else if (js->OptionIs("tags", "VMOnly")) {
2407 tag_order = Profiler::kVM; 2671 tag_order = Profiler::kVM;
2408 } else { 2672 } else {
2409 PrintError(js, "Invalid tags option value: %s\n", tags_option); 2673 PrintError(js, "Invalid tags option value: %s\n", tags_option);
2410 return true; 2674 return true;
2411 } 2675 }
2412 } 2676 }
2413 Profiler::PrintJSON(isolate, js, full_profile, tag_order); 2677 Profiler::PrintJSON(isolate, js, full_profile, tag_order);
2414 return true; 2678 return true;
2415 } 2679 }
2416 2680
2417 static bool HandleCoverage(Isolate* isolate, JSONStream* js) {
2418 CodeCoverage::PrintJSON(isolate, js, NULL);
2419 return true;
2420 }
2421
2422 2681
2423 static bool HandleAllocationProfile(Isolate* isolate, JSONStream* js) { 2682 static bool HandleIsolateGetAllocationProfile(Isolate* isolate,
2683 JSONStream* js) {
2424 bool should_reset_accumulator = false; 2684 bool should_reset_accumulator = false;
2425 bool should_collect = false; 2685 bool should_collect = false;
2426 if (js->num_arguments() != 1) {
2427 PrintError(js, "Command too long");
2428 return true;
2429 }
2430 if (js->HasOption("reset")) { 2686 if (js->HasOption("reset")) {
2431 if (js->OptionIs("reset", "true")) { 2687 if (js->OptionIs("reset", "true")) {
2432 should_reset_accumulator = true; 2688 should_reset_accumulator = true;
2433 } else { 2689 } else {
2434 PrintError(js, "Unrecognized reset option '%s'", 2690 PrintError(js, "Unrecognized reset option '%s'",
2435 js->LookupOption("reset")); 2691 js->LookupOption("reset"));
2436 return true; 2692 return true;
2437 } 2693 }
2438 } 2694 }
2439 if (js->HasOption("gc")) { 2695 if (js->HasOption("gc")) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
2502 if ((id < 0) || (id >= table_size) || (table.At(id) == Object::null())) { 2758 if ((id < 0) || (id >= table_size) || (table.At(id) == Object::null())) {
2503 PrintError(js, "%" Pd " is not a valid typearguments id.", id); 2759 PrintError(js, "%" Pd " is not a valid typearguments id.", id);
2504 return true; 2760 return true;
2505 } 2761 }
2506 type_args ^= table.At(id); 2762 type_args ^= table.At(id);
2507 type_args.PrintJSON(js, false); 2763 type_args.PrintJSON(js, false);
2508 return true; 2764 return true;
2509 } 2765 }
2510 2766
2511 2767
2512 static bool HandleHeapMap(Isolate* isolate, JSONStream* js) { 2768 static bool HandleIsolateGetHeapMap(Isolate* isolate, JSONStream* js) {
2513 isolate->heap()->PrintHeapMapToJSONStream(isolate, js); 2769 isolate->heap()->PrintHeapMapToJSONStream(isolate, js);
2514 return true; 2770 return true;
2515 } 2771 }
2516 2772
2517 2773
2518 static bool HandleGraph(Isolate* isolate, JSONStream* js) { 2774 static bool HandleIsolateRequestHeapSnapshot(Isolate* isolate, JSONStream* js) {
2519 Service::SendGraphEvent(isolate); 2775 Service::SendGraphEvent(isolate);
2520 // TODO(koda): Provide some id that ties this request to async response(s). 2776 // TODO(koda): Provide some id that ties this request to async response(s).
2521 JSONObject jsobj(js); 2777 JSONObject jsobj(js);
2522 jsobj.AddProperty("type", "OK"); 2778 jsobj.AddProperty("type", "OK");
2523 jsobj.AddProperty("id", "ok"); 2779 jsobj.AddProperty("id", "ok");
2524 return true; 2780 return true;
2525 } 2781 }
2526 2782
2527 2783
2528 void Service::SendGraphEvent(Isolate* isolate) { 2784 void Service::SendGraphEvent(Isolate* isolate) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
2599 2855
2600 2856
2601 static bool HandleMalformedObject(Isolate* isolate, JSONStream* js) { 2857 static bool HandleMalformedObject(Isolate* isolate, JSONStream* js) {
2602 JSONObject jsobj(js); 2858 JSONObject jsobj(js);
2603 jsobj.AddProperty("bart", "simpson"); 2859 jsobj.AddProperty("bart", "simpson");
2604 return true; 2860 return true;
2605 } 2861 }
2606 2862
2607 2863
2608 static IsolateMessageHandlerEntry isolate_handlers[] = { 2864 static IsolateMessageHandlerEntry isolate_handlers[] = {
2609 { "_malformedjson", HandleMalformedJson }, 2865 { "_malformedjson", HandleMalformedJson }, // debug
2610 { "_malformedobject", HandleMalformedObject }, 2866 { "_malformedobject", HandleMalformedObject }, // debug
2611 { "_echo", HandleIsolateEcho }, 2867 { "_echo", HandleIsolateEcho }, // debug
2612 { "", HandleIsolate }, 2868 { "", HandleIsolate }, // getObject
2613 { "address", HandleAddress }, 2869 { "address", HandleAddress }, // to do
2614 { "allocationprofile", HandleAllocationProfile }, 2870 { "classes", HandleClasses }, // getObject
2615 { "classes", HandleClasses }, 2871 { "code", HandleCode }, // getObject
2616 { "code", HandleCode }, 2872 { "libraries", HandleLibraries }, // getObject
2617 { "coverage", HandleCoverage }, 2873 { "metrics", HandleMetrics }, // to do - complex?
2618 { "debug", HandleDebug }, 2874 { "objects", HandleObjects }, // getObject
2619 { "graph", HandleGraph }, 2875 { "scripts", HandleScripts }, // getObject
2620 { "heapmap", HandleHeapMap }, 2876 { "typearguments", HandleTypeArguments }, // confusing
2621 { "libraries", HandleLibraries },
2622 { "metrics", HandleMetrics },
2623 { "objects", HandleObjects },
2624 { "profile", HandleProfile },
2625 { "scripts", HandleScripts },
2626 { "stacktrace", HandleStackTrace },
2627 { "typearguments", HandleTypeArguments },
2628 }; 2877 };
2629 2878
2630 2879
2631 static IsolateMessageHandler FindIsolateMessageHandler(const char* command) { 2880 static IsolateMessageHandler FindIsolateMessageHandler(const char* command) {
2632 intptr_t num_message_handlers = sizeof(isolate_handlers) / 2881 intptr_t num_message_handlers = sizeof(isolate_handlers) /
2633 sizeof(isolate_handlers[0]); 2882 sizeof(isolate_handlers[0]);
2634 for (intptr_t i = 0; i < num_message_handlers; i++) { 2883 for (intptr_t i = 0; i < num_message_handlers; i++) {
2635 const IsolateMessageHandlerEntry& entry = isolate_handlers[i]; 2884 const IsolateMessageHandlerEntry& entry = isolate_handlers[i];
2636 if (strcmp(command, entry.command) == 0) { 2885 if (strcmp(command, entry.command) == 0) {
2637 return entry.handler; 2886 return entry.handler;
2638 } 2887 }
2639 } 2888 }
2640 if (FLAG_trace_service) { 2889 if (FLAG_trace_service) {
2641 OS::Print("vm-service: No isolate message handler for <%s>.\n", command); 2890 OS::Print("vm-service: No isolate message handler for <%s>.\n", command);
2642 } 2891 }
2643 return NULL; 2892 return NULL;
2644 } 2893 }
2645 2894
2646 2895
2896 static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) {
2897 const char* id = js->LookupOption("id");
2898 if (id == NULL) {
2899 // TODO(turnidge): Print the isolate here instead.
2900 PrintError(js, "GetObject expects an 'id' parameter\n",
2901 js->num_arguments());
2902 return true;
2903 }
2904
2905 // Handle heap objects.
2906 ObjectIdRing::LookupResult lookup_result;
2907 const Object& obj =
2908 Object::Handle(LookupHeapObject(isolate, id, &lookup_result));
2909 if (obj.raw() != Object::sentinel().raw()) {
2910 // We found a heap object for this id. Return it.
2911 obj.PrintJSON(js, false);
2912 return true;
2913 } else if (lookup_result == ObjectIdRing::kCollected) {
2914 PrintSentinel(js, "objects/collected", "<collected>");
2915 } else if (lookup_result == ObjectIdRing::kExpired) {
2916 PrintSentinel(js, "objects/expired", "<expired>");
2917 }
2918
2919 // Handle non-heap objects.
2920 SourceBreakpoint* bpt = LookupBreakpoint(isolate, id);
2921 if (bpt != NULL) {
2922 bpt->PrintJSON(js);
2923 return true;
2924 }
2925
2926 PrintError(js, "Unrecognized object id: %s\n", id);
2927 return true;
2928 }
2929
2930
2931 static IsolateMessageHandlerEntry isolate_handlers_new[] = {
2932 { "getObject", HandleIsolateGetObject },
2933 { "getBreakpoints", HandleIsolateGetBreakpoints },
2934 { "pause", HandleIsolatePause },
2935 { "resume", HandleIsolateResume },
2936 { "getStack", HandleIsolateGetStack },
2937 { "getCpuProfile", HandleIsolateGetCpuProfile },
2938 { "getTagProfile", HandleIsolateGetTagProfile },
2939 { "getAllocationProfile", HandleIsolateGetAllocationProfile },
2940 { "getHeapMap", HandleIsolateGetHeapMap },
2941 { "addBreakpoint", HandleIsolateAddBreakpoint },
2942 { "removeBreakpoint", HandleIsolateRemoveBreakpoint },
2943 { "getCoverage", HandleIsolateGetCoverage },
2944 { "eval", HandleIsolateEval },
2945 { "getRetainedSize", HandleIsolateGetRetainedSize },
2946 { "getRetainingPath", HandleIsolateGetRetainingPath },
2947 { "getInboundReferences", HandleIsolateGetInboundReferences },
2948 { "getInstances", HandleIsolateGetInstances },
2949 { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot },
2950 };
2951
2952
2953 static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command) {
2954 intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
2955 sizeof(isolate_handlers_new[0]);
2956 for (intptr_t i = 0; i < num_message_handlers; i++) {
2957 const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
2958 if (strcmp(command, entry.command) == 0) {
2959 return entry.handler;
2960 }
2961 }
2962 if (FLAG_trace_service) {
2963 OS::Print("Service has no isolate message handler for <%s>\n", command);
2964 }
2965 return NULL;
2966 }
2967
2968
2647 void Service::HandleRootMessage(const Instance& msg) { 2969 void Service::HandleRootMessage(const Instance& msg) {
2648 Isolate* isolate = Isolate::Current(); 2970 Isolate* isolate = Isolate::Current();
2649 ASSERT(!msg.IsNull()); 2971 ASSERT(!msg.IsNull());
2650 ASSERT(msg.IsArray()); 2972 ASSERT(msg.IsArray());
2651 2973
2652 { 2974 {
2653 StackZone zone(isolate); 2975 StackZone zone(isolate);
2654 HANDLESCOPE(isolate); 2976 HANDLESCOPE(isolate);
2655 2977
2656 const Array& message = Array::Cast(msg); 2978 const Array& message = Array::Cast(msg);
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
2997 while (current != NULL) { 3319 while (current != NULL) {
2998 if (strcmp(name, current->name()) == 0) { 3320 if (strcmp(name, current->name()) == 0) {
2999 return current; 3321 return current;
3000 } 3322 }
3001 current = current->next(); 3323 current = current->next();
3002 } 3324 }
3003 return NULL; 3325 return NULL;
3004 } 3326 }
3005 3327
3006 } // namespace dart 3328 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698