| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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* LookupHeapObjectLibraries(Isolate* isolate, |
| 1292 char** parts, int num_parts) { |
| 1293 // Library ids look like "libraries/35" |
| 1294 if (num_parts < 2) { |
| 1295 return Object::sentinel().raw(); |
| 1296 } |
| 1297 const GrowableObjectArray& libs = |
| 1298 GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| 1299 ASSERT(!libs.IsNull()); |
| 1300 intptr_t id = 0; |
| 1301 if (!GetIntegerId(parts[1], &id)) { |
| 1302 return Object::sentinel().raw(); |
| 1303 } |
| 1304 if ((id < 0) || (id >= libs.Length())) { |
| 1305 return Object::sentinel().raw(); |
| 1306 } |
| 1307 Library& lib = Library::Handle(); |
| 1308 lib ^= libs.At(id); |
| 1309 ASSERT(!lib.IsNull()); |
| 1310 if (num_parts == 2) { |
| 1311 return lib.raw(); |
| 1312 } |
| 1313 if (strcmp(parts[2], "scripts") == 0) { |
| 1314 // Script ids look like "libraries/35/scripts/library%2Furl.dart" |
| 1315 if (num_parts != 4) { |
| 1316 return Object::sentinel().raw(); |
| 1317 } |
| 1318 const String& id = String::Handle(String::New(parts[3])); |
| 1319 ASSERT(!id.IsNull()); |
| 1320 // The id is the url of the script % encoded, decode it. |
| 1321 const String& requested_url = String::Handle(String::DecodeIRI(id)); |
| 1322 Script& script = Script::Handle(); |
| 1323 String& script_url = String::Handle(); |
| 1324 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); |
| 1325 ASSERT(!loaded_scripts.IsNull()); |
| 1326 intptr_t i; |
| 1327 for (i = 0; i < loaded_scripts.Length(); i++) { |
| 1328 script ^= loaded_scripts.At(i); |
| 1329 ASSERT(!script.IsNull()); |
| 1330 script_url ^= script.url(); |
| 1331 if (script_url.Equals(requested_url)) { |
| 1332 return script.raw(); |
| 1333 } |
| 1334 } |
| 1335 } |
| 1336 |
| 1337 // Not found. |
| 1338 return Object::sentinel().raw(); |
| 1339 } |
| 1340 |
| 1341 static RawObject* LookupHeapObjectClasses(Isolate* isolate, |
| 1342 char** parts, int num_parts) { |
| 1343 // Class ids look like: "classes/17" |
| 1344 if (num_parts < 2) { |
| 1345 return Object::sentinel().raw(); |
| 1346 } |
| 1347 ClassTable* table = isolate->class_table(); |
| 1348 intptr_t id; |
| 1349 if (!GetIntegerId(parts[1], &id) || |
| 1350 !table->IsValidIndex(id)) { |
| 1351 return Object::sentinel().raw(); |
| 1352 } |
| 1353 Class& cls = Class::Handle(table->At(id)); |
| 1354 if (num_parts == 2) { |
| 1355 return cls.raw(); |
| 1356 } |
| 1357 if (strcmp(parts[2], "closures") == 0) { |
| 1358 // Closure ids look like: "classes/17/closures/11" |
| 1359 if (num_parts != 4) { |
| 1360 return Object::sentinel().raw(); |
| 1361 } |
| 1362 intptr_t id; |
| 1363 if (!GetIntegerId(parts[3], &id)) { |
| 1364 return Object::sentinel().raw(); |
| 1365 } |
| 1366 Function& func = Function::Handle(); |
| 1367 func ^= cls.ClosureFunctionFromIndex(id); |
| 1368 if (func.IsNull()) { |
| 1369 return Object::sentinel().raw(); |
| 1370 } |
| 1371 return func.raw(); |
| 1372 |
| 1373 } else if (strcmp(parts[2], "fields") == 0) { |
| 1374 // Field ids look like: "classes/17/fields/11" |
| 1375 if (num_parts != 4) { |
| 1376 return Object::sentinel().raw(); |
| 1377 } |
| 1378 intptr_t id; |
| 1379 if (!GetIntegerId(parts[3], &id)) { |
| 1380 return Object::sentinel().raw(); |
| 1381 } |
| 1382 Field& field = Field::Handle(cls.FieldFromIndex(id)); |
| 1383 if (field.IsNull()) { |
| 1384 return Object::sentinel().raw(); |
| 1385 } |
| 1386 return field.raw(); |
| 1387 |
| 1388 } else if (strcmp(parts[2], "functions") == 0) { |
| 1389 // Function ids look like: "classes/17/functions/11" |
| 1390 if (num_parts != 4) { |
| 1391 return Object::sentinel().raw(); |
| 1392 } |
| 1393 const char* encoded_id = parts[3]; |
| 1394 String& id = String::Handle(isolate, String::New(encoded_id)); |
| 1395 id = String::DecodeIRI(id); |
| 1396 if (id.IsNull()) { |
| 1397 return Object::sentinel().raw(); |
| 1398 } |
| 1399 Function& func = Function::Handle(cls.LookupFunction(id)); |
| 1400 if (func.IsNull()) { |
| 1401 return Object::sentinel().raw(); |
| 1402 } |
| 1403 return func.raw(); |
| 1404 |
| 1405 } else if (strcmp(parts[2], "implicit_closures") == 0) { |
| 1406 // Function ids look like: "classes/17/implicit_closures/11" |
| 1407 if (num_parts != 4) { |
| 1408 return Object::sentinel().raw(); |
| 1409 } |
| 1410 intptr_t id; |
| 1411 if (!GetIntegerId(parts[3], &id)) { |
| 1412 return Object::sentinel().raw(); |
| 1413 } |
| 1414 Function& func = Function::Handle(); |
| 1415 func ^= cls.ImplicitClosureFunctionFromIndex(id); |
| 1416 if (func.IsNull()) { |
| 1417 return Object::sentinel().raw(); |
| 1418 } |
| 1419 return func.raw(); |
| 1420 |
| 1421 } else if (strcmp(parts[2], "dispatchers") == 0) { |
| 1422 // Dispatcher Function ids look like: "classes/17/dispatchers/11" |
| 1423 if (num_parts != 4) { |
| 1424 return Object::sentinel().raw(); |
| 1425 } |
| 1426 intptr_t id; |
| 1427 if (!GetIntegerId(parts[3], &id)) { |
| 1428 return Object::sentinel().raw(); |
| 1429 } |
| 1430 Function& func = Function::Handle(); |
| 1431 func ^= cls.InvocationDispatcherFunctionFromIndex(id); |
| 1432 if (func.IsNull()) { |
| 1433 return Object::sentinel().raw(); |
| 1434 } |
| 1435 return func.raw(); |
| 1436 |
| 1437 } else if (strcmp(parts[2], "types") == 0) { |
| 1438 // Type ids look like: "classes/17/types/11" |
| 1439 if (num_parts != 4) { |
| 1440 return Object::sentinel().raw(); |
| 1441 } |
| 1442 intptr_t id; |
| 1443 if (!GetIntegerId(parts[3], &id)) { |
| 1444 return Object::sentinel().raw(); |
| 1445 } |
| 1446 Type& type = Type::Handle(); |
| 1447 type ^= cls.CanonicalTypeFromIndex(id); |
| 1448 if (type.IsNull()) { |
| 1449 return Object::sentinel().raw(); |
| 1450 } |
| 1451 return type.raw(); |
| 1452 } |
| 1453 |
| 1454 // Not found. |
| 1455 return Object::sentinel().raw(); |
| 1456 } |
| 1457 |
| 1458 |
| 1459 static RawObject* LookupHeapObject(Isolate* isolate, |
| 1460 const char* id_original, |
| 1461 ObjectIdRing::LookupResult* result) { |
| 1462 char* id = isolate->current_zone()->MakeCopyOfString(id_original); |
| 1463 |
| 1464 // Parse the id by splitting at each '/'. |
| 1465 const int MAX_PARTS = 8; |
| 1466 char* parts[MAX_PARTS]; |
| 1467 int num_parts = 0; |
| 1468 int i = 0; |
| 1469 int start_pos = 0; |
| 1470 while (id[i] != '\0') { |
| 1471 if (id[i] == '/') { |
| 1472 id[i++] = '\0'; |
| 1473 parts[num_parts++] = &id[start_pos]; |
| 1474 if (num_parts == MAX_PARTS) { |
| 1475 break; |
| 1476 } |
| 1477 start_pos = i; |
| 1478 } else { |
| 1479 i++; |
| 1480 } |
| 1481 } |
| 1482 if (num_parts < MAX_PARTS) { |
| 1483 parts[num_parts++] = &id[start_pos]; |
| 1484 } |
| 1485 |
| 1486 if (result != NULL) { |
| 1487 *result = ObjectIdRing::kValid; |
| 1488 } |
| 1489 |
| 1490 if (strcmp(parts[0], "objects") == 0) { |
| 1491 // Object ids look like "objects/1123" |
| 1492 Object& obj = Object::Handle(isolate); |
| 1493 ObjectIdRing::LookupResult lookup_result; |
| 1494 obj = LookupObjectId(isolate, parts[1], &lookup_result); |
| 1495 if (lookup_result != ObjectIdRing::kValid) { |
| 1496 if (result != NULL) { |
| 1497 *result = lookup_result; |
| 1498 } |
| 1499 return Object::sentinel().raw(); |
| 1500 } |
| 1501 return obj.raw(); |
| 1502 |
| 1503 } else if (strcmp(parts[0], "libraries") == 0) { |
| 1504 return LookupHeapObjectLibraries(isolate, parts, num_parts); |
| 1505 } else if (strcmp(parts[0], "classes") == 0) { |
| 1506 return LookupHeapObjectClasses(isolate, parts, num_parts); |
| 1507 } |
| 1508 |
| 1509 // Not found. |
| 1510 return Object::sentinel().raw(); |
| 1511 } |
| 1512 |
| 1513 |
| 1514 static void PrintSentinel(JSONStream* js, |
| 1515 const char* id, |
| 1516 const char* preview) { |
| 1517 JSONObject jsobj(js); |
| 1518 jsobj.AddProperty("type", "Sentinel"); |
| 1519 jsobj.AddProperty("id", id); |
| 1520 jsobj.AddProperty("valueAsString", preview); |
| 1521 } |
| 1522 |
| 1523 |
| 1524 static SourceBreakpoint* LookupBreakpoint(Isolate* isolate, const char* id) { |
| 1525 size_t end_pos = strcspn(id, "/"); |
| 1526 const char* rest = NULL; |
| 1527 if (end_pos < strlen(id)) { |
| 1528 rest = id + end_pos + 1; // +1 for '/'. |
| 1529 } |
| 1530 if (strncmp("breakpoints", id, end_pos) == 0) { |
| 1531 if (rest == NULL) { |
| 1532 return NULL; |
| 1533 } |
| 1534 intptr_t bpt_id = 0; |
| 1535 SourceBreakpoint* bpt = NULL; |
| 1536 if (GetIntegerId(rest, &bpt_id)) { |
| 1537 bpt = isolate->debugger()->GetBreakpointById(bpt_id); |
| 1538 } |
| 1539 return bpt; |
| 1540 } |
| 1541 return NULL; |
| 1542 } |
| 1543 |
| 1544 |
| 1545 |
| 1546 |
| 1547 static bool PrintInboundReferences(Isolate* isolate, |
| 1548 Object* target, |
| 1549 intptr_t limit, |
| 1550 JSONStream* js) { |
| 1202 ObjectGraph graph(isolate); | 1551 ObjectGraph graph(isolate); |
| 1203 Array& path = Array::Handle(Array::New(limit * 2)); | 1552 Array& path = Array::Handle(Array::New(limit * 2)); |
| 1204 intptr_t length = graph.InboundReferences(target, path); | 1553 intptr_t length = graph.InboundReferences(target, path); |
| 1205 JSONObject jsobj(js); | 1554 JSONObject jsobj(js); |
| 1206 jsobj.AddProperty("type", "InboundReferences"); | 1555 jsobj.AddProperty("type", "InboundReferences"); |
| 1207 jsobj.AddProperty("id", "inbound_references"); | |
| 1208 { | 1556 { |
| 1209 JSONArray elements(&jsobj, "references"); | 1557 JSONArray elements(&jsobj, "references"); |
| 1210 Object& source = Object::Handle(); | 1558 Object& source = Object::Handle(); |
| 1211 Smi& slot_offset = Smi::Handle(); | 1559 Smi& slot_offset = Smi::Handle(); |
| 1212 Class& source_class = Class::Handle(); | 1560 Class& source_class = Class::Handle(); |
| 1213 Field& field = Field::Handle(); | 1561 Field& field = Field::Handle(); |
| 1214 Array& parent_field_map = Array::Handle(); | 1562 Array& parent_field_map = Array::Handle(); |
| 1215 limit = Utils::Minimum(limit, length); | 1563 limit = Utils::Minimum(limit, length); |
| 1216 for (intptr_t i = 0; i < limit; ++i) { | 1564 for (intptr_t i = 0; i < limit; ++i) { |
| 1217 JSONObject jselement(&elements); | 1565 JSONObject jselement(&elements); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1237 // We nil out the array after generating the response to prevent | 1585 // We nil out the array after generating the response to prevent |
| 1238 // reporting suprious references when repeatedly looking for the | 1586 // reporting suprious references when repeatedly looking for the |
| 1239 // references to an object. | 1587 // references to an object. |
| 1240 path.SetAt(i * 2, Object::null_object()); | 1588 path.SetAt(i * 2, Object::null_object()); |
| 1241 } | 1589 } |
| 1242 } | 1590 } |
| 1243 return true; | 1591 return true; |
| 1244 } | 1592 } |
| 1245 | 1593 |
| 1246 | 1594 |
| 1247 static bool HandleRetainingPath(Isolate* isolate, | 1595 static bool HandleIsolateGetInboundReferences(Isolate* isolate, |
| 1248 Object* obj, | 1596 JSONStream* js) { |
| 1249 intptr_t limit, | 1597 const char* target_id = js->LookupOption("targetId"); |
| 1250 JSONStream* js) { | 1598 if (target_id == NULL) { |
| 1599 PrintError(js, "Missing 'targetId' option"); |
| 1600 return true; |
| 1601 } |
| 1602 const char* limit_cstr = js->LookupOption("limit"); |
| 1603 if (target_id == NULL) { |
| 1604 PrintError(js, "Missing 'limit' option"); |
| 1605 return true; |
| 1606 } |
| 1607 intptr_t limit; |
| 1608 if (!GetIntegerId(js->LookupOption("limit"), &limit)) { |
| 1609 PrintError(js, "Invalid 'limit' option: %s", limit_cstr); |
| 1610 return true; |
| 1611 } |
| 1612 |
| 1613 Object& obj = Object::Handle(isolate); |
| 1614 ObjectIdRing::LookupResult lookup_result; |
| 1615 { |
| 1616 HANDLESCOPE(isolate); |
| 1617 obj = LookupHeapObject(isolate, target_id, &lookup_result); |
| 1618 } |
| 1619 if (obj.raw() == Object::sentinel().raw()) { |
| 1620 if (lookup_result == ObjectIdRing::kCollected) { |
| 1621 PrintErrorWithKind( |
| 1622 js, "InboundReferencesCollected", |
| 1623 "attempt to find a retaining path for a collected object\n", |
| 1624 js->num_arguments()); |
| 1625 return true; |
| 1626 } else if (lookup_result == ObjectIdRing::kExpired) { |
| 1627 PrintErrorWithKind( |
| 1628 js, "InboundReferencesExpired", |
| 1629 "attempt to find a retaining path for an expired object\n", |
| 1630 js->num_arguments()); |
| 1631 return true; |
| 1632 } |
| 1633 PrintError(js, "Invalid 'targetId' value: no object with id '%s'", |
| 1634 target_id); |
| 1635 return true; |
| 1636 } |
| 1637 return PrintInboundReferences(isolate, &obj, limit, js); |
| 1638 } |
| 1639 |
| 1640 |
| 1641 static bool PrintRetainingPath(Isolate* isolate, |
| 1642 Object* obj, |
| 1643 intptr_t limit, |
| 1644 JSONStream* js) { |
| 1251 ObjectGraph graph(isolate); | 1645 ObjectGraph graph(isolate); |
| 1252 Array& path = Array::Handle(Array::New(limit * 2)); | 1646 Array& path = Array::Handle(Array::New(limit * 2)); |
| 1253 intptr_t length = graph.RetainingPath(obj, path); | 1647 intptr_t length = graph.RetainingPath(obj, path); |
| 1254 JSONObject jsobj(js); | 1648 JSONObject jsobj(js); |
| 1255 jsobj.AddProperty("type", "RetainingPath"); | 1649 jsobj.AddProperty("type", "RetainingPath"); |
| 1256 jsobj.AddProperty("id", "retaining_path"); | |
| 1257 jsobj.AddProperty("length", length); | 1650 jsobj.AddProperty("length", length); |
| 1258 JSONArray elements(&jsobj, "elements"); | 1651 JSONArray elements(&jsobj, "elements"); |
| 1259 Object& element = Object::Handle(); | 1652 Object& element = Object::Handle(); |
| 1260 Object& parent = Object::Handle(); | 1653 Object& parent = Object::Handle(); |
| 1261 Smi& offset_from_parent = Smi::Handle(); | 1654 Smi& offset_from_parent = Smi::Handle(); |
| 1262 Class& parent_class = Class::Handle(); | 1655 Class& parent_class = Class::Handle(); |
| 1263 Array& parent_field_map = Array::Handle(); | 1656 Array& parent_field_map = Array::Handle(); |
| 1264 Field& field = Field::Handle(); | 1657 Field& field = Field::Handle(); |
| 1265 limit = Utils::Minimum(limit, length); | 1658 limit = Utils::Minimum(limit, length); |
| 1266 for (intptr_t i = 0; i < limit; ++i) { | 1659 for (intptr_t i = 0; i < limit; ++i) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1284 intptr_t offset = offset_from_parent.Value(); | 1677 intptr_t offset = offset_from_parent.Value(); |
| 1285 if (offset > 0 && offset < parent_field_map.Length()) { | 1678 if (offset > 0 && offset < parent_field_map.Length()) { |
| 1286 field ^= parent_field_map.At(offset); | 1679 field ^= parent_field_map.At(offset); |
| 1287 jselement.AddProperty("parentField", field); | 1680 jselement.AddProperty("parentField", field); |
| 1288 } | 1681 } |
| 1289 } | 1682 } |
| 1290 } | 1683 } |
| 1291 } | 1684 } |
| 1292 | 1685 |
| 1293 // We nil out the array after generating the response to prevent | 1686 // We nil out the array after generating the response to prevent |
| 1294 // reporting suprious references when looking for inbound references | 1687 // reporting spurious references when looking for inbound references |
| 1295 // after looking for a retaining path. | 1688 // after looking for a retaining path. |
| 1296 for (intptr_t i = 0; i < limit; ++i) { | 1689 for (intptr_t i = 0; i < limit; ++i) { |
| 1297 path.SetAt(i * 2, Object::null_object()); | 1690 path.SetAt(i * 2, Object::null_object()); |
| 1298 } | 1691 } |
| 1299 | 1692 |
| 1300 return true; | 1693 return true; |
| 1301 } | 1694 } |
| 1302 | 1695 |
| 1696 static bool HandleIsolateGetRetainingPath(Isolate* isolate, |
| 1697 JSONStream* js) { |
| 1698 const char* target_id = js->LookupOption("targetId"); |
| 1699 if (target_id == NULL) { |
| 1700 PrintError(js, "Missing 'targetId' option"); |
| 1701 return true; |
| 1702 } |
| 1703 const char* limit_cstr = js->LookupOption("limit"); |
| 1704 if (target_id == NULL) { |
| 1705 PrintError(js, "Missing 'limit' option"); |
| 1706 return true; |
| 1707 } |
| 1708 intptr_t limit; |
| 1709 if (!GetIntegerId(js->LookupOption("limit"), &limit)) { |
| 1710 PrintError(js, "Invalid 'limit' option: %s", limit_cstr); |
| 1711 return true; |
| 1712 } |
| 1303 | 1713 |
| 1304 // Takes an Object* only because RetainingPath temporarily clears it. | 1714 Object& obj = Object::Handle(isolate); |
| 1305 static bool HandleInstanceCommands(Isolate* isolate, | 1715 ObjectIdRing::LookupResult lookup_result; |
| 1306 Object* obj, | 1716 { |
| 1307 ObjectIdRing::LookupResult kind, | 1717 HANDLESCOPE(isolate); |
| 1308 JSONStream* js, | 1718 obj = LookupHeapObject(isolate, target_id, &lookup_result); |
| 1309 intptr_t arg_pos) { | 1719 } |
| 1310 ASSERT(js->num_arguments() > arg_pos); | 1720 if (obj.raw() == Object::sentinel().raw()) { |
| 1311 ASSERT(kind != ObjectIdRing::kInvalid); | 1721 if (lookup_result == ObjectIdRing::kCollected) { |
| 1312 const char* action = js->GetArgument(arg_pos); | 1722 PrintErrorWithKind( |
| 1313 if (strcmp(action, "eval") == 0) { | 1723 js, "RetainingPathCollected", |
| 1314 if (js->num_arguments() > (arg_pos + 1)) { | 1724 "attempt to find a retaining path for a collected object\n", |
| 1315 PrintError(js, "expected at most %" Pd " arguments but found %" Pd "\n", | 1725 js->num_arguments()); |
| 1316 arg_pos + 1, | 1726 return true; |
| 1317 js->num_arguments()); | 1727 } else if (lookup_result == ObjectIdRing::kExpired) { |
| 1728 PrintErrorWithKind( |
| 1729 js, "RetainingPathExpired", |
| 1730 "attempt to find a retaining path for an expired object\n", |
| 1731 js->num_arguments()); |
| 1318 return true; | 1732 return true; |
| 1319 } | 1733 } |
| 1320 if (kind == ObjectIdRing::kCollected) { | 1734 PrintError(js, "Invalid 'targetId' value: no object with id '%s'", |
| 1321 PrintErrorWithKind(js, "EvalCollected", | 1735 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; | 1736 return true; |
| 1352 } else if (strcmp(action, "retained") == 0) { | 1737 } |
| 1353 if (kind == ObjectIdRing::kCollected) { | 1738 return PrintRetainingPath(isolate, &obj, limit, js); |
| 1739 } |
| 1740 |
| 1741 |
| 1742 static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) { |
| 1743 const char* target_id = js->LookupOption("targetId"); |
| 1744 if (target_id == NULL) { |
| 1745 PrintError(js, "Missing 'targetId' option"); |
| 1746 return true; |
| 1747 } |
| 1748 ObjectIdRing::LookupResult lookup_result; |
| 1749 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, |
| 1750 &lookup_result)); |
| 1751 if (obj.raw() == Object::sentinel().raw()) { |
| 1752 if (lookup_result == ObjectIdRing::kCollected) { |
| 1354 PrintErrorWithKind( | 1753 PrintErrorWithKind( |
| 1355 js, "RetainedCollected", | 1754 js, "RetainedCollected", |
| 1356 "attempt to calculate size retained by a collected object\n", | 1755 "attempt to calculate size retained by a collected object\n", |
| 1357 js->num_arguments()); | 1756 js->num_arguments()); |
| 1358 return true; | 1757 return true; |
| 1359 } | 1758 } else if (lookup_result == ObjectIdRing::kExpired) { |
| 1360 if (kind == ObjectIdRing::kExpired) { | |
| 1361 PrintErrorWithKind( | 1759 PrintErrorWithKind( |
| 1362 js, "RetainedExpired", | 1760 js, "RetainedExpired", |
| 1363 "attempt to calculate size retained by an expired object\n", | 1761 "attempt to calculate size retained by an expired object\n", |
| 1364 js->num_arguments()); | 1762 js->num_arguments()); |
| 1365 return true; | 1763 return true; |
| 1366 } | 1764 } |
| 1765 PrintError(js, "Invalid 'targetId' value: no object with id '%s'", |
| 1766 target_id); |
| 1767 return true; |
| 1768 } |
| 1769 if (obj.IsClass()) { |
| 1770 const Class& cls = Class::Cast(obj); |
| 1367 ObjectGraph graph(isolate); | 1771 ObjectGraph graph(isolate); |
| 1368 intptr_t retained_size = graph.SizeRetainedByInstance(*obj); | 1772 intptr_t retained_size = graph.SizeRetainedByClass(cls.id()); |
| 1369 const Object& result = Object::Handle(Integer::New(retained_size)); | 1773 const Object& result = Object::Handle(Integer::New(retained_size)); |
| 1370 result.PrintJSON(js, true); | 1774 result.PrintJSON(js, true); |
| 1371 return true; | 1775 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 } | 1776 } |
| 1417 | 1777 if (obj.IsInstance() || obj.IsNull()) { |
| 1418 PrintError(js, "unrecognized action '%s'\n", action); | 1778 // We don't use Instance::Cast here because it doesn't allow null. |
| 1779 ObjectGraph graph(isolate); |
| 1780 intptr_t retained_size = graph.SizeRetainedByInstance(obj); |
| 1781 const Object& result = Object::Handle(Integer::New(retained_size)); |
| 1782 result.PrintJSON(js, true); |
| 1783 return true; |
| 1784 } |
| 1785 PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a " |
| 1786 "library, class, or instance", target_id); |
| 1419 return true; | 1787 return true; |
| 1420 } | 1788 } |
| 1421 | 1789 |
| 1422 | 1790 |
| 1423 static bool HandleClassesClosures(Isolate* isolate, const Class& cls, | 1791 static bool HandleClassesClosures(Isolate* isolate, const Class& cls, |
| 1424 JSONStream* js) { | 1792 JSONStream* js) { |
| 1425 intptr_t id; | 1793 intptr_t id; |
| 1426 if (js->num_arguments() > 4) { | 1794 if (js->num_arguments() > 4) { |
| 1427 PrintError(js, "Command too long"); | 1795 PrintError(js, "Command too long"); |
| 1428 return true; | 1796 return true; |
| 1429 } | 1797 } |
| 1430 if (!GetIntegerId(js->GetArgument(3), &id)) { | 1798 if (!GetIntegerId(js->GetArgument(3), &id)) { |
| 1431 PrintError(js, "Must specify collection object id: closures/id"); | 1799 PrintError(js, "Must specify collection object id: closures/id"); |
| 1432 return true; | 1800 return true; |
| 1433 } | 1801 } |
| 1434 Function& func = Function::Handle(); | 1802 Function& func = Function::Handle(); |
| 1435 func ^= cls.ClosureFunctionFromIndex(id); | 1803 func ^= cls.ClosureFunctionFromIndex(id); |
| 1436 if (func.IsNull()) { | 1804 if (func.IsNull()) { |
| 1437 PrintError(js, "Closure function %" Pd " not found", id); | 1805 PrintError(js, "Closure function %" Pd " not found", id); |
| 1438 return true; | 1806 return true; |
| 1439 } | 1807 } |
| 1440 func.PrintJSON(js, false); | 1808 func.PrintJSON(js, false); |
| 1441 return true; | 1809 return true; |
| 1442 } | 1810 } |
| 1443 | 1811 |
| 1444 | 1812 |
| 1445 static bool HandleClassesEval(Isolate* isolate, const Class& cls, | 1813 static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) { |
| 1446 JSONStream* js) { | 1814 const char* target_id = js->LookupOption("targetId"); |
| 1447 if (js->num_arguments() > 3) { | 1815 if (target_id == NULL) { |
| 1448 PrintError(js, "Command too long"); | 1816 PrintError(js, "Missing 'targetId' option"); |
| 1449 return true; | 1817 return true; |
| 1450 } | 1818 } |
| 1451 const char* expr = js->LookupOption("expr"); | 1819 const char* expr = js->LookupOption("expression"); |
| 1452 if (expr == NULL) { | 1820 if (expr == NULL) { |
| 1453 PrintError(js, "eval expects an 'expr' option\n", | 1821 PrintError(js, "Missing 'expression' option"); |
| 1454 js->num_arguments()); | |
| 1455 return true; | 1822 return true; |
| 1456 } | 1823 } |
| 1457 const String& expr_str = String::Handle(isolate, String::New(expr)); | 1824 const String& expr_str = String::Handle(isolate, String::New(expr)); |
| 1458 const Object& result = Object::Handle(cls.Evaluate(expr_str, | 1825 ObjectIdRing::LookupResult lookup_result; |
| 1459 Array::empty_array(), | 1826 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, |
| 1460 Array::empty_array())); | 1827 &lookup_result)); |
| 1461 result.PrintJSON(js, true); | 1828 if (obj.raw() == Object::sentinel().raw()) { |
| 1829 if (lookup_result == ObjectIdRing::kCollected) { |
| 1830 PrintSentinel(js, "objects/collected", "<collected>"); |
| 1831 } else if (lookup_result == ObjectIdRing::kExpired) { |
| 1832 PrintSentinel(js, "objects/expired", "<expired>"); |
| 1833 } else { |
| 1834 PrintError(js, "Invalid 'targetId' value: no object with id '%s'", |
| 1835 target_id); |
| 1836 } |
| 1837 return true; |
| 1838 } |
| 1839 if (obj.IsLibrary()) { |
| 1840 const Library& lib = Library::Cast(obj); |
| 1841 const Object& result = Object::Handle(lib.Evaluate(expr_str, |
| 1842 Array::empty_array(), |
| 1843 Array::empty_array())); |
| 1844 result.PrintJSON(js, true); |
| 1845 return true; |
| 1846 } |
| 1847 if (obj.IsClass()) { |
| 1848 const Class& cls = Class::Cast(obj); |
| 1849 const Object& result = Object::Handle(cls.Evaluate(expr_str, |
| 1850 Array::empty_array(), |
| 1851 Array::empty_array())); |
| 1852 result.PrintJSON(js, true); |
| 1853 return true; |
| 1854 } |
| 1855 if ((obj.IsInstance() || obj.IsNull()) && |
| 1856 !ContainsNonInstance(obj)) { |
| 1857 // We don't use Instance::Cast here because it doesn't allow null. |
| 1858 Instance& instance = Instance::Handle(isolate); |
| 1859 instance ^= obj.raw(); |
| 1860 const Object& result = |
| 1861 Object::Handle(instance.Evaluate(expr_str, |
| 1862 Array::empty_array(), |
| 1863 Array::empty_array())); |
| 1864 result.PrintJSON(js, true); |
| 1865 return true; |
| 1866 } |
| 1867 PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a " |
| 1868 "library, class, or instance", target_id); |
| 1462 return true; | 1869 return true; |
| 1463 } | 1870 } |
| 1464 | 1871 |
| 1465 | 1872 |
| 1466 static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls, | 1873 static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls, |
| 1467 JSONStream* js) { | 1874 JSONStream* js) { |
| 1468 intptr_t id; | 1875 intptr_t id; |
| 1469 if (js->num_arguments() > 4) { | 1876 if (js->num_arguments() > 4) { |
| 1470 PrintError(js, "Command too long"); | 1877 PrintError(js, "Command too long"); |
| 1471 return true; | 1878 return true; |
| 1472 } | 1879 } |
| 1473 if (!GetIntegerId(js->GetArgument(3), &id)) { | 1880 if (!GetIntegerId(js->GetArgument(3), &id)) { |
| 1474 PrintError(js, "Must specify collection object id: dispatchers/id"); | 1881 PrintError(js, "Must specify collection object id: dispatchers/id"); |
| 1475 return true; | 1882 return true; |
| 1476 } | 1883 } |
| 1477 Function& func = Function::Handle(); | 1884 Function& func = Function::Handle(); |
| 1478 func ^= cls.InvocationDispatcherFunctionFromIndex(id); | 1885 func ^= cls.InvocationDispatcherFunctionFromIndex(id); |
| 1479 if (func.IsNull()) { | 1886 if (func.IsNull()) { |
| 1480 PrintError(js, "Dispatcher %" Pd " not found", id); | 1887 PrintError(js, "Dispatcher %" Pd " not found", id); |
| 1481 return true; | 1888 return true; |
| 1482 } | 1889 } |
| 1483 func.PrintJSON(js, false); | 1890 func.PrintJSON(js, false); |
| 1484 return true; | 1891 return true; |
| 1485 } | 1892 } |
| 1486 | 1893 |
| 1487 | 1894 |
| 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( | 1895 static bool HandleFunctionSetSource( |
| 1497 Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) { | 1896 Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) { |
| 1498 if (js->LookupOption("source") == NULL) { | 1897 if (js->LookupOption("source") == NULL) { |
| 1499 PrintError(js, "set_source expects a 'source' option\n"); | 1898 PrintError(js, "set_source expects a 'source' option\n"); |
| 1500 return true; | 1899 return true; |
| 1501 } | 1900 } |
| 1502 const String& source = | 1901 const String& source = |
| 1503 String::Handle(String::New(js->LookupOption("source"))); | 1902 String::Handle(String::New(js->LookupOption("source"))); |
| 1504 const Object& result = Object::Handle( | 1903 const Object& result = Object::Handle( |
| 1505 Parser::ParseFunctionFromSource(cls, source)); | 1904 Parser::ParseFunctionFromSource(cls, source)); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1539 Function& func = Function::Handle(cls.LookupFunction(id)); | 1938 Function& func = Function::Handle(cls.LookupFunction(id)); |
| 1540 if (func.IsNull()) { | 1939 if (func.IsNull()) { |
| 1541 PrintError(js, "Function %s not found", encoded_id); | 1940 PrintError(js, "Function %s not found", encoded_id); |
| 1542 return true; | 1941 return true; |
| 1543 } | 1942 } |
| 1544 if (js->num_arguments() == 4) { | 1943 if (js->num_arguments() == 4) { |
| 1545 func.PrintJSON(js, false); | 1944 func.PrintJSON(js, false); |
| 1546 return true; | 1945 return true; |
| 1547 } else { | 1946 } else { |
| 1548 const char* subcommand = js->GetArgument(4); | 1947 const char* subcommand = js->GetArgument(4); |
| 1549 if (strcmp(subcommand, "coverage") == 0) { | 1948 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); | 1949 return HandleFunctionSetSource(isolate, cls, func, js); |
| 1553 } else { | 1950 } else { |
| 1554 PrintError(js, "Invalid sub command %s", subcommand); | 1951 PrintError(js, "Invalid sub command %s", subcommand); |
| 1555 return true; | 1952 return true; |
| 1556 } | 1953 } |
| 1557 } | 1954 } |
| 1558 UNREACHABLE(); | 1955 UNREACHABLE(); |
| 1559 return true; | 1956 return true; |
| 1560 } | 1957 } |
| 1561 | 1958 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1610 jsobj.AddProperty("type", "TypeList"); | 2007 jsobj.AddProperty("type", "TypeList"); |
| 1611 JSONArray members(&jsobj, "members"); | 2008 JSONArray members(&jsobj, "members"); |
| 1612 const intptr_t num_types = cls.NumCanonicalTypes(); | 2009 const intptr_t num_types = cls.NumCanonicalTypes(); |
| 1613 Type& type = Type::Handle(); | 2010 Type& type = Type::Handle(); |
| 1614 for (intptr_t i = 0; i < num_types; i++) { | 2011 for (intptr_t i = 0; i < num_types; i++) { |
| 1615 type = cls.CanonicalTypeFromIndex(i); | 2012 type = cls.CanonicalTypeFromIndex(i); |
| 1616 members.AddValue(type); | 2013 members.AddValue(type); |
| 1617 } | 2014 } |
| 1618 return true; | 2015 return true; |
| 1619 } | 2016 } |
| 1620 ASSERT(js->num_arguments() >= 4); | 2017 if (js->num_arguments() > 4) { |
| 2018 PrintError(js, "Command too long"); |
| 2019 return true; |
| 2020 } |
| 2021 ASSERT(js->num_arguments() == 4); |
| 1621 intptr_t id; | 2022 intptr_t id; |
| 1622 if (!GetIntegerId(js->GetArgument(3), &id)) { | 2023 if (!GetIntegerId(js->GetArgument(3), &id)) { |
| 1623 PrintError(js, "Must specify collection object id: types/id"); | 2024 PrintError(js, "Must specify collection object id: types/id"); |
| 1624 return true; | 2025 return true; |
| 1625 } | 2026 } |
| 1626 Type& type = Type::Handle(); | 2027 Type& type = Type::Handle(); |
| 1627 type ^= cls.CanonicalTypeFromIndex(id); | 2028 type ^= cls.CanonicalTypeFromIndex(id); |
| 1628 if (type.IsNull()) { | 2029 if (type.IsNull()) { |
| 1629 PrintError(js, "Canonical type %" Pd " not found", id); | 2030 PrintError(js, "Canonical type %" Pd " not found", id); |
| 1630 return true; | 2031 return true; |
| 1631 } | 2032 } |
| 1632 if (js->num_arguments() == 4) { | 2033 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; | 2034 return true; |
| 1651 } | 2035 } |
| 1652 | 2036 |
| 1653 | 2037 |
| 1654 class GetInstancesVisitor : public ObjectGraph::Visitor { | 2038 class GetInstancesVisitor : public ObjectGraph::Visitor { |
| 1655 public: | 2039 public: |
| 1656 GetInstancesVisitor(const Class& cls, const Array& storage) | 2040 GetInstancesVisitor(const Class& cls, const Array& storage) |
| 1657 : cls_(cls), storage_(storage), count_(0) {} | 2041 : cls_(cls), storage_(storage), count_(0) {} |
| 1658 | 2042 |
| 1659 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { | 2043 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1676 | 2060 |
| 1677 intptr_t count() const { return count_; } | 2061 intptr_t count() const { return count_; } |
| 1678 | 2062 |
| 1679 private: | 2063 private: |
| 1680 const Class& cls_; | 2064 const Class& cls_; |
| 1681 const Array& storage_; | 2065 const Array& storage_; |
| 1682 intptr_t count_; | 2066 intptr_t count_; |
| 1683 }; | 2067 }; |
| 1684 | 2068 |
| 1685 | 2069 |
| 1686 static bool HandleClassesInstances(Isolate* isolate, const Class& cls, | 2070 static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) { |
| 1687 JSONStream* js) { | 2071 const char* target_id = js->LookupOption("classId"); |
| 1688 if (js->num_arguments() != 3) { | 2072 if (target_id == NULL) { |
| 1689 PrintError(js, "Command too long"); | 2073 PrintError(js, "Missing 'classId' option"); |
| 2074 return true; |
| 2075 } |
| 2076 const char* limit_cstr = js->LookupOption("limit"); |
| 2077 if (target_id == NULL) { |
| 2078 PrintError(js, "Missing 'limit' option"); |
| 1690 return true; | 2079 return true; |
| 1691 } | 2080 } |
| 1692 intptr_t limit; | 2081 intptr_t limit; |
| 1693 if (!GetIntegerId(js->LookupOption("limit"), &limit)) { | 2082 if (!GetIntegerId(js->LookupOption("limit"), &limit)) { |
| 1694 PrintError(js, "instances expects a 'limit' option\n", | 2083 PrintError(js, "Invalid 'limit' option: %s", limit_cstr); |
| 1695 js->num_arguments()); | |
| 1696 return true; | 2084 return true; |
| 1697 } | 2085 } |
| 2086 const Object& obj = |
| 2087 Object::Handle(LookupHeapObject(isolate, target_id, NULL)); |
| 2088 if (obj.raw() == Object::sentinel().raw() || |
| 2089 !obj.IsClass()) { |
| 2090 PrintError(js, "Invalid 'classId' value: no class with id '%s'", target_id); |
| 2091 return true; |
| 2092 } |
| 2093 const Class& cls = Class::Cast(obj); |
| 1698 Array& storage = Array::Handle(Array::New(limit)); | 2094 Array& storage = Array::Handle(Array::New(limit)); |
| 1699 GetInstancesVisitor visitor(cls, storage); | 2095 GetInstancesVisitor visitor(cls, storage); |
| 1700 ObjectGraph graph(isolate); | 2096 ObjectGraph graph(isolate); |
| 1701 graph.IterateObjects(&visitor); | 2097 graph.IterateObjects(&visitor); |
| 1702 intptr_t count = visitor.count(); | 2098 intptr_t count = visitor.count(); |
| 1703 if (count < limit) { | 2099 if (count < limit) { |
| 1704 // Truncate the list using utility method for GrowableObjectArray. | 2100 // Truncate the list using utility method for GrowableObjectArray. |
| 1705 GrowableObjectArray& wrapper = GrowableObjectArray::Handle( | 2101 GrowableObjectArray& wrapper = GrowableObjectArray::Handle( |
| 1706 GrowableObjectArray::New(storage)); | 2102 GrowableObjectArray::New(storage)); |
| 1707 wrapper.SetLength(count); | 2103 wrapper.SetLength(count); |
| 1708 storage = Array::MakeArray(wrapper); | 2104 storage = Array::MakeArray(wrapper); |
| 1709 } | 2105 } |
| 1710 JSONObject jsobj(js); | 2106 JSONObject jsobj(js); |
| 1711 jsobj.AddProperty("type", "InstanceSet"); | 2107 jsobj.AddProperty("type", "InstanceSet"); |
| 1712 jsobj.AddProperty("id", "instance_set"); | 2108 jsobj.AddProperty("id", "instance_set"); |
| 1713 jsobj.AddProperty("totalCount", count); | 2109 jsobj.AddProperty("totalCount", count); |
| 1714 jsobj.AddProperty("sampleCount", storage.Length()); | 2110 jsobj.AddProperty("sampleCount", storage.Length()); |
| 1715 jsobj.AddProperty("sample", storage); | 2111 jsobj.AddProperty("sample", storage); |
| 1716 return true; | 2112 return true; |
| 1717 } | 2113 } |
| 1718 | 2114 |
| 1719 | 2115 |
| 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) { | 2116 static bool HandleClasses(Isolate* isolate, JSONStream* js) { |
| 1730 if (js->num_arguments() == 1) { | 2117 if (js->num_arguments() == 1) { |
| 1731 ClassTable* table = isolate->class_table(); | 2118 ClassTable* table = isolate->class_table(); |
| 1732 JSONObject jsobj(js); | 2119 JSONObject jsobj(js); |
| 1733 table->PrintToJSONObject(&jsobj); | 2120 table->PrintToJSONObject(&jsobj); |
| 1734 return true; | 2121 return true; |
| 1735 } | 2122 } |
| 1736 ASSERT(js->num_arguments() >= 2); | 2123 ASSERT(js->num_arguments() >= 2); |
| 1737 intptr_t id; | 2124 intptr_t id; |
| 1738 if (!GetIntegerId(js->GetArgument(1), &id)) { | 2125 if (!GetIntegerId(js->GetArgument(1), &id)) { |
| 1739 PrintError(js, "Must specify collection object id: /classes/id"); | 2126 PrintError(js, "Must specify collection object id: /classes/id"); |
| 1740 return true; | 2127 return true; |
| 1741 } | 2128 } |
| 1742 ClassTable* table = isolate->class_table(); | 2129 ClassTable* table = isolate->class_table(); |
| 1743 if (!table->IsValidIndex(id)) { | 2130 if (!table->IsValidIndex(id)) { |
| 1744 PrintError(js, "%" Pd " is not a valid class id.", id); | 2131 PrintError(js, "%" Pd " is not a valid class id.", id); |
| 1745 return true; | 2132 return true; |
| 1746 } | 2133 } |
| 1747 Class& cls = Class::Handle(table->At(id)); | 2134 Class& cls = Class::Handle(table->At(id)); |
| 1748 if (js->num_arguments() == 2) { | 2135 if (js->num_arguments() == 2) { |
| 1749 cls.PrintJSON(js, false); | 2136 cls.PrintJSON(js, false); |
| 1750 return true; | 2137 return true; |
| 1751 } else if (js->num_arguments() >= 3) { | 2138 } else if (js->num_arguments() >= 3) { |
| 1752 const char* second = js->GetArgument(2); | 2139 const char* second = js->GetArgument(2); |
| 1753 if (strcmp(second, "eval") == 0) { | 2140 if (strcmp(second, "closures") == 0) { |
| 1754 return HandleClassesEval(isolate, cls, js); | |
| 1755 } else if (strcmp(second, "closures") == 0) { | |
| 1756 return HandleClassesClosures(isolate, cls, js); | 2141 return HandleClassesClosures(isolate, cls, js); |
| 1757 } else if (strcmp(second, "fields") == 0) { | 2142 } else if (strcmp(second, "fields") == 0) { |
| 1758 return HandleClassesFields(isolate, cls, js); | 2143 return HandleClassesFields(isolate, cls, js); |
| 1759 } else if (strcmp(second, "functions") == 0) { | 2144 } else if (strcmp(second, "functions") == 0) { |
| 1760 return HandleClassesFunctions(isolate, cls, js); | 2145 return HandleClassesFunctions(isolate, cls, js); |
| 1761 } else if (strcmp(second, "implicit_closures") == 0) { | 2146 } else if (strcmp(second, "implicit_closures") == 0) { |
| 1762 return HandleClassesImplicitClosures(isolate, cls, js); | 2147 return HandleClassesImplicitClosures(isolate, cls, js); |
| 1763 } else if (strcmp(second, "dispatchers") == 0) { | 2148 } else if (strcmp(second, "dispatchers") == 0) { |
| 1764 return HandleClassesDispatchers(isolate, cls, js); | 2149 return HandleClassesDispatchers(isolate, cls, js); |
| 1765 } else if (strcmp(second, "types") == 0) { | 2150 } else if (strcmp(second, "types") == 0) { |
| 1766 return HandleClassesTypes(isolate, cls, js); | 2151 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 { | 2152 } else { |
| 1774 PrintError(js, "Invalid sub collection %s", second); | 2153 PrintError(js, "Invalid sub collection %s", second); |
| 1775 return true; | 2154 return true; |
| 1776 } | 2155 } |
| 1777 } | 2156 } |
| 1778 UNREACHABLE(); | 2157 UNREACHABLE(); |
| 1779 return true; | 2158 return true; |
| 1780 } | 2159 } |
| 1781 | 2160 |
| 1782 | 2161 |
| 1783 static bool HandleLibrariesEval(Isolate* isolate, const Library& lib, | 2162 static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) { |
| 1784 JSONStream* js) { | 2163 if (!js->HasOption("targetId")) { |
| 1785 if (js->num_arguments() > 3) { | 2164 CodeCoverage::PrintJSON(isolate, js, NULL); |
| 1786 PrintError(js, "Command too long"); | |
| 1787 return true; | 2165 return true; |
| 1788 } | 2166 } |
| 1789 const char* expr = js->LookupOption("expr"); | 2167 const char* target_id = js->LookupOption("targetId"); |
| 1790 if (expr == NULL) { | 2168 Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL)); |
| 1791 PrintError(js, "eval expects an 'expr' option\n", | 2169 if (obj.raw() == Object::sentinel().raw()) { |
| 1792 js->num_arguments()); | 2170 PrintError(js, "Invalid 'targetId' value: no object with id '%s'", |
| 2171 target_id); |
| 1793 return true; | 2172 return true; |
| 1794 } | 2173 } |
| 1795 const String& expr_str = String::Handle(isolate, String::New(expr)); | 2174 if (obj.IsScript()) { |
| 1796 const Object& result = Object::Handle(lib.Evaluate(expr_str, | 2175 ScriptCoverageFilter sf(Script::Cast(obj)); |
| 1797 Array::empty_array(), | 2176 CodeCoverage::PrintJSON(isolate, js, &sf); |
| 1798 Array::empty_array())); | 2177 return true; |
| 1799 result.PrintJSON(js, true); | 2178 } |
| 2179 if (obj.IsLibrary()) { |
| 2180 LibraryCoverageFilter lf(Library::Cast(obj)); |
| 2181 CodeCoverage::PrintJSON(isolate, js, &lf); |
| 2182 return true; |
| 2183 } |
| 2184 if (obj.IsClass()) { |
| 2185 ClassCoverageFilter cf(Class::Cast(obj)); |
| 2186 CodeCoverage::PrintJSON(isolate, js, &cf); |
| 2187 return true; |
| 2188 } |
| 2189 if (obj.IsFunction()) { |
| 2190 FunctionCoverageFilter ff(Function::Cast(obj)); |
| 2191 CodeCoverage::PrintJSON(isolate, js, &ff); |
| 2192 return true; |
| 2193 } |
| 2194 PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a " |
| 2195 "script, library, class, or function", target_id); |
| 1800 return true; | 2196 return true; |
| 1801 } | 2197 } |
| 1802 | 2198 |
| 1803 | 2199 |
| 1804 static bool HandleLibrariesScriptsCoverage( | 2200 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")) { | 2201 if (!js->HasOption("line")) { |
| 1815 PrintError(js, "Missing 'line' option"); | 2202 PrintError(js, "Missing 'line' option"); |
| 1816 return true; | 2203 return true; |
| 1817 } | 2204 } |
| 1818 const char* line_option = js->LookupOption("line"); | 2205 const char* line_option = js->LookupOption("line"); |
| 1819 intptr_t line = -1; | 2206 intptr_t line = -1; |
| 1820 if (!GetIntegerId(line_option, &line)) { | 2207 if (!GetIntegerId(line_option, &line)) { |
| 1821 PrintError(js, "Invalid 'line' value: %s", line_option); | 2208 PrintError(js, "Invalid 'line' value: %s is not an integer", line_option); |
| 1822 return true; | 2209 return true; |
| 1823 } | 2210 } |
| 2211 const char* script_id = js->LookupOption("script"); |
| 2212 Object& obj = Object::Handle(LookupHeapObject(isolate, script_id, NULL)); |
| 2213 if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) { |
| 2214 PrintError(js, "Invalid 'script' value: no script with id '%s'", script_id); |
| 2215 return true; |
| 2216 } |
| 2217 const Script& script = Script::Cast(obj); |
| 1824 const String& script_url = String::Handle(script.url()); | 2218 const String& script_url = String::Handle(script.url()); |
| 1825 SourceBreakpoint* bpt = | 2219 SourceBreakpoint* bpt = |
| 1826 isolate->debugger()->SetBreakpointAtLine(script_url, line); | 2220 isolate->debugger()->SetBreakpointAtLine(script_url, line); |
| 1827 if (bpt == NULL) { | 2221 if (bpt == NULL) { |
| 1828 PrintError(js, "Unable to set breakpoint at line %s", line_option); | 2222 PrintError(js, "Unable to set breakpoint at line %s", line_option); |
| 1829 return true; | 2223 return true; |
| 1830 } | 2224 } |
| 1831 bpt->PrintJSON(js); | 2225 bpt->PrintJSON(js); |
| 1832 return true; | 2226 return true; |
| 1833 } | 2227 } |
| 1834 | 2228 |
| 1835 | 2229 |
| 2230 static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) { |
| 2231 if (!js->HasOption("breakpointId")) { |
| 2232 PrintError(js, "Missing 'breakpointId' option"); |
| 2233 return true; |
| 2234 } |
| 2235 const char* bpt_id = js->LookupOption("breakpointId"); |
| 2236 SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id); |
| 2237 if (bpt == NULL) { |
| 2238 fprintf(stderr, "ERROR1"); |
| 2239 PrintError(js, "Invalid 'breakpointId' value: no breakpoint with id '%s'", |
| 2240 bpt_id); |
| 2241 return true; |
| 2242 } |
| 2243 isolate->debugger()->RemoveBreakpoint(bpt->id()); |
| 2244 |
| 2245 fprintf(stderr, "SUCCESS"); |
| 2246 // TODO(turnidge): Consider whether the 'Success' type is proper. |
| 2247 JSONObject jsobj(js); |
| 2248 jsobj.AddProperty("type", "Success"); |
| 2249 jsobj.AddProperty("id", ""); |
| 2250 return true; |
| 2251 } |
| 2252 |
| 2253 |
| 1836 static bool HandleLibrariesScripts(Isolate* isolate, | 2254 static bool HandleLibrariesScripts(Isolate* isolate, |
| 1837 const Library& lib, | 2255 const Library& lib, |
| 1838 JSONStream* js) { | 2256 JSONStream* js) { |
| 1839 if (js->num_arguments() > 5) { | 2257 if (js->num_arguments() > 5) { |
| 1840 PrintError(js, "Command too long"); | 2258 PrintError(js, "Command too long"); |
| 1841 return true; | 2259 return true; |
| 1842 } else if (js->num_arguments() < 4) { | 2260 } else if (js->num_arguments() < 4) { |
| 1843 PrintError(js, "Must specify collection object id: scripts/id"); | 2261 PrintError(js, "Must specify collection object id: scripts/id"); |
| 1844 return true; | 2262 return true; |
| 1845 } | 2263 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1857 ASSERT(!script.IsNull()); | 2275 ASSERT(!script.IsNull()); |
| 1858 script_url ^= script.url(); | 2276 script_url ^= script.url(); |
| 1859 if (script_url.Equals(requested_url)) { | 2277 if (script_url.Equals(requested_url)) { |
| 1860 break; | 2278 break; |
| 1861 } | 2279 } |
| 1862 } | 2280 } |
| 1863 if (i == loaded_scripts.Length()) { | 2281 if (i == loaded_scripts.Length()) { |
| 1864 PrintError(js, "Script %s not found", requested_url.ToCString()); | 2282 PrintError(js, "Script %s not found", requested_url.ToCString()); |
| 1865 return true; | 2283 return true; |
| 1866 } | 2284 } |
| 1867 if (js->num_arguments() == 4) { | 2285 if (js->num_arguments() > 4) { |
| 1868 script.PrintJSON(js, false); | 2286 PrintError(js, "Command too long"); |
| 1869 return true; | 2287 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 } | 2288 } |
| 1881 UNREACHABLE(); | 2289 script.PrintJSON(js, false); |
| 1882 return true; | 2290 return true; |
| 1883 } | 2291 } |
| 1884 | 2292 |
| 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 | 2293 |
| 1895 static bool HandleLibraries(Isolate* isolate, JSONStream* js) { | 2294 static bool HandleLibraries(Isolate* isolate, JSONStream* js) { |
| 1896 // TODO(johnmccutchan): Support fields and functions on libraries. | 2295 // TODO(johnmccutchan): Support fields and functions on libraries. |
| 1897 REQUIRE_COLLECTION_ID("libraries"); | 2296 REQUIRE_COLLECTION_ID("libraries"); |
| 1898 const GrowableObjectArray& libs = | 2297 const GrowableObjectArray& libs = |
| 1899 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | 2298 GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| 1900 ASSERT(!libs.IsNull()); | 2299 ASSERT(!libs.IsNull()); |
| 1901 intptr_t id = 0; | 2300 intptr_t id = 0; |
| 1902 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1), | 2301 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1), |
| 1903 id, js); | 2302 id, js); |
| 1904 Library& lib = Library::Handle(); | 2303 Library& lib = Library::Handle(); |
| 1905 lib ^= libs.At(id); | 2304 lib ^= libs.At(id); |
| 1906 ASSERT(!lib.IsNull()); | 2305 ASSERT(!lib.IsNull()); |
| 1907 if (js->num_arguments() == 2) { | 2306 if (js->num_arguments() == 2) { |
| 1908 lib.PrintJSON(js, false); | 2307 lib.PrintJSON(js, false); |
| 1909 return true; | 2308 return true; |
| 1910 } else if (js->num_arguments() >= 3) { | 2309 } else if (js->num_arguments() >= 3) { |
| 1911 const char* second = js->GetArgument(2); | 2310 const char* second = js->GetArgument(2); |
| 1912 if (strcmp(second, "eval") == 0) { | 2311 if (strcmp(second, "scripts") == 0) { |
| 1913 return HandleLibrariesEval(isolate, lib, js); | |
| 1914 } else if (strcmp(second, "scripts") == 0) { | |
| 1915 return HandleLibrariesScripts(isolate, lib, js); | 2312 return HandleLibrariesScripts(isolate, lib, js); |
| 1916 } else if (strcmp(second, "coverage") == 0) { | |
| 1917 return HandleLibrariesCoverage(isolate, lib, js); | |
| 1918 } else { | 2313 } else { |
| 1919 PrintError(js, "Invalid sub collection %s", second); | 2314 PrintError(js, "Invalid sub collection %s", second); |
| 1920 return true; | 2315 return true; |
| 1921 } | 2316 } |
| 1922 } | 2317 } |
| 1923 UNREACHABLE(); | 2318 UNREACHABLE(); |
| 1924 return true; | 2319 return true; |
| 1925 } | 2320 } |
| 1926 | 2321 |
| 1927 | 2322 |
| 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) { | 2323 static RawClass* GetMetricsClass(Isolate* isolate) { |
| 1977 const Library& prof_lib = | 2324 const Library& prof_lib = |
| 1978 Library::Handle(isolate, Library::ProfilerLibrary()); | 2325 Library::Handle(isolate, Library::ProfilerLibrary()); |
| 1979 ASSERT(!prof_lib.IsNull()); | 2326 ASSERT(!prof_lib.IsNull()); |
| 1980 const String& metrics_cls_name = | 2327 const String& metrics_cls_name = |
| 1981 String::Handle(isolate, String::New("Metrics")); | 2328 String::Handle(isolate, String::New("Metrics")); |
| 1982 ASSERT(!metrics_cls_name.IsNull()); | 2329 ASSERT(!metrics_cls_name.IsNull()); |
| 1983 const Class& metrics_cls = | 2330 const Class& metrics_cls = |
| 1984 Class::Handle(isolate, prof_lib.LookupClass(metrics_cls_name)); | 2331 Class::Handle(isolate, prof_lib.LookupClass(metrics_cls_name)); |
| 1985 ASSERT(!metrics_cls.IsNull()); | 2332 ASSERT(!metrics_cls.IsNull()); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2088 if (js->num_arguments() > 2) { | 2435 if (js->num_arguments() > 2) { |
| 2089 PrintError(js, "Command too long"); | 2436 PrintError(js, "Command too long"); |
| 2090 return true; | 2437 return true; |
| 2091 } | 2438 } |
| 2092 return HandleMetric(isolate, js, arg); | 2439 return HandleMetric(isolate, js, arg); |
| 2093 } | 2440 } |
| 2094 | 2441 |
| 2095 | 2442 |
| 2096 static bool HandleObjects(Isolate* isolate, JSONStream* js) { | 2443 static bool HandleObjects(Isolate* isolate, JSONStream* js) { |
| 2097 REQUIRE_COLLECTION_ID("objects"); | 2444 REQUIRE_COLLECTION_ID("objects"); |
| 2098 if (js->num_arguments() < 2) { | 2445 if (js->num_arguments() != 2) { |
| 2099 PrintError(js, "expected at least 2 arguments but found %" Pd "\n", | 2446 PrintError(js, "expected at least 2 arguments but found %" Pd "\n", |
| 2100 js->num_arguments()); | 2447 js->num_arguments()); |
| 2101 return true; | 2448 return true; |
| 2102 } | 2449 } |
| 2103 const char* arg = js->GetArgument(1); | 2450 const char* arg = js->GetArgument(1); |
| 2104 | 2451 |
| 2105 // Handle special non-objects first. | 2452 // Handle special non-objects first. |
| 2106 if (strcmp(arg, "optimized-out") == 0) { | 2453 if (strcmp(arg, "optimized-out") == 0) { |
| 2107 if (js->num_arguments() > 2) { | 2454 if (js->num_arguments() > 2) { |
| 2108 PrintError(js, "expected at most 2 arguments but found %" Pd "\n", | 2455 PrintError(js, "expected at most 2 arguments but found %" Pd "\n", |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2132 } | 2479 } |
| 2133 | 2480 |
| 2134 // Lookup the object. | 2481 // Lookup the object. |
| 2135 Object& obj = Object::Handle(isolate); | 2482 Object& obj = Object::Handle(isolate); |
| 2136 ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid; | 2483 ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid; |
| 2137 obj = LookupObjectId(isolate, arg, &kind); | 2484 obj = LookupObjectId(isolate, arg, &kind); |
| 2138 if (kind == ObjectIdRing::kInvalid) { | 2485 if (kind == ObjectIdRing::kInvalid) { |
| 2139 PrintError(js, "unrecognized object id '%s'", arg); | 2486 PrintError(js, "unrecognized object id '%s'", arg); |
| 2140 return true; | 2487 return true; |
| 2141 } | 2488 } |
| 2142 if (js->num_arguments() == 2) { | 2489 |
| 2143 // Print. | 2490 // Print. |
| 2144 if (kind == ObjectIdRing::kCollected) { | 2491 if (kind == ObjectIdRing::kCollected) { |
| 2145 // The object has been collected by the gc. | 2492 // The object has been collected by the gc. |
| 2146 PrintSentinel(js, "objects/collected", "<collected>"); | 2493 PrintSentinel(js, "objects/collected", "<collected>"); |
| 2147 return true; | 2494 return true; |
| 2148 } else if (kind == ObjectIdRing::kExpired) { | 2495 } else if (kind == ObjectIdRing::kExpired) { |
| 2149 // The object id has expired. | 2496 // The object id has expired. |
| 2150 PrintSentinel(js, "objects/expired", "<expired>"); | 2497 PrintSentinel(js, "objects/expired", "<expired>"); |
| 2151 return true; | |
| 2152 } | |
| 2153 obj.PrintJSON(js, false); | |
| 2154 return true; | 2498 return true; |
| 2155 } | 2499 } |
| 2156 return HandleInstanceCommands(isolate, &obj, kind, js, 2); | 2500 obj.PrintJSON(js, false); |
| 2501 return true; |
| 2157 } | 2502 } |
| 2158 | 2503 |
| 2159 | 2504 |
| 2160 static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { | 2505 static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { |
| 2161 JSONObject jsobj(js); | 2506 JSONObject jsobj(js); |
| 2162 jsobj.AddProperty("type", "ScriptList"); | 2507 jsobj.AddProperty("type", "ScriptList"); |
| 2163 jsobj.AddProperty("id", "scripts"); | 2508 jsobj.AddProperty("id", "scripts"); |
| 2164 JSONArray members(&jsobj, "members"); | 2509 JSONArray members(&jsobj, "members"); |
| 2165 const GrowableObjectArray& libs = | 2510 const GrowableObjectArray& libs = |
| 2166 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | 2511 GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2186 static bool HandleScripts(Isolate* isolate, JSONStream* js) { | 2531 static bool HandleScripts(Isolate* isolate, JSONStream* js) { |
| 2187 if (js->num_arguments() == 1) { | 2532 if (js->num_arguments() == 1) { |
| 2188 // Enumerate all scripts. | 2533 // Enumerate all scripts. |
| 2189 return HandleScriptsEnumerate(isolate, js); | 2534 return HandleScriptsEnumerate(isolate, js); |
| 2190 } | 2535 } |
| 2191 PrintError(js, "Command too long"); | 2536 PrintError(js, "Command too long"); |
| 2192 return true; | 2537 return true; |
| 2193 } | 2538 } |
| 2194 | 2539 |
| 2195 | 2540 |
| 2196 static bool HandleDebugResume(Isolate* isolate, | 2541 static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) { |
| 2197 const char* step_option, | 2542 const char* step_option = js->LookupOption("step"); |
| 2198 JSONStream* js) { | |
| 2199 if (isolate->message_handler()->paused_on_start()) { | 2543 if (isolate->message_handler()->paused_on_start()) { |
| 2200 isolate->message_handler()->set_pause_on_start(false); | 2544 isolate->message_handler()->set_pause_on_start(false); |
| 2201 JSONObject jsobj(js); | 2545 JSONObject jsobj(js); |
| 2202 jsobj.AddProperty("type", "Success"); | 2546 jsobj.AddProperty("type", "Success"); |
| 2203 jsobj.AddProperty("id", ""); | 2547 jsobj.AddProperty("id", ""); |
| 2204 return true; | 2548 return true; |
| 2205 } | 2549 } |
| 2206 if (isolate->message_handler()->paused_on_exit()) { | 2550 if (isolate->message_handler()->paused_on_exit()) { |
| 2207 isolate->message_handler()->set_pause_on_exit(false); | 2551 isolate->message_handler()->set_pause_on_exit(false); |
| 2208 JSONObject jsobj(js); | 2552 JSONObject jsobj(js); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2228 jsobj.AddProperty("type", "Success"); | 2572 jsobj.AddProperty("type", "Success"); |
| 2229 jsobj.AddProperty("id", ""); | 2573 jsobj.AddProperty("id", ""); |
| 2230 return true; | 2574 return true; |
| 2231 } | 2575 } |
| 2232 | 2576 |
| 2233 PrintError(js, "VM was not paused"); | 2577 PrintError(js, "VM was not paused"); |
| 2234 return true; | 2578 return true; |
| 2235 } | 2579 } |
| 2236 | 2580 |
| 2237 | 2581 |
| 2238 static bool HandleDebug(Isolate* isolate, JSONStream* js) { | 2582 static bool HandleIsolateGetBreakpoints(Isolate* isolate, JSONStream* js) { |
| 2239 if (js->num_arguments() == 1) { | 2583 JSONObject jsobj(js); |
| 2240 PrintError(js, "Must specify a subcommand"); | 2584 jsobj.AddProperty("type", "BreakpointList"); |
| 2241 return true; | 2585 JSONArray jsarr(&jsobj, "breakpoints"); |
| 2242 } | 2586 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); |
| 2243 const char* command = js->GetArgument(1); | 2587 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 } | 2588 } |
| 2311 | 2589 |
| 2312 | 2590 |
| 2591 static bool HandleIsolatePause(Isolate* isolate, JSONStream* js) { |
| 2592 // TODO(turnidge): Don't double-interrupt the isolate here. |
| 2593 isolate->ScheduleInterrupts(Isolate::kApiInterrupt); |
| 2594 JSONObject jsobj(js); |
| 2595 jsobj.AddProperty("type", "Success"); |
| 2596 jsobj.AddProperty("id", ""); |
| 2597 return true; |
| 2598 } |
| 2599 |
| 2600 |
| 2313 static bool HandleNullCode(uintptr_t pc, JSONStream* js) { | 2601 static bool HandleNullCode(uintptr_t pc, JSONStream* js) { |
| 2314 // TODO(turnidge): Consider adding/using Object::null_code() for | 2602 // TODO(turnidge): Consider adding/using Object::null_code() for |
| 2315 // consistent "type". | 2603 // consistent "type". |
| 2316 Object::null_object().PrintJSON(js, false); | 2604 Object::null_object().PrintJSON(js, false); |
| 2317 return true; | 2605 return true; |
| 2318 } | 2606 } |
| 2319 | 2607 |
| 2320 | 2608 |
| 2321 static bool HandleCode(Isolate* isolate, JSONStream* js) { | 2609 static bool HandleCode(Isolate* isolate, JSONStream* js) { |
| 2322 REQUIRE_COLLECTION_ID("code"); | 2610 REQUIRE_COLLECTION_ID("code"); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2366 Code& code = Code::Handle(Code::FindCode(pc, timestamp)); | 2654 Code& code = Code::Handle(Code::FindCode(pc, timestamp)); |
| 2367 if (!code.IsNull()) { | 2655 if (!code.IsNull()) { |
| 2368 code.PrintJSON(js, false); | 2656 code.PrintJSON(js, false); |
| 2369 return true; | 2657 return true; |
| 2370 } | 2658 } |
| 2371 PrintError(js, "Could not find code with id: %s", command); | 2659 PrintError(js, "Could not find code with id: %s", command); |
| 2372 return true; | 2660 return true; |
| 2373 } | 2661 } |
| 2374 | 2662 |
| 2375 | 2663 |
| 2376 static bool HandleProfile(Isolate* isolate, JSONStream* js) { | 2664 static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) { |
| 2377 if (js->num_arguments() == 2) { | 2665 JSONObject miniProfile(js); |
| 2378 const char* sub_command = js->GetArgument(1); | 2666 miniProfile.AddProperty("type", "TagProfile"); |
| 2379 if (!strcmp(sub_command, "tag")) { | 2667 miniProfile.AddProperty("id", "profile/tag"); |
| 2380 { | 2668 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile); |
| 2381 JSONObject miniProfile(js); | 2669 return true; |
| 2382 miniProfile.AddProperty("type", "TagProfile"); | 2670 } |
| 2383 miniProfile.AddProperty("id", "profile/tag"); | 2671 |
| 2384 isolate->vm_tag_counters()->PrintToJSONObject(&miniProfile); | 2672 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. | 2673 // A full profile includes disassembly of all Dart code objects. |
| 2393 // TODO(johnmccutchan): Add sub command to trigger full code dump. | 2674 // TODO(johnmccutchan): Add sub command to trigger full code dump. |
| 2394 bool full_profile = false; | 2675 bool full_profile = false; |
| 2395 const char* tags_option = js->LookupOption("tags"); | 2676 const char* tags_option = js->LookupOption("tags"); |
| 2396 Profiler::TagOrder tag_order = Profiler::kUserVM; | 2677 Profiler::TagOrder tag_order = Profiler::kUserVM; |
| 2397 if (js->HasOption("tags")) { | 2678 if (js->HasOption("tags")) { |
| 2398 if (js->OptionIs("tags", "hide")) { | 2679 if (js->OptionIs("tags", "None")) { |
| 2399 tag_order = Profiler::kNoTags; | 2680 tag_order = Profiler::kNoTags; |
| 2400 } else if (js->OptionIs("tags", "uv")) { | 2681 } else if (js->OptionIs("tags", "UserVM")) { |
| 2401 tag_order = Profiler::kUserVM; | 2682 tag_order = Profiler::kUserVM; |
| 2402 } else if (js->OptionIs("tags", "u")) { | 2683 } else if (js->OptionIs("tags", "UserOnly")) { |
| 2403 tag_order = Profiler::kUser; | 2684 tag_order = Profiler::kUser; |
| 2404 } else if (js->OptionIs("tags", "vu")) { | 2685 } else if (js->OptionIs("tags", "VMUser")) { |
| 2405 tag_order = Profiler::kVMUser; | 2686 tag_order = Profiler::kVMUser; |
| 2406 } else if (js->OptionIs("tags", "v")) { | 2687 } else if (js->OptionIs("tags", "VMOnly")) { |
| 2407 tag_order = Profiler::kVM; | 2688 tag_order = Profiler::kVM; |
| 2408 } else { | 2689 } else { |
| 2409 PrintError(js, "Invalid tags option value: %s\n", tags_option); | 2690 PrintError(js, "Invalid tags option value: %s\n", tags_option); |
| 2410 return true; | 2691 return true; |
| 2411 } | 2692 } |
| 2412 } | 2693 } |
| 2413 Profiler::PrintJSON(isolate, js, full_profile, tag_order); | 2694 Profiler::PrintJSON(isolate, js, full_profile, tag_order); |
| 2414 return true; | 2695 return true; |
| 2415 } | 2696 } |
| 2416 | 2697 |
| 2417 static bool HandleCoverage(Isolate* isolate, JSONStream* js) { | |
| 2418 CodeCoverage::PrintJSON(isolate, js, NULL); | |
| 2419 return true; | |
| 2420 } | |
| 2421 | |
| 2422 | 2698 |
| 2423 static bool HandleAllocationProfile(Isolate* isolate, JSONStream* js) { | 2699 static bool HandleIsolateGetAllocationProfile(Isolate* isolate, |
| 2700 JSONStream* js) { |
| 2424 bool should_reset_accumulator = false; | 2701 bool should_reset_accumulator = false; |
| 2425 bool should_collect = false; | 2702 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")) { | 2703 if (js->HasOption("reset")) { |
| 2431 if (js->OptionIs("reset", "true")) { | 2704 if (js->OptionIs("reset", "true")) { |
| 2432 should_reset_accumulator = true; | 2705 should_reset_accumulator = true; |
| 2433 } else { | 2706 } else { |
| 2434 PrintError(js, "Unrecognized reset option '%s'", | 2707 PrintError(js, "Unrecognized reset option '%s'", |
| 2435 js->LookupOption("reset")); | 2708 js->LookupOption("reset")); |
| 2436 return true; | 2709 return true; |
| 2437 } | 2710 } |
| 2438 } | 2711 } |
| 2439 if (js->HasOption("gc")) { | 2712 if (js->HasOption("gc")) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2502 if ((id < 0) || (id >= table_size) || (table.At(id) == Object::null())) { | 2775 if ((id < 0) || (id >= table_size) || (table.At(id) == Object::null())) { |
| 2503 PrintError(js, "%" Pd " is not a valid typearguments id.", id); | 2776 PrintError(js, "%" Pd " is not a valid typearguments id.", id); |
| 2504 return true; | 2777 return true; |
| 2505 } | 2778 } |
| 2506 type_args ^= table.At(id); | 2779 type_args ^= table.At(id); |
| 2507 type_args.PrintJSON(js, false); | 2780 type_args.PrintJSON(js, false); |
| 2508 return true; | 2781 return true; |
| 2509 } | 2782 } |
| 2510 | 2783 |
| 2511 | 2784 |
| 2512 static bool HandleHeapMap(Isolate* isolate, JSONStream* js) { | 2785 static bool HandleIsolateGetHeapMap(Isolate* isolate, JSONStream* js) { |
| 2513 isolate->heap()->PrintHeapMapToJSONStream(isolate, js); | 2786 isolate->heap()->PrintHeapMapToJSONStream(isolate, js); |
| 2514 return true; | 2787 return true; |
| 2515 } | 2788 } |
| 2516 | 2789 |
| 2517 | 2790 |
| 2518 static bool HandleGraph(Isolate* isolate, JSONStream* js) { | 2791 static bool HandleIsolateRequestHeapSnapshot(Isolate* isolate, JSONStream* js) { |
| 2519 Service::SendGraphEvent(isolate); | 2792 Service::SendGraphEvent(isolate); |
| 2520 // TODO(koda): Provide some id that ties this request to async response(s). | 2793 // TODO(koda): Provide some id that ties this request to async response(s). |
| 2521 JSONObject jsobj(js); | 2794 JSONObject jsobj(js); |
| 2522 jsobj.AddProperty("type", "OK"); | 2795 jsobj.AddProperty("type", "OK"); |
| 2523 jsobj.AddProperty("id", "ok"); | 2796 jsobj.AddProperty("id", "ok"); |
| 2524 return true; | 2797 return true; |
| 2525 } | 2798 } |
| 2526 | 2799 |
| 2527 | 2800 |
| 2528 void Service::SendGraphEvent(Isolate* isolate) { | 2801 void Service::SendGraphEvent(Isolate* isolate) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2599 | 2872 |
| 2600 | 2873 |
| 2601 static bool HandleMalformedObject(Isolate* isolate, JSONStream* js) { | 2874 static bool HandleMalformedObject(Isolate* isolate, JSONStream* js) { |
| 2602 JSONObject jsobj(js); | 2875 JSONObject jsobj(js); |
| 2603 jsobj.AddProperty("bart", "simpson"); | 2876 jsobj.AddProperty("bart", "simpson"); |
| 2604 return true; | 2877 return true; |
| 2605 } | 2878 } |
| 2606 | 2879 |
| 2607 | 2880 |
| 2608 static IsolateMessageHandlerEntry isolate_handlers[] = { | 2881 static IsolateMessageHandlerEntry isolate_handlers[] = { |
| 2609 { "_malformedjson", HandleMalformedJson }, | 2882 { "_malformedjson", HandleMalformedJson }, // debug |
| 2610 { "_malformedobject", HandleMalformedObject }, | 2883 { "_malformedobject", HandleMalformedObject }, // debug |
| 2611 { "_echo", HandleIsolateEcho }, | 2884 { "_echo", HandleIsolateEcho }, // debug |
| 2612 { "", HandleIsolate }, | 2885 { "", HandleIsolate }, // getObject |
| 2613 { "address", HandleAddress }, | 2886 { "address", HandleAddress }, // to do |
| 2614 { "allocationprofile", HandleAllocationProfile }, | 2887 { "classes", HandleClasses }, // getObject |
| 2615 { "classes", HandleClasses }, | 2888 { "code", HandleCode }, // getObject |
| 2616 { "code", HandleCode }, | 2889 { "libraries", HandleLibraries }, // getObject |
| 2617 { "coverage", HandleCoverage }, | 2890 { "metrics", HandleMetrics }, // to do - complex? |
| 2618 { "debug", HandleDebug }, | 2891 { "objects", HandleObjects }, // getObject |
| 2619 { "graph", HandleGraph }, | 2892 { "scripts", HandleScripts }, // getObject |
| 2620 { "heapmap", HandleHeapMap }, | 2893 { "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 }; | 2894 }; |
| 2629 | 2895 |
| 2630 | 2896 |
| 2631 static IsolateMessageHandler FindIsolateMessageHandler(const char* command) { | 2897 static IsolateMessageHandler FindIsolateMessageHandler(const char* command) { |
| 2632 intptr_t num_message_handlers = sizeof(isolate_handlers) / | 2898 intptr_t num_message_handlers = sizeof(isolate_handlers) / |
| 2633 sizeof(isolate_handlers[0]); | 2899 sizeof(isolate_handlers[0]); |
| 2634 for (intptr_t i = 0; i < num_message_handlers; i++) { | 2900 for (intptr_t i = 0; i < num_message_handlers; i++) { |
| 2635 const IsolateMessageHandlerEntry& entry = isolate_handlers[i]; | 2901 const IsolateMessageHandlerEntry& entry = isolate_handlers[i]; |
| 2636 if (strcmp(command, entry.command) == 0) { | 2902 if (strcmp(command, entry.command) == 0) { |
| 2637 return entry.handler; | 2903 return entry.handler; |
| 2638 } | 2904 } |
| 2639 } | 2905 } |
| 2640 if (FLAG_trace_service) { | 2906 if (FLAG_trace_service) { |
| 2641 OS::Print("vm-service: No isolate message handler for <%s>.\n", command); | 2907 OS::Print("vm-service: No isolate message handler for <%s>.\n", command); |
| 2642 } | 2908 } |
| 2643 return NULL; | 2909 return NULL; |
| 2644 } | 2910 } |
| 2645 | 2911 |
| 2646 | 2912 |
| 2913 static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) { |
| 2914 const char* id = js->LookupOption("id"); |
| 2915 if (id == NULL) { |
| 2916 // TODO(turnidge): Print the isolate here instead. |
| 2917 PrintError(js, "GetObject expects an 'id' parameter\n", |
| 2918 js->num_arguments()); |
| 2919 return true; |
| 2920 } |
| 2921 |
| 2922 // Handle heap objects. |
| 2923 ObjectIdRing::LookupResult lookup_result; |
| 2924 const Object& obj = |
| 2925 Object::Handle(LookupHeapObject(isolate, id, &lookup_result)); |
| 2926 if (obj.raw() != Object::sentinel().raw()) { |
| 2927 // We found a heap object for this id. Return it. |
| 2928 obj.PrintJSON(js, false); |
| 2929 return true; |
| 2930 } else if (lookup_result == ObjectIdRing::kCollected) { |
| 2931 PrintSentinel(js, "objects/collected", "<collected>"); |
| 2932 } else if (lookup_result == ObjectIdRing::kExpired) { |
| 2933 PrintSentinel(js, "objects/expired", "<expired>"); |
| 2934 } |
| 2935 |
| 2936 // Handle non-heap objects. |
| 2937 SourceBreakpoint* bpt = LookupBreakpoint(isolate, id); |
| 2938 if (bpt != NULL) { |
| 2939 bpt->PrintJSON(js); |
| 2940 return true; |
| 2941 } |
| 2942 |
| 2943 PrintError(js, "Unrecognized object id: %s\n", id); |
| 2944 return true; |
| 2945 } |
| 2946 |
| 2947 |
| 2948 static IsolateMessageHandlerEntry isolate_handlers_new[] = { |
| 2949 { "getObject", HandleIsolateGetObject }, |
| 2950 { "getBreakpoints", HandleIsolateGetBreakpoints }, |
| 2951 { "pause", HandleIsolatePause }, |
| 2952 { "resume", HandleIsolateResume }, |
| 2953 { "getStack", HandleIsolateGetStack }, |
| 2954 { "getCpuProfile", HandleIsolateGetCpuProfile }, |
| 2955 { "getTagProfile", HandleIsolateGetTagProfile }, |
| 2956 { "getAllocationProfile", HandleIsolateGetAllocationProfile }, |
| 2957 { "getHeapMap", HandleIsolateGetHeapMap }, |
| 2958 { "addBreakpoint", HandleIsolateAddBreakpoint }, |
| 2959 { "removeBreakpoint", HandleIsolateRemoveBreakpoint }, |
| 2960 { "getCoverage", HandleIsolateGetCoverage }, |
| 2961 { "eval", HandleIsolateEval }, |
| 2962 { "getRetainedSize", HandleIsolateGetRetainedSize }, |
| 2963 { "getRetainingPath", HandleIsolateGetRetainingPath }, |
| 2964 { "getInboundReferences", HandleIsolateGetInboundReferences }, |
| 2965 { "getInstances", HandleIsolateGetInstances }, |
| 2966 { "requestHeapSnapshot", HandleIsolateRequestHeapSnapshot }, |
| 2967 }; |
| 2968 |
| 2969 |
| 2970 static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command) { |
| 2971 intptr_t num_message_handlers = sizeof(isolate_handlers_new) / |
| 2972 sizeof(isolate_handlers_new[0]); |
| 2973 for (intptr_t i = 0; i < num_message_handlers; i++) { |
| 2974 const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i]; |
| 2975 if (strcmp(command, entry.command) == 0) { |
| 2976 return entry.handler; |
| 2977 } |
| 2978 } |
| 2979 if (FLAG_trace_service) { |
| 2980 OS::Print("Service has no isolate message handler for <%s>\n", command); |
| 2981 } |
| 2982 return NULL; |
| 2983 } |
| 2984 |
| 2985 |
| 2647 void Service::HandleRootMessage(const Instance& msg) { | 2986 void Service::HandleRootMessage(const Instance& msg) { |
| 2648 Isolate* isolate = Isolate::Current(); | 2987 Isolate* isolate = Isolate::Current(); |
| 2649 ASSERT(!msg.IsNull()); | 2988 ASSERT(!msg.IsNull()); |
| 2650 ASSERT(msg.IsArray()); | 2989 ASSERT(msg.IsArray()); |
| 2651 | 2990 |
| 2652 { | 2991 { |
| 2653 StackZone zone(isolate); | 2992 StackZone zone(isolate); |
| 2654 HANDLESCOPE(isolate); | 2993 HANDLESCOPE(isolate); |
| 2655 | 2994 |
| 2656 const Array& message = Array::Cast(msg); | 2995 const Array& message = Array::Cast(msg); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2997 while (current != NULL) { | 3336 while (current != NULL) { |
| 2998 if (strcmp(name, current->name()) == 0) { | 3337 if (strcmp(name, current->name()) == 0) { |
| 2999 return current; | 3338 return current; |
| 3000 } | 3339 } |
| 3001 current = current->next(); | 3340 current = current->next(); |
| 3002 } | 3341 } |
| 3003 return NULL; | 3342 return NULL; |
| 3004 } | 3343 } |
| 3005 | 3344 |
| 3006 } // namespace dart | 3345 } // namespace dart |
| OLD | NEW |