| 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 "vm/cpu.h" | 7 #include "vm/cpu.h" |
| 8 #include "vm/dart_entry.h" | 8 #include "vm/dart_entry.h" |
| 9 #include "vm/debugger.h" | 9 #include "vm/debugger.h" |
| 10 #include "vm/heap_histogram.h" | 10 #include "vm/heap_histogram.h" |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 jsobj.AddProperty("name", isolate->name()); | 189 jsobj.AddProperty("name", isolate->name()); |
| 190 } | 190 } |
| 191 | 191 |
| 192 | 192 |
| 193 static void HandleStackTrace(Isolate* isolate, JSONStream* js) { | 193 static void HandleStackTrace(Isolate* isolate, JSONStream* js) { |
| 194 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); | 194 DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); |
| 195 JSONObject jsobj(js); | 195 JSONObject jsobj(js); |
| 196 jsobj.AddProperty("type", "StackTrace"); | 196 jsobj.AddProperty("type", "StackTrace"); |
| 197 JSONArray jsarr(&jsobj, "members"); | 197 JSONArray jsarr(&jsobj, "members"); |
| 198 intptr_t n_frames = stack->Length(); | 198 intptr_t n_frames = stack->Length(); |
| 199 String& url = String::Handle(); | |
| 200 String& function = String::Handle(); | 199 String& function = String::Handle(); |
| 200 Script& script = Script::Handle(); |
| 201 for (int i = 0; i < n_frames; i++) { | 201 for (int i = 0; i < n_frames; i++) { |
| 202 ActivationFrame* frame = stack->FrameAt(i); | 202 ActivationFrame* frame = stack->FrameAt(i); |
| 203 url ^= frame->SourceUrl(); | 203 script ^= frame->SourceScript(); |
| 204 function ^= frame->function().UserVisibleName(); | 204 function ^= frame->function().UserVisibleName(); |
| 205 JSONObject jsobj(&jsarr); | 205 JSONObject jsobj(&jsarr); |
| 206 jsobj.AddProperty("name", function.ToCString()); | 206 jsobj.AddProperty("name", function.ToCString()); |
| 207 jsobj.AddProperty("url", url.ToCString()); | 207 jsobj.AddProperty("script", script); |
| 208 jsobj.AddProperty("line", frame->LineNumber()); | 208 jsobj.AddProperty("line", frame->LineNumber()); |
| 209 jsobj.AddProperty("function", frame->function()); | 209 jsobj.AddProperty("function", frame->function()); |
| 210 jsobj.AddProperty("code", frame->code()); | 210 jsobj.AddProperty("code", frame->code()); |
| 211 } | 211 } |
| 212 } | 212 } |
| 213 | 213 |
| 214 | 214 |
| 215 static void HandleObjectHistogram(Isolate* isolate, JSONStream* js) { | 215 static void HandleObjectHistogram(Isolate* isolate, JSONStream* js) { |
| 216 ObjectHistogram* histogram = Isolate::Current()->object_histogram(); | 216 ObjectHistogram* histogram = Isolate::Current()->object_histogram(); |
| 217 if (histogram == NULL) { | 217 if (histogram == NULL) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 232 | 232 |
| 233 | 233 |
| 234 // Print an error message if there is no ID argument. | 234 // Print an error message if there is no ID argument. |
| 235 #define REQUIRE_COLLECTION_ID(collection) \ | 235 #define REQUIRE_COLLECTION_ID(collection) \ |
| 236 if (js->num_arguments() == 1) { \ | 236 if (js->num_arguments() == 1) { \ |
| 237 PrintError(js, "Must specify collection object id: /%s/id", collection); \ | 237 PrintError(js, "Must specify collection object id: /%s/id", collection); \ |
| 238 return; \ | 238 return; \ |
| 239 } | 239 } |
| 240 | 240 |
| 241 | 241 |
| 242 #define CHECK_COLLECTION_ID_BOUNDS(collection, length, arg, id, js) \ |
| 243 if (!GetIntegerId(arg, &id)) { \ |
| 244 PrintError(js, "Must specify collection object id: %s/id", collection); \ |
| 245 return; \ |
| 246 } \ |
| 247 if ((id < 0) || (id >= length)) { \ |
| 248 PrintError(js, "%s id (%" Pd ") must be in [0, %" Pd ").", collection, id, \ |
| 249 length); \ |
| 250 return; \ |
| 251 } |
| 252 |
| 253 |
| 254 static bool GetIntegerId(const char* s, intptr_t* id) { |
| 255 if ((s == NULL) || (*s == '\0')) { |
| 256 // Empty string. |
| 257 return false; |
| 258 } |
| 259 if (id == NULL) { |
| 260 // No id pointer. |
| 261 return false; |
| 262 } |
| 263 intptr_t r = 0; |
| 264 char* end_ptr = NULL; |
| 265 r = strtol(s, &end_ptr, 10); |
| 266 if (end_ptr == s) { |
| 267 // String was not advanced at all, cannot be valid. |
| 268 return false; |
| 269 } |
| 270 *id = r; |
| 271 return true; |
| 272 } |
| 273 |
| 274 |
| 275 static void HandleClassesClosures(Isolate* isolate, const Class& cls, |
| 276 JSONStream* js) { |
| 277 const GrowableObjectArray& closures = |
| 278 GrowableObjectArray::Handle(cls.closures()); |
| 279 intptr_t id; |
| 280 if (js->num_arguments() > 4) { |
| 281 PrintError(js, "Command too long"); |
| 282 return; |
| 283 } |
| 284 CHECK_COLLECTION_ID_BOUNDS("closures", closures.Length(), js->GetArgument(3), |
| 285 id, js); |
| 286 Function& function = Function::Handle(); |
| 287 function ^= closures.At(id); |
| 288 ASSERT(!function.IsNull()); |
| 289 function.PrintToJSONStream(js, false); |
| 290 } |
| 291 |
| 292 |
| 293 static void HandleClassesFunctions(Isolate* isolate, const Class& cls, |
| 294 JSONStream* js) { |
| 295 const Array& functions = |
| 296 Array::Handle(cls.functions()); |
| 297 intptr_t id; |
| 298 if (js->num_arguments() > 4) { |
| 299 PrintError(js, "Command too long"); |
| 300 return; |
| 301 } |
| 302 CHECK_COLLECTION_ID_BOUNDS("functions", functions.Length(), |
| 303 js->GetArgument(3), id, js); |
| 304 Function& function = Function::Handle(); |
| 305 function ^= functions.At(id); |
| 306 ASSERT(!function.IsNull()); |
| 307 function.PrintToJSONStream(js, false); |
| 308 } |
| 309 |
| 310 |
| 311 static void HandleClassesFields(Isolate* isolate, const Class& cls, |
| 312 JSONStream* js) { |
| 313 const Array& fields = |
| 314 Array::Handle(cls.fields()); |
| 315 intptr_t id; |
| 316 if (js->num_arguments() > 4) { |
| 317 PrintError(js, "Command too long"); |
| 318 return; |
| 319 } |
| 320 CHECK_COLLECTION_ID_BOUNDS("fields", fields.Length(), js->GetArgument(3), |
| 321 id, js); |
| 322 Field& field = Field::Handle(); |
| 323 field ^= fields.At(id); |
| 324 ASSERT(!field.IsNull()); |
| 325 field.PrintToJSONStream(js, false); |
| 326 } |
| 327 |
| 328 |
| 242 static void HandleClasses(Isolate* isolate, JSONStream* js) { | 329 static void HandleClasses(Isolate* isolate, JSONStream* js) { |
| 243 if (js->num_arguments() == 1) { | 330 if (js->num_arguments() == 1) { |
| 244 ClassTable* table = isolate->class_table(); | 331 ClassTable* table = isolate->class_table(); |
| 245 table->PrintToJSONStream(js); | 332 table->PrintToJSONStream(js); |
| 246 return; | 333 return; |
| 247 } | 334 } |
| 248 ASSERT(js->num_arguments() >= 2); | 335 ASSERT(js->num_arguments() >= 2); |
| 249 intptr_t id = atoi(js->GetArgument(1)); | 336 intptr_t id; |
| 337 if (!GetIntegerId(js->GetArgument(1), &id)) { |
| 338 PrintError(js, "Must specify collection object id: /classes/id"); |
| 339 return; |
| 340 } |
| 250 ClassTable* table = isolate->class_table(); | 341 ClassTable* table = isolate->class_table(); |
| 251 if (!table->IsValidIndex(id)) { | 342 if (!table->IsValidIndex(id)) { |
| 252 Object::null_object().PrintToJSONStream(js, false); | 343 PrintError(js, "%" Pd " is not a valid class id.", id);; |
| 253 } else { | 344 return; |
| 254 Class& cls = Class::Handle(table->At(id)); | 345 } |
| 346 Class& cls = Class::Handle(table->At(id)); |
| 347 if (js->num_arguments() == 2) { |
| 255 cls.PrintToJSONStream(js, false); | 348 cls.PrintToJSONStream(js, false); |
| 349 return; |
| 350 } else if (js->num_arguments() >= 3) { |
| 351 const char* second = js->GetArgument(2); |
| 352 if (!strcmp(second, "closures")) { |
| 353 HandleClassesClosures(isolate, cls, js); |
| 354 } else if (!strcmp(second, "fields")) { |
| 355 HandleClassesFields(isolate, cls, js); |
| 356 } else if (!strcmp(second, "functions")) { |
| 357 HandleClassesFunctions(isolate, cls, js); |
| 358 } else { |
| 359 PrintError(js, "Invalid sub collection %s", second); |
| 360 } |
| 361 return; |
| 256 } | 362 } |
| 363 UNREACHABLE(); |
| 257 } | 364 } |
| 258 | 365 |
| 259 | 366 |
| 260 static void HandleLibrary(Isolate* isolate, JSONStream* js) { | 367 static void HandleLibrary(Isolate* isolate, JSONStream* js) { |
| 261 if (js->num_arguments() == 1) { | 368 if (js->num_arguments() == 1) { |
| 262 const Library& lib = | 369 const Library& lib = |
| 263 Library::Handle(isolate->object_store()->root_library()); | 370 Library::Handle(isolate->object_store()->root_library()); |
| 264 lib.PrintToJSONStream(js, false); | 371 lib.PrintToJSONStream(js, false); |
| 265 return; | 372 return; |
| 266 } | 373 } |
| 267 PrintGenericError(js); | 374 PrintGenericError(js); |
| 268 } | 375 } |
| 269 | 376 |
| 270 | 377 |
| 378 static void HandleLibraries(Isolate* isolate, JSONStream* js) { |
| 379 // TODO(johnmccutchan): Support fields and functions on libraries. |
| 380 REQUIRE_COLLECTION_ID("libraries"); |
| 381 const GrowableObjectArray& libs = |
| 382 GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| 383 ASSERT(!libs.IsNull()); |
| 384 intptr_t id = 0; |
| 385 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1), |
| 386 id, js); |
| 387 Library& lib = Library::Handle(); |
| 388 lib ^= libs.At(id); |
| 389 ASSERT(!lib.IsNull()); |
| 390 lib.PrintToJSONStream(js, false); |
| 391 } |
| 392 |
| 393 |
| 271 static void HandleObjects(Isolate* isolate, JSONStream* js) { | 394 static void HandleObjects(Isolate* isolate, JSONStream* js) { |
| 272 REQUIRE_COLLECTION_ID("objects"); | 395 REQUIRE_COLLECTION_ID("objects"); |
| 273 ASSERT(js->num_arguments() >= 2); | 396 ASSERT(js->num_arguments() >= 2); |
| 274 ObjectIdRing* ring = isolate->object_id_ring(); | 397 ObjectIdRing* ring = isolate->object_id_ring(); |
| 275 ASSERT(ring != NULL); | 398 ASSERT(ring != NULL); |
| 276 intptr_t id = atoi(js->GetArgument(1)); | 399 intptr_t id = -1; |
| 400 if (!GetIntegerId(js->GetArgument(1), &id)) { |
| 401 Object::null_object().PrintToJSONStream(js, false); |
| 402 return; |
| 403 } |
| 277 Object& obj = Object::Handle(ring->GetObjectForId(id)); | 404 Object& obj = Object::Handle(ring->GetObjectForId(id)); |
| 278 obj.PrintToJSONStream(js, false); | 405 obj.PrintToJSONStream(js, false); |
| 279 } | 406 } |
| 280 | 407 |
| 281 | 408 |
| 409 |
| 410 static void HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { |
| 411 JSONObject jsobj(js); |
| 412 jsobj.AddProperty("type", "ScriptList"); |
| 413 { |
| 414 JSONArray members(&jsobj, "members"); |
| 415 const GrowableObjectArray& libs = |
| 416 GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| 417 int num_libs = libs.Length(); |
| 418 Library &lib = Library::Handle(); |
| 419 Script& script = Script::Handle(); |
| 420 for (intptr_t i = 0; i < num_libs; i++) { |
| 421 lib ^= libs.At(i); |
| 422 ASSERT(!lib.IsNull()); |
| 423 ASSERT(Smi::IsValid(lib.index())); |
| 424 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); |
| 425 ASSERT(!loaded_scripts.IsNull()); |
| 426 intptr_t num_scripts = loaded_scripts.Length(); |
| 427 for (intptr_t i = 0; i < num_scripts; i++) { |
| 428 script ^= loaded_scripts.At(i); |
| 429 members.AddValue(script); |
| 430 } |
| 431 } |
| 432 } |
| 433 } |
| 434 |
| 435 |
| 436 static void HandleScriptsFetch(Isolate* isolate, JSONStream* js) { |
| 437 const GrowableObjectArray& libs = |
| 438 GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
| 439 int num_libs = libs.Length(); |
| 440 Library &lib = Library::Handle(); |
| 441 Script& script = Script::Handle(); |
| 442 String& url = String::Handle(); |
| 443 const String& id = String::Handle(String::New(js->GetArgument(1))); |
| 444 ASSERT(!id.IsNull()); |
| 445 // The id is the url of the script % encoded, decode it. |
| 446 String& requested_url = String::Handle(String::DecodeURI(id)); |
| 447 for (intptr_t i = 0; i < num_libs; i++) { |
| 448 lib ^= libs.At(i); |
| 449 ASSERT(!lib.IsNull()); |
| 450 ASSERT(Smi::IsValid(lib.index())); |
| 451 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); |
| 452 ASSERT(!loaded_scripts.IsNull()); |
| 453 intptr_t num_scripts = loaded_scripts.Length(); |
| 454 for (intptr_t i = 0; i < num_scripts; i++) { |
| 455 script ^= loaded_scripts.At(i); |
| 456 ASSERT(!script.IsNull()); |
| 457 url ^= script.url(); |
| 458 if (url.Equals(requested_url)) { |
| 459 script.PrintToJSONStream(js, false); |
| 460 return; |
| 461 } |
| 462 } |
| 463 } |
| 464 PrintError(js, "Cannot find script %s\n", requested_url.ToCString()); |
| 465 } |
| 466 |
| 467 |
| 468 static void HandleScripts(Isolate* isolate, JSONStream* js) { |
| 469 if (js->num_arguments() == 1) { |
| 470 // Enumerate all scripts. |
| 471 HandleScriptsEnumerate(isolate, js); |
| 472 } else if (js->num_arguments() == 2) { |
| 473 // Fetch specific script. |
| 474 HandleScriptsFetch(isolate, js); |
| 475 } else { |
| 476 PrintError(js, "Command too long"); |
| 477 } |
| 478 } |
| 479 |
| 480 |
| 282 static void HandleDebug(Isolate* isolate, JSONStream* js) { | 481 static void HandleDebug(Isolate* isolate, JSONStream* js) { |
| 283 if (js->num_arguments() == 1) { | 482 if (js->num_arguments() == 1) { |
| 284 PrintError(js, "Must specify a subcommand"); | 483 PrintError(js, "Must specify a subcommand"); |
| 285 return; | 484 return; |
| 286 } | 485 } |
| 287 const char* command = js->GetArgument(1); | 486 const char* command = js->GetArgument(1); |
| 288 if (!strcmp(command, "breakpoints")) { | 487 if (!strcmp(command, "breakpoints")) { |
| 289 if (js->num_arguments() == 2) { | 488 if (js->num_arguments() == 2) { |
| 290 // Print breakpoint list. | 489 // Print breakpoint list. |
| 291 JSONObject jsobj(js); | 490 JSONObject jsobj(js); |
| 292 jsobj.AddProperty("type", "BreakpointList"); | 491 jsobj.AddProperty("type", "BreakpointList"); |
| 293 JSONArray jsarr(&jsobj, "breakpoints"); | 492 JSONArray jsarr(&jsobj, "breakpoints"); |
| 294 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); | 493 isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr); |
| 295 | 494 |
| 296 } else if (js->num_arguments() == 3) { | 495 } else if (js->num_arguments() == 3) { |
| 297 // Print individual breakpoint. | 496 // Print individual breakpoint. |
| 298 intptr_t id = atoi(js->GetArgument(2)); | 497 intptr_t id = 0; |
| 299 SourceBreakpoint* bpt = isolate->debugger()->GetBreakpointById(id); | 498 SourceBreakpoint* bpt = NULL; |
| 499 if (GetIntegerId(js->GetArgument(2), &id)) { |
| 500 bpt = isolate->debugger()->GetBreakpointById(id); |
| 501 } |
| 300 if (bpt != NULL) { | 502 if (bpt != NULL) { |
| 301 bpt->PrintToJSONStream(js); | 503 bpt->PrintToJSONStream(js); |
| 302 } else { | 504 } else { |
| 303 PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2)); | 505 PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2)); |
| 304 } | 506 } |
| 305 | 507 |
| 306 } else { | 508 } else { |
| 307 PrintError(js, "Command too long"); | 509 PrintError(js, "Command too long"); |
| 308 } | 510 } |
| 309 } else { | 511 } else { |
| 310 PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1)); | 512 PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1)); |
| 311 } | 513 } |
| 312 } | 514 } |
| 313 | 515 |
| 314 | 516 |
| 315 static void HandleCpu(Isolate* isolate, JSONStream* js) { | 517 static void HandleCpu(Isolate* isolate, JSONStream* js) { |
| 316 JSONObject jsobj(js); | 518 JSONObject jsobj(js); |
| 317 jsobj.AddProperty("type", "CPU"); | 519 jsobj.AddProperty("type", "CPU"); |
| 318 jsobj.AddProperty("architecture", CPU::Id()); | 520 jsobj.AddProperty("architecture", CPU::Id()); |
| 319 } | 521 } |
| 320 | 522 |
| 321 | 523 |
| 322 static ServiceMessageHandlerEntry __message_handlers[] = { | 524 static ServiceMessageHandlerEntry __message_handlers[] = { |
| 323 { "_echo", HandleEcho }, | 525 { "_echo", HandleEcho }, |
| 324 { "classes", HandleClasses }, | 526 { "classes", HandleClasses }, |
| 325 { "cpu", HandleCpu }, | 527 { "cpu", HandleCpu }, |
| 326 { "debug", HandleDebug }, | 528 { "debug", HandleDebug }, |
| 529 { "libraries", HandleLibraries }, |
| 327 { "library", HandleLibrary }, | 530 { "library", HandleLibrary }, |
| 328 { "name", HandleName }, | 531 { "name", HandleName }, |
| 329 { "objecthistogram", HandleObjectHistogram}, | 532 { "objecthistogram", HandleObjectHistogram}, |
| 330 { "objects", HandleObjects }, | 533 { "objects", HandleObjects }, |
| 534 { "scripts", HandleScripts }, |
| 331 { "stacktrace", HandleStackTrace }, | 535 { "stacktrace", HandleStackTrace }, |
| 332 }; | 536 }; |
| 333 | 537 |
| 334 | 538 |
| 335 static void HandleFallthrough(Isolate* isolate, JSONStream* js) { | 539 static void HandleFallthrough(Isolate* isolate, JSONStream* js) { |
| 336 JSONObject jsobj(js); | 540 JSONObject jsobj(js); |
| 337 jsobj.AddProperty("type", "Error"); | 541 jsobj.AddProperty("type", "Error"); |
| 338 jsobj.AddProperty("text", "request not understood."); | 542 jsobj.AddProperty("text", "request not understood."); |
| 339 PrintArgumentsAndOptions(jsobj, js); | 543 PrintArgumentsAndOptions(jsobj, js); |
| 340 } | 544 } |
| 341 | 545 |
| 342 | 546 |
| 343 static ServiceMessageHandler FindServiceMessageHandler(const char* command) { | 547 static ServiceMessageHandler FindServiceMessageHandler(const char* command) { |
| 344 intptr_t num_message_handlers = sizeof(__message_handlers) / | 548 intptr_t num_message_handlers = sizeof(__message_handlers) / |
| 345 sizeof(__message_handlers[0]); | 549 sizeof(__message_handlers[0]); |
| 346 for (intptr_t i = 0; i < num_message_handlers; i++) { | 550 for (intptr_t i = 0; i < num_message_handlers; i++) { |
| 347 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; | 551 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; |
| 348 if (!strcmp(command, entry.command)) { | 552 if (!strcmp(command, entry.command)) { |
| 349 return entry.handler; | 553 return entry.handler; |
| 350 } | 554 } |
| 351 } | 555 } |
| 352 return HandleFallthrough; | 556 return HandleFallthrough; |
| 353 } | 557 } |
| 354 | 558 |
| 355 } // namespace dart | 559 } // namespace dart |
| OLD | NEW |