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