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 "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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 } | 146 } |
| 147 { | 147 { |
| 148 JSONArray jsarr(&jsobj, "option_values"); | 148 JSONArray jsarr(&jsobj, "option_values"); |
| 149 for (intptr_t i = 0; i < js->num_options(); i++) { | 149 for (intptr_t i = 0; i < js->num_options(); i++) { |
| 150 jsarr.AddValue(js->GetOptionValue(i)); | 150 jsarr.AddValue(js->GetOptionValue(i)); |
| 151 } | 151 } |
| 152 } | 152 } |
| 153 } | 153 } |
| 154 | 154 |
| 155 | 155 |
| 156 static void PrintCollectionErrorResponse(const char* collection_name, | |
| 157 JSONStream* js) { | |
| 158 JSONObject jsobj(js); | |
| 159 jsobj.AddProperty("type", "Error"); | |
| 160 jsobj.AddPropertyF("text", "Must specify collection object id: %s/id", | |
| 161 collection_name); | |
| 162 } | |
| 163 | |
| 164 | |
| 165 static void PrintCollectionRangeErrorResponse(const char* collection_name, | |
| 166 JSONStream* js, | |
| 167 intptr_t id, | |
| 168 intptr_t length) { | |
| 169 JSONObject jsobj(js); | |
| 170 jsobj.AddProperty("type", "Error"); | |
| 171 jsobj.AddPropertyF("text", "%s id (%" Pd ") must be in [0, %" Pd ").", | |
| 172 collection_name, id, length); | |
| 173 } | |
| 174 | |
| 175 | |
| 156 static void PrintGenericError(JSONStream* js) { | 176 static void PrintGenericError(JSONStream* js) { |
| 157 JSONObject jsobj(js); | 177 JSONObject jsobj(js); |
| 158 jsobj.AddProperty("type", "Error"); | 178 jsobj.AddProperty("type", "Error"); |
| 159 jsobj.AddProperty("text", "Invalid request."); | 179 jsobj.AddProperty("text", "Invalid request."); |
| 160 PrintArgumentsAndOptions(jsobj, js); | 180 PrintArgumentsAndOptions(jsobj, js); |
| 161 } | 181 } |
| 162 | 182 |
| 163 | 183 |
| 164 static void PrintError(JSONStream* js, const char* format, ...) { | 184 static void PrintError(JSONStream* js, const char* format, ...) { |
| 165 Isolate* isolate = Isolate::Current(); | 185 Isolate* isolate = Isolate::Current(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 } | 251 } |
| 232 | 252 |
| 233 | 253 |
| 234 // Print an error message if there is no ID argument. | 254 // Print an error message if there is no ID argument. |
| 235 #define REQUIRE_COLLECTION_ID(collection) \ | 255 #define REQUIRE_COLLECTION_ID(collection) \ |
| 236 if (js->num_arguments() == 1) { \ | 256 if (js->num_arguments() == 1) { \ |
| 237 PrintError(js, "Must specify collection object id: /%s/id", collection); \ | 257 PrintError(js, "Must specify collection object id: /%s/id", collection); \ |
| 238 return; \ | 258 return; \ |
| 239 } | 259 } |
| 240 | 260 |
| 261 #define CHECK_COLLECTION_ID_BOUNDS(collection, length, arg, id, js) \ | |
| 262 if (!GetIntegerId(arg, &id)) { \ | |
| 263 PrintCollectionErrorResponse(collection, js); \ | |
|
turnidge
2013/12/19 20:39:29
Why not just use PrintError (accepts format string
Cutch
2013/12/19 21:53:58
Done.
| |
| 264 return; \ | |
| 265 } \ | |
| 266 if ((id < 0) || (id >= length)) { \ | |
| 267 PrintCollectionRangeErrorResponse(collection, js, id, length); \ | |
| 268 } | |
| 269 | |
| 270 | |
| 271 static bool GetIntegerId(const char* s, intptr_t* id) { | |
| 272 if ((s == NULL) || (*s == '\0')) { | |
| 273 // Empty string. | |
| 274 return false; | |
| 275 } | |
| 276 if (id == NULL) { | |
| 277 // No id pointer. | |
| 278 return false; | |
| 279 } | |
| 280 intptr_t r = 0; | |
| 281 char* end_ptr = NULL; | |
| 282 r = strtol(s, &end_ptr, 10); | |
| 283 if (end_ptr == s) { | |
| 284 // String was not advanced at all, cannot be valid. | |
| 285 return false; | |
| 286 } | |
| 287 *id = r; | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 | |
| 292 static void HandleClassesClosures(Isolate* isolate, const Class& cls, | |
| 293 JSONStream* js) { | |
| 294 const GrowableObjectArray& closures = | |
| 295 GrowableObjectArray::Handle(cls.closures()); | |
| 296 intptr_t id; | |
| 297 CHECK_COLLECTION_ID_BOUNDS("closures", closures.Length(), js->GetArgument(3), | |
| 298 id, js); | |
| 299 Function& function = Function::Handle(); | |
| 300 function ^= closures.At(id); | |
| 301 ASSERT(!function.IsNull()); | |
| 302 function.PrintToJSONStream(js, false); | |
| 303 } | |
| 304 | |
| 305 | |
| 306 static void HandleClassesFunctions(Isolate* isolate, const Class& cls, | |
| 307 JSONStream* js) { | |
| 308 const Array& functions = | |
| 309 Array::Handle(cls.functions()); | |
| 310 intptr_t id; | |
| 311 CHECK_COLLECTION_ID_BOUNDS("functions", functions.Length(), | |
| 312 js->GetArgument(3), id, js); | |
| 313 Function& function = Function::Handle(); | |
| 314 function ^= functions.At(id); | |
| 315 ASSERT(!function.IsNull()); | |
| 316 function.PrintToJSONStream(js, false); | |
| 317 } | |
| 318 | |
| 319 | |
| 320 static void HandleClassesFields(Isolate* isolate, const Class& cls, | |
| 321 JSONStream* js) { | |
| 322 const Array& fields = | |
| 323 Array::Handle(cls.fields()); | |
| 324 intptr_t id; | |
| 325 CHECK_COLLECTION_ID_BOUNDS("fields", fields.Length(), js->GetArgument(3), | |
| 326 id, js); | |
| 327 Field& field = Field::Handle(); | |
| 328 field ^= fields.At(id); | |
| 329 ASSERT(!field.IsNull()); | |
| 330 field.PrintToJSONStream(js, false); | |
| 331 } | |
| 332 | |
| 241 | 333 |
| 242 static void HandleClasses(Isolate* isolate, JSONStream* js) { | 334 static void HandleClasses(Isolate* isolate, JSONStream* js) { |
| 243 if (js->num_arguments() == 1) { | 335 if (js->num_arguments() == 1) { |
| 244 ClassTable* table = isolate->class_table(); | 336 ClassTable* table = isolate->class_table(); |
| 245 table->PrintToJSONStream(js); | 337 table->PrintToJSONStream(js); |
| 246 return; | 338 return; |
| 247 } | 339 } |
| 248 ASSERT(js->num_arguments() >= 2); | 340 ASSERT(js->num_arguments() >= 2); |
| 249 intptr_t id = atoi(js->GetArgument(1)); | 341 intptr_t id; |
| 342 if (!GetIntegerId(js->GetArgument(1), &id)) { | |
| 343 PrintGenericError(js); | |
|
turnidge
2013/12/19 20:39:29
Use PrintError and give a nice message here.
Cutch
2013/12/19 21:53:58
Done.
| |
| 344 return; | |
| 345 } | |
| 250 ClassTable* table = isolate->class_table(); | 346 ClassTable* table = isolate->class_table(); |
| 251 if (!table->IsValidIndex(id)) { | 347 if (!table->IsValidIndex(id)) { |
| 252 Object::null_object().PrintToJSONStream(js, false); | 348 Object::null_object().PrintToJSONStream(js, false); |
|
turnidge
2013/12/19 20:39:29
So null is what we give for an invalid reference?
Cutch
2013/12/19 21:53:58
Legacy code, returning Error now.
| |
| 349 return; | |
| 350 } | |
| 351 Class& cls = Class::Handle(table->At(id)); | |
| 352 if (js->num_arguments() == 2) { | |
| 353 cls.PrintToJSONStream(js, false); | |
| 354 return; | |
| 355 } else if (js->num_arguments() == 4) { | |
|
turnidge
2013/12/19 20:39:29
Maybe just check that num_arguments is >= 3 and le
Cutch
2013/12/19 21:53:58
Done.
| |
| 356 const char* second = js->GetArgument(2); | |
| 357 if (!strcmp(second, "closures")) { | |
| 358 HandleClassesClosures(isolate, cls, js); | |
| 359 } else if (!strcmp(second, "fields")) { | |
| 360 HandleClassesFields(isolate, cls, js); | |
| 361 } else if (!strcmp(second, "functions")) { | |
| 362 HandleClassesFunctions(isolate, cls, js); | |
| 363 } else { | |
| 364 PrintError(js, "Invalid sub collection %s", second); | |
| 365 } | |
| 253 } else { | 366 } else { |
| 254 Class& cls = Class::Handle(table->At(id)); | 367 PrintGenericError(js); |
|
turnidge
2013/12/19 20:39:29
This goes away if you let helpers handle sub-error
Cutch
2013/12/19 21:53:58
Done.
| |
| 255 cls.PrintToJSONStream(js, false); | |
| 256 } | 368 } |
| 257 } | 369 } |
|
turnidge
2013/12/19 20:39:29
Here and below...
You should have my changes now
Cutch
2013/12/19 21:53:58
Done.
| |
| 258 | 370 |
| 259 | 371 |
| 260 static void HandleLibrary(Isolate* isolate, JSONStream* js) { | 372 static void HandleLibrary(Isolate* isolate, JSONStream* js) { |
| 261 if (js->num_arguments() == 1) { | 373 if (js->num_arguments() == 1) { |
| 262 const Library& lib = | 374 const Library& lib = |
| 263 Library::Handle(isolate->object_store()->root_library()); | 375 Library::Handle(isolate->object_store()->root_library()); |
| 264 lib.PrintToJSONStream(js, false); | 376 lib.PrintToJSONStream(js, false); |
| 265 return; | 377 return; |
| 266 } | 378 } |
| 267 PrintGenericError(js); | 379 PrintGenericError(js); |
| 268 } | 380 } |
| 269 | 381 |
| 270 | 382 |
| 383 static void HandleLibraries(Isolate* isolate, JSONStream* js) { | |
| 384 REQUIRE_COLLECTION_ID("libraries"); | |
| 385 const GrowableObjectArray& libs = | |
| 386 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | |
| 387 ASSERT(!libs.IsNull()); | |
| 388 intptr_t id = 0; | |
| 389 CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1), | |
| 390 id, js); | |
| 391 Library& lib = Library::Handle(); | |
| 392 lib ^= libs.At(id); | |
| 393 ASSERT(!lib.IsNull()); | |
| 394 lib.PrintToJSONStream(js, false); | |
|
turnidge
2013/12/19 20:39:29
So do we not yet support Fields/Functions for libr
Cutch
2013/12/19 21:53:58
Good point! TODO added.
| |
| 395 } | |
| 396 | |
| 397 | |
| 271 static void HandleObjects(Isolate* isolate, JSONStream* js) { | 398 static void HandleObjects(Isolate* isolate, JSONStream* js) { |
| 272 REQUIRE_COLLECTION_ID("objects"); | 399 REQUIRE_COLLECTION_ID("objects"); |
| 273 ASSERT(js->num_arguments() >= 2); | 400 ASSERT(js->num_arguments() >= 2); |
| 274 ObjectIdRing* ring = isolate->object_id_ring(); | 401 ObjectIdRing* ring = isolate->object_id_ring(); |
| 275 ASSERT(ring != NULL); | 402 ASSERT(ring != NULL); |
| 276 intptr_t id = atoi(js->GetArgument(1)); | 403 intptr_t id = -1; |
| 404 if (!GetIntegerId(js->GetArgument(1), &id)) { | |
| 405 Object::null_object().PrintToJSONStream(js, false); | |
|
turnidge
2013/12/19 20:39:29
Again, null object seems ambiguous. I might prefe
| |
| 406 return; | |
| 407 } | |
| 277 Object& obj = Object::Handle(ring->GetObjectForId(id)); | 408 Object& obj = Object::Handle(ring->GetObjectForId(id)); |
| 278 obj.PrintToJSONStream(js, false); | 409 obj.PrintToJSONStream(js, false); |
| 279 } | 410 } |
| 280 | 411 |
| 281 | 412 |
| 413 | |
| 414 static void HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) { | |
| 415 JSONObject jsobj(js); | |
| 416 jsobj.AddProperty("type", "ScriptList"); | |
| 417 { | |
| 418 JSONArray members(&jsobj, "members"); | |
| 419 const GrowableObjectArray& libs = | |
| 420 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | |
| 421 int num_libs = libs.Length(); | |
| 422 Library &lib = Library::Handle(); | |
| 423 Script& script = Script::Handle(); | |
| 424 for (intptr_t i = 0; i < num_libs; i++) { | |
| 425 lib ^= libs.At(i); | |
| 426 ASSERT(!lib.IsNull()); | |
| 427 ASSERT(Smi::IsValid(lib.index())); | |
| 428 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); | |
| 429 ASSERT(!loaded_scripts.IsNull()); | |
| 430 intptr_t num_scripts = loaded_scripts.Length(); | |
| 431 for (intptr_t i = 0; i < num_scripts; i++) { | |
| 432 script ^= loaded_scripts.At(i); | |
| 433 members.AddValue(script); | |
| 434 } | |
| 435 } | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 | |
| 440 static void HandleScriptsFetch(Isolate* isolate, JSONStream* js) { | |
| 441 const GrowableObjectArray& libs = | |
| 442 GrowableObjectArray::Handle(isolate->object_store()->libraries()); | |
| 443 int num_libs = libs.Length(); | |
| 444 Library &lib = Library::Handle(); | |
| 445 Script& script = Script::Handle(); | |
| 446 String& url = String::Handle(); | |
| 447 const String& id = String::Handle(String::New(js->GetArgument(1))); | |
| 448 ASSERT(!id.IsNull()); | |
| 449 // The id is the url of the script % encoded, decode it. | |
| 450 String& requested_url = String::Handle(String::DecodeURI(id)); | |
| 451 for (intptr_t i = 0; i < num_libs; i++) { | |
| 452 lib ^= libs.At(i); | |
| 453 ASSERT(!lib.IsNull()); | |
| 454 ASSERT(Smi::IsValid(lib.index())); | |
| 455 const Array& loaded_scripts = Array::Handle(lib.LoadedScripts()); | |
| 456 ASSERT(!loaded_scripts.IsNull()); | |
| 457 intptr_t num_scripts = loaded_scripts.Length(); | |
| 458 for (intptr_t i = 0; i < num_scripts; i++) { | |
| 459 script ^= loaded_scripts.At(i); | |
| 460 ASSERT(!script.IsNull()); | |
| 461 url ^= script.url(); | |
| 462 if (url.Equals(requested_url)) { | |
| 463 script.PrintToJSONStream(js, false); | |
| 464 return; | |
| 465 } | |
| 466 } | |
| 467 } | |
| 468 PrintError(js, "Cannot find script %s\n", requested_url.ToCString()); | |
| 469 } | |
| 470 | |
| 471 | |
| 472 static void HandleScripts(Isolate* isolate, JSONStream* js) { | |
| 473 if (js->num_arguments() == 1) { | |
| 474 // Enumerate all scripts. | |
| 475 HandleScriptsEnumerate(isolate, js); | |
| 476 } else if (js->num_arguments() == 2) { | |
| 477 // Fetch specific script. | |
| 478 HandleScriptsFetch(isolate, js); | |
| 479 } else { | |
| 480 PrintError(js, "Command too long"); | |
| 481 } | |
| 482 } | |
| 483 | |
| 484 | |
| 282 static void HandleDebug(Isolate* isolate, JSONStream* js) { | 485 static void HandleDebug(Isolate* isolate, JSONStream* js) { |
| 283 if (js->num_arguments() == 1) { | 486 if (js->num_arguments() == 1) { |
| 284 PrintError(js, "Must specify a subcommand"); | 487 PrintError(js, "Must specify a subcommand"); |
| 285 return; | 488 return; |
| 286 } | 489 } |
| 287 const char* command = js->GetArgument(1); | 490 const char* command = js->GetArgument(1); |
| 288 if (!strcmp(command, "breakpoints")) { | 491 if (!strcmp(command, "breakpoints")) { |
| 289 if (js->num_arguments() == 2) { | 492 if (js->num_arguments() == 2) { |
| 290 // Print breakpoint list. | 493 // Print breakpoint list. |
| 291 JSONObject jsobj(js); | 494 JSONObject jsobj(js); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 317 jsobj.AddProperty("type", "CPU"); | 520 jsobj.AddProperty("type", "CPU"); |
| 318 jsobj.AddProperty("architecture", CPU::Id()); | 521 jsobj.AddProperty("architecture", CPU::Id()); |
| 319 } | 522 } |
| 320 | 523 |
| 321 | 524 |
| 322 static ServiceMessageHandlerEntry __message_handlers[] = { | 525 static ServiceMessageHandlerEntry __message_handlers[] = { |
| 323 { "_echo", HandleEcho }, | 526 { "_echo", HandleEcho }, |
| 324 { "classes", HandleClasses }, | 527 { "classes", HandleClasses }, |
| 325 { "cpu", HandleCpu }, | 528 { "cpu", HandleCpu }, |
| 326 { "debug", HandleDebug }, | 529 { "debug", HandleDebug }, |
| 530 { "libraries", HandleLibraries }, | |
| 327 { "library", HandleLibrary }, | 531 { "library", HandleLibrary }, |
|
turnidge
2013/12/19 20:39:29
Is the plan to have both library and libraries? I
Cutch
2013/12/19 21:53:58
library is how you get to the root library. librar
| |
| 328 { "name", HandleName }, | 532 { "name", HandleName }, |
| 329 { "objecthistogram", HandleObjectHistogram}, | 533 { "objecthistogram", HandleObjectHistogram}, |
| 330 { "objects", HandleObjects }, | 534 { "objects", HandleObjects }, |
| 535 { "scripts", HandleScripts }, | |
| 331 { "stacktrace", HandleStackTrace }, | 536 { "stacktrace", HandleStackTrace }, |
| 332 }; | 537 }; |
| 333 | 538 |
| 334 | 539 |
| 335 static void HandleFallthrough(Isolate* isolate, JSONStream* js) { | 540 static void HandleFallthrough(Isolate* isolate, JSONStream* js) { |
| 336 JSONObject jsobj(js); | 541 JSONObject jsobj(js); |
| 337 jsobj.AddProperty("type", "Error"); | 542 jsobj.AddProperty("type", "Error"); |
| 338 jsobj.AddProperty("text", "request not understood."); | 543 jsobj.AddProperty("text", "request not understood."); |
| 339 PrintArgumentsAndOptions(jsobj, js); | 544 PrintArgumentsAndOptions(jsobj, js); |
| 340 } | 545 } |
| 341 | 546 |
| 342 | 547 |
| 343 static ServiceMessageHandler FindServiceMessageHandler(const char* command) { | 548 static ServiceMessageHandler FindServiceMessageHandler(const char* command) { |
| 344 intptr_t num_message_handlers = sizeof(__message_handlers) / | 549 intptr_t num_message_handlers = sizeof(__message_handlers) / |
| 345 sizeof(__message_handlers[0]); | 550 sizeof(__message_handlers[0]); |
| 346 for (intptr_t i = 0; i < num_message_handlers; i++) { | 551 for (intptr_t i = 0; i < num_message_handlers; i++) { |
| 347 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; | 552 const ServiceMessageHandlerEntry& entry = __message_handlers[i]; |
| 348 if (!strcmp(command, entry.command)) { | 553 if (!strcmp(command, entry.command)) { |
| 349 return entry.handler; | 554 return entry.handler; |
| 350 } | 555 } |
| 351 } | 556 } |
| 352 return HandleFallthrough; | 557 return HandleFallthrough; |
| 353 } | 558 } |
| 354 | 559 |
| 355 } // namespace dart | 560 } // namespace dart |
| OLD | NEW |