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 "include/dart_native_api.h" | 8 #include "include/dart_native_api.h" |
9 #include "platform/globals.h" | 9 #include "platform/globals.h" |
10 | 10 |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "vm/object.h" | 23 #include "vm/object.h" |
24 #include "vm/object_graph.h" | 24 #include "vm/object_graph.h" |
25 #include "vm/object_id_ring.h" | 25 #include "vm/object_id_ring.h" |
26 #include "vm/object_store.h" | 26 #include "vm/object_store.h" |
27 #include "vm/parser.h" | 27 #include "vm/parser.h" |
28 #include "vm/port.h" | 28 #include "vm/port.h" |
29 #include "vm/profiler_service.h" | 29 #include "vm/profiler_service.h" |
30 #include "vm/reusable_handles.h" | 30 #include "vm/reusable_handles.h" |
31 #include "vm/service_event.h" | 31 #include "vm/service_event.h" |
32 #include "vm/service_isolate.h" | 32 #include "vm/service_isolate.h" |
| 33 #include "vm/source_report.h" |
33 #include "vm/stack_frame.h" | 34 #include "vm/stack_frame.h" |
34 #include "vm/symbols.h" | 35 #include "vm/symbols.h" |
35 #include "vm/unicode.h" | 36 #include "vm/unicode.h" |
36 #include "vm/version.h" | 37 #include "vm/version.h" |
37 | 38 |
38 namespace dart { | 39 namespace dart { |
39 | 40 |
40 #define Z (T->zone()) | 41 #define Z (T->zone()) |
41 | 42 |
42 | 43 |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 for (i = 0; enums[i] != NULL; i++) { | 555 for (i = 0; enums[i] != NULL; i++) { |
555 if (strcmp(value, enums[i]) == 0) { | 556 if (strcmp(value, enums[i]) == 0) { |
556 return values[i]; | 557 return values[i]; |
557 } | 558 } |
558 } | 559 } |
559 // Default value. | 560 // Default value. |
560 return values[i]; | 561 return values[i]; |
561 } | 562 } |
562 | 563 |
563 | 564 |
| 565 class EnumListParameter : public MethodParameter { |
| 566 public: |
| 567 EnumListParameter(const char* name, bool required, const char* const* enums) |
| 568 : MethodParameter(name, required), |
| 569 enums_(enums) { |
| 570 } |
| 571 |
| 572 virtual bool Validate(const char* value) const { |
| 573 return ElementCount(value) >= 0; |
| 574 } |
| 575 |
| 576 const char** Parse(Zone* zone, const char* value_in) const { |
| 577 const char* kJsonChars = " \t\r\n[,]"; |
| 578 |
| 579 // Make a writeable copy of the value. |
| 580 char* value = zone->MakeCopyOfString(value_in); |
| 581 intptr_t element_count = ElementCount(value); |
| 582 intptr_t element_pos = 0; |
| 583 |
| 584 // Allocate our element array. +1 for NULL terminator. |
| 585 char** elements = zone->Alloc<char*>(element_count + 1); |
| 586 elements[element_count] = NULL; |
| 587 |
| 588 // Parse the string destructively. Build the list of elements. |
| 589 while (element_pos < element_count) { |
| 590 // Skip to the next element. |
| 591 value += strspn(value, kJsonChars); |
| 592 |
| 593 intptr_t len = strcspn(value, kJsonChars); |
| 594 ASSERT(len > 0); // We rely on the parameter being validated already. |
| 595 value[len] = '\0'; |
| 596 elements[element_pos++] = value; |
| 597 |
| 598 // Advance. +1 for null terminator. |
| 599 value += (len + 1); |
| 600 } |
| 601 return const_cast<const char**>(elements); |
| 602 } |
| 603 |
| 604 private: |
| 605 // For now observatory enums are ascii letters plus underscore. |
| 606 static bool IsEnumChar(char c) { |
| 607 return (((c >= 'a') && (c <= 'z')) || |
| 608 ((c >= 'A') && (c <= 'Z')) || |
| 609 (c == '_')); |
| 610 } |
| 611 |
| 612 // Returns number of elements in the list. -1 on parse error. |
| 613 intptr_t ElementCount(const char* value) const { |
| 614 const char* kJsonWhitespaceChars = " \t\r\n"; |
| 615 |
| 616 if (value == NULL) { |
| 617 return -1; |
| 618 } |
| 619 const char* cp = value; |
| 620 cp += strspn(cp, kJsonWhitespaceChars); |
| 621 if (*cp++ != '[') { |
| 622 // Missing initial [. |
| 623 return -1; |
| 624 } |
| 625 bool closed = false; |
| 626 bool element_allowed = true; |
| 627 intptr_t element_count = 0; |
| 628 while (true) { |
| 629 // Skip json whitespace. |
| 630 cp += strspn(cp, kJsonWhitespaceChars); |
| 631 switch (*cp) { |
| 632 case '\0': |
| 633 return closed ? element_count : -1; |
| 634 case ']': |
| 635 closed = true; |
| 636 cp++; |
| 637 break; |
| 638 case ',': |
| 639 if (element_allowed) { |
| 640 return -1; |
| 641 } |
| 642 element_allowed = true; |
| 643 cp++; |
| 644 break; |
| 645 default: |
| 646 if (!element_allowed) { |
| 647 return -1; |
| 648 } |
| 649 bool valid_enum = false; |
| 650 if (enums_ != NULL) { |
| 651 for (intptr_t i = 0; enums_[i] != NULL; i++) { |
| 652 intptr_t len = strlen(enums_[i]); |
| 653 if (strncmp(cp, enums_[i], len) == 0) { |
| 654 element_count++; |
| 655 valid_enum = true; |
| 656 cp += len; |
| 657 element_allowed = false; // we need a comma first. |
| 658 break; |
| 659 } |
| 660 } |
| 661 } else { |
| 662 // Allow any identifiers |
| 663 const char* id_start = cp; |
| 664 while (IsEnumChar(*cp)) { |
| 665 cp++; |
| 666 } |
| 667 if (cp == id_start) { |
| 668 // Empty identifier, something like this [,]. |
| 669 return -1; |
| 670 } |
| 671 } |
| 672 if (!valid_enum) { |
| 673 return -1; |
| 674 } |
| 675 break; |
| 676 } |
| 677 } |
| 678 } |
| 679 |
| 680 const char* const* enums_; |
| 681 }; |
| 682 |
| 683 |
564 typedef bool (*ServiceMethodEntry)(Thread* thread, JSONStream* js); | 684 typedef bool (*ServiceMethodEntry)(Thread* thread, JSONStream* js); |
565 | 685 |
566 | 686 |
567 struct ServiceMethodDescriptor { | 687 struct ServiceMethodDescriptor { |
568 const char* name; | 688 const char* name; |
569 const ServiceMethodEntry entry; | 689 const ServiceMethodEntry entry; |
570 const MethodParameter* const * parameters; | 690 const MethodParameter* const * parameters; |
571 }; | 691 }; |
572 | 692 |
573 | 693 |
(...skipping 1610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2184 NULL, | 2304 NULL, |
2185 }; | 2305 }; |
2186 | 2306 |
2187 | 2307 |
2188 static bool GetCoverage(Thread* thread, JSONStream* js) { | 2308 static bool GetCoverage(Thread* thread, JSONStream* js) { |
2189 // TODO(rmacnak): Remove this response; it is subsumed by GetCallSiteData. | 2309 // TODO(rmacnak): Remove this response; it is subsumed by GetCallSiteData. |
2190 return GetHitsOrSites(thread, js, false); | 2310 return GetHitsOrSites(thread, js, false); |
2191 } | 2311 } |
2192 | 2312 |
2193 | 2313 |
| 2314 static const char* kCallSitesStr = "CallSites"; |
| 2315 static const char* kCoverageStr = "Coverage"; |
| 2316 |
| 2317 |
| 2318 static const char* const report_enum_names[] = { |
| 2319 kCallSitesStr, |
| 2320 kCoverageStr, |
| 2321 NULL, |
| 2322 }; |
| 2323 |
| 2324 |
| 2325 static const EnumListParameter* reports_parameter = |
| 2326 new EnumListParameter("reports", true, report_enum_names); |
| 2327 |
| 2328 |
| 2329 static const MethodParameter* get_source_report_params[] = { |
| 2330 ISOLATE_PARAMETER, |
| 2331 reports_parameter, |
| 2332 new IdParameter("scriptId", false), |
| 2333 new UIntParameter("tokenPos", false), |
| 2334 new UIntParameter("endTokenPos", false), |
| 2335 NULL, |
| 2336 }; |
| 2337 |
| 2338 |
| 2339 static bool GetSourceReport(Thread* thread, JSONStream* js) { |
| 2340 const char* reports_str = js->LookupParam("reports"); |
| 2341 const char** reports = reports_parameter->Parse(thread->zone(), reports_str); |
| 2342 intptr_t report_set = 0; |
| 2343 while (*reports != NULL) { |
| 2344 if (strcmp(*reports, kCallSitesStr) == 0) { |
| 2345 report_set |= SourceReport::kCallSites; |
| 2346 } else if (strcmp(*reports, kCoverageStr) == 0) { |
| 2347 report_set |= SourceReport::kCoverage; |
| 2348 } |
| 2349 reports++; |
| 2350 } |
| 2351 |
| 2352 Script& script = Script::Handle(); |
| 2353 intptr_t start_pos = UIntParameter::Parse(js->LookupParam("tokenPos")); |
| 2354 intptr_t end_pos = UIntParameter::Parse(js->LookupParam("endTokenPos")); |
| 2355 |
| 2356 if (js->HasParam("scriptId")) { |
| 2357 // Get the target script. |
| 2358 const char* script_id_param = js->LookupParam("scriptId"); |
| 2359 const Object& obj = |
| 2360 Object::Handle(LookupHeapObject(thread, script_id_param, NULL)); |
| 2361 if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) { |
| 2362 PrintInvalidParamError(js, "scriptId"); |
| 2363 return true; |
| 2364 } |
| 2365 script ^= obj.raw(); |
| 2366 } else { |
| 2367 if (js->HasParam("tokenPos")) { |
| 2368 js->PrintError( |
| 2369 kInvalidParams, |
| 2370 "%s: the 'tokenPos' parameter requires the 'scriptId' parameter", |
| 2371 js->method()); |
| 2372 return true; |
| 2373 } |
| 2374 if (js->HasParam("endTokenPos")) { |
| 2375 js->PrintError( |
| 2376 kInvalidParams, |
| 2377 "%s: the 'endTokenPos' parameter requires the 'scriptId' parameter", |
| 2378 js->method()); |
| 2379 return true; |
| 2380 } |
| 2381 } |
| 2382 SourceReport report(report_set); |
| 2383 report.PrintJSON(js, script, start_pos, end_pos); |
| 2384 return true; |
| 2385 } |
| 2386 |
| 2387 |
2194 static const MethodParameter* get_call_site_data_params[] = { | 2388 static const MethodParameter* get_call_site_data_params[] = { |
2195 ISOLATE_PARAMETER, | 2389 ISOLATE_PARAMETER, |
2196 new IdParameter("targetId", false), | 2390 new IdParameter("targetId", false), |
2197 NULL, | 2391 NULL, |
2198 }; | 2392 }; |
2199 | 2393 |
2200 | 2394 |
2201 static bool GetCallSiteData(Thread* thread, JSONStream* js) { | 2395 static bool GetCallSiteData(Thread* thread, JSONStream* js) { |
2202 return GetHitsOrSites(thread, js, true); | 2396 return GetHitsOrSites(thread, js, true); |
2203 } | 2397 } |
(...skipping 1397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3601 { "_getObjectByAddress", GetObjectByAddress, | 3795 { "_getObjectByAddress", GetObjectByAddress, |
3602 get_object_by_address_params }, | 3796 get_object_by_address_params }, |
3603 { "_getPorts", GetPorts, | 3797 { "_getPorts", GetPorts, |
3604 get_ports_params }, | 3798 get_ports_params }, |
3605 { "_getReachableSize", GetReachableSize, | 3799 { "_getReachableSize", GetReachableSize, |
3606 get_reachable_size_params }, | 3800 get_reachable_size_params }, |
3607 { "_getRetainedSize", GetRetainedSize, | 3801 { "_getRetainedSize", GetRetainedSize, |
3608 get_retained_size_params }, | 3802 get_retained_size_params }, |
3609 { "_getRetainingPath", GetRetainingPath, | 3803 { "_getRetainingPath", GetRetainingPath, |
3610 get_retaining_path_params }, | 3804 get_retaining_path_params }, |
| 3805 { "_getSourceReport", GetSourceReport, |
| 3806 get_source_report_params }, |
3611 { "getStack", GetStack, | 3807 { "getStack", GetStack, |
3612 get_stack_params }, | 3808 get_stack_params }, |
3613 { "_getTagProfile", GetTagProfile, | 3809 { "_getTagProfile", GetTagProfile, |
3614 get_tag_profile_params }, | 3810 get_tag_profile_params }, |
3615 { "_getTypeArgumentsList", GetTypeArgumentsList, | 3811 { "_getTypeArgumentsList", GetTypeArgumentsList, |
3616 get_type_arguments_list_params }, | 3812 get_type_arguments_list_params }, |
3617 { "getVersion", GetVersion, | 3813 { "getVersion", GetVersion, |
3618 get_version_params }, | 3814 get_version_params }, |
3619 { "getVM", GetVM, | 3815 { "getVM", GetVM, |
3620 get_vm_params }, | 3816 get_vm_params }, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3660 const ServiceMethodDescriptor& method = service_methods_[i]; | 3856 const ServiceMethodDescriptor& method = service_methods_[i]; |
3661 if (strcmp(method_name, method.name) == 0) { | 3857 if (strcmp(method_name, method.name) == 0) { |
3662 return &method; | 3858 return &method; |
3663 } | 3859 } |
3664 } | 3860 } |
3665 return NULL; | 3861 return NULL; |
3666 } | 3862 } |
3667 | 3863 |
3668 | 3864 |
3669 } // namespace dart | 3865 } // namespace dart |
OLD | NEW |