Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Unified Diff: runtime/vm/service.cc

Issue 1566793002: Expose the new _getSourceReport api in the service protocol. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: code rev Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/observatory/tests/service/get_source_report_test.dart ('k') | runtime/vm/source_report.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/service.cc
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 4735b51036403ae329e2e5fc0c99c7b2f773dbc1..35be737034cc8e4dad41d78a6a61baa1475a0c90 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -30,6 +30,7 @@
#include "vm/reusable_handles.h"
#include "vm/service_event.h"
#include "vm/service_isolate.h"
+#include "vm/source_report.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/unicode.h"
@@ -561,6 +562,125 @@ T EnumMapper(const char* value, const char* const* enums, T* values) {
}
+class EnumListParameter : public MethodParameter {
+ public:
+ EnumListParameter(const char* name, bool required, const char* const* enums)
+ : MethodParameter(name, required),
+ enums_(enums) {
+ }
+
+ virtual bool Validate(const char* value) const {
+ return ElementCount(value) >= 0;
+ }
+
+ const char** Parse(Zone* zone, const char* value_in) const {
+ const char* kJsonChars = " \t\r\n[,]";
+
+ // Make a writeable copy of the value.
+ char* value = zone->MakeCopyOfString(value_in);
+ intptr_t element_count = ElementCount(value);
+ intptr_t element_pos = 0;
+
+ // Allocate our element array. +1 for NULL terminator.
+ char** elements = zone->Alloc<char*>(element_count + 1);
+ elements[element_count] = NULL;
+
+ // Parse the string destructively. Build the list of elements.
+ while (element_pos < element_count) {
+ // Skip to the next element.
+ value += strspn(value, kJsonChars);
+
+ intptr_t len = strcspn(value, kJsonChars);
+ ASSERT(len > 0); // We rely on the parameter being validated already.
+ value[len] = '\0';
+ elements[element_pos++] = value;
+
+ // Advance. +1 for null terminator.
+ value += (len + 1);
+ }
+ return const_cast<const char**>(elements);
+ }
+
+ private:
+ // For now observatory enums are ascii letters plus underscore.
+ static bool IsEnumChar(char c) {
+ return (((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ||
+ (c == '_'));
+ }
+
+ // Returns number of elements in the list. -1 on parse error.
+ intptr_t ElementCount(const char* value) const {
+ const char* kJsonWhitespaceChars = " \t\r\n";
+
+ if (value == NULL) {
+ return -1;
+ }
+ const char* cp = value;
+ cp += strspn(cp, kJsonWhitespaceChars);
+ if (*cp++ != '[') {
+ // Missing initial [.
+ return -1;
+ }
+ bool closed = false;
+ bool element_allowed = true;
+ intptr_t element_count = 0;
+ while (true) {
+ // Skip json whitespace.
+ cp += strspn(cp, kJsonWhitespaceChars);
+ switch (*cp) {
+ case '\0':
+ return closed ? element_count : -1;
+ case ']':
+ closed = true;
+ cp++;
+ break;
+ case ',':
+ if (element_allowed) {
+ return -1;
+ }
+ element_allowed = true;
+ cp++;
+ break;
+ default:
+ if (!element_allowed) {
+ return -1;
+ }
+ bool valid_enum = false;
+ if (enums_ != NULL) {
+ for (intptr_t i = 0; enums_[i] != NULL; i++) {
+ intptr_t len = strlen(enums_[i]);
+ if (strncmp(cp, enums_[i], len) == 0) {
+ element_count++;
+ valid_enum = true;
+ cp += len;
+ element_allowed = false; // we need a comma first.
+ break;
+ }
+ }
+ } else {
+ // Allow any identifiers
+ const char* id_start = cp;
+ while (IsEnumChar(*cp)) {
+ cp++;
+ }
+ if (cp == id_start) {
+ // Empty identifier, something like this [,].
+ return -1;
+ }
+ }
+ if (!valid_enum) {
+ return -1;
+ }
+ break;
+ }
+ }
+ }
+
+ const char* const* enums_;
+};
+
+
typedef bool (*ServiceMethodEntry)(Thread* thread, JSONStream* js);
@@ -2191,6 +2311,80 @@ static bool GetCoverage(Thread* thread, JSONStream* js) {
}
+static const char* kCallSitesStr = "CallSites";
+static const char* kCoverageStr = "Coverage";
+
+
+static const char* const report_enum_names[] = {
+ kCallSitesStr,
+ kCoverageStr,
+ NULL,
+};
+
+
+static const EnumListParameter* reports_parameter =
+ new EnumListParameter("reports", true, report_enum_names);
+
+
+static const MethodParameter* get_source_report_params[] = {
+ ISOLATE_PARAMETER,
+ reports_parameter,
+ new IdParameter("scriptId", false),
+ new UIntParameter("tokenPos", false),
+ new UIntParameter("endTokenPos", false),
+ NULL,
+};
+
+
+static bool GetSourceReport(Thread* thread, JSONStream* js) {
+ const char* reports_str = js->LookupParam("reports");
+ const char** reports = reports_parameter->Parse(thread->zone(), reports_str);
+ intptr_t report_set = 0;
+ while (*reports != NULL) {
+ if (strcmp(*reports, kCallSitesStr) == 0) {
+ report_set |= SourceReport::kCallSites;
+ } else if (strcmp(*reports, kCoverageStr) == 0) {
+ report_set |= SourceReport::kCoverage;
+ }
+ reports++;
+ }
+
+ Script& script = Script::Handle();
+ intptr_t start_pos = UIntParameter::Parse(js->LookupParam("tokenPos"));
+ intptr_t end_pos = UIntParameter::Parse(js->LookupParam("endTokenPos"));
+
+ if (js->HasParam("scriptId")) {
+ // Get the target script.
+ const char* script_id_param = js->LookupParam("scriptId");
+ const Object& obj =
+ Object::Handle(LookupHeapObject(thread, script_id_param, NULL));
+ if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
+ PrintInvalidParamError(js, "scriptId");
+ return true;
+ }
+ script ^= obj.raw();
+ } else {
+ if (js->HasParam("tokenPos")) {
+ js->PrintError(
+ kInvalidParams,
+ "%s: the 'tokenPos' parameter requires the 'scriptId' parameter",
+ js->method());
+ return true;
+ }
+ if (js->HasParam("endTokenPos")) {
+ js->PrintError(
+ kInvalidParams,
+ "%s: the 'endTokenPos' parameter requires the 'scriptId' parameter",
+ js->method());
+ return true;
+ }
+ }
+ SourceReport report(report_set);
+ report.PrintJSON(js, script, start_pos, end_pos);
+ return true;
+}
+
+
static const MethodParameter* get_call_site_data_params[] = {
ISOLATE_PARAMETER,
new IdParameter("targetId", false),
@@ -3608,6 +3802,8 @@ static const ServiceMethodDescriptor service_methods_[] = {
get_retained_size_params },
{ "_getRetainingPath", GetRetainingPath,
get_retaining_path_params },
+ { "_getSourceReport", GetSourceReport,
+ get_source_report_params },
{ "getStack", GetStack,
get_stack_params },
{ "_getTagProfile", GetTagProfile,
« no previous file with comments | « runtime/observatory/tests/service/get_source_report_test.dart ('k') | runtime/vm/source_report.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698