| Index: runtime/vm/service.cc
|
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
|
| index 4cbc5ddba46f142d49aa4c71cb4551b87d1c3ebb..df8f3dc996ea5709aed180c9c8ce47d1e21ec21f 100644
|
| --- a/runtime/vm/service.cc
|
| +++ b/runtime/vm/service.cc
|
| @@ -259,6 +259,48 @@ static bool GetCodeId(const char* s, int64_t* timestamp, uword* address) {
|
| }
|
|
|
|
|
| +// Verifies that |s| begins with |prefix| and then calls |GetIntegerId| on
|
| +// the remainder of |s|.
|
| +static bool GetPrefixedIntegerId(const char* s,
|
| + const char* prefix,
|
| + intptr_t* service_id) {
|
| + if (s == NULL) {
|
| + return false;
|
| + }
|
| + ASSERT(prefix != NULL);
|
| + const intptr_t kInputLen = strlen(s);
|
| + const intptr_t kPrefixLen = strlen(prefix);
|
| + ASSERT(kPrefixLen > 0);
|
| + if (kInputLen <= kPrefixLen) {
|
| + return false;
|
| + }
|
| + if (strncmp(s, prefix, kPrefixLen) != 0) {
|
| + return false;
|
| + }
|
| + // Prefix satisfied. Move forward.
|
| + s += kPrefixLen;
|
| + // Attempt to read integer id.
|
| + return GetIntegerId(s, service_id);
|
| +}
|
| +
|
| +
|
| +static bool IsValidClassId(Isolate* isolate, intptr_t cid) {
|
| + ASSERT(isolate != NULL);
|
| + ClassTable* class_table = isolate->class_table();
|
| + ASSERT(class_table != NULL);
|
| + return class_table->IsValidIndex(cid) && class_table->HasValidClassAt(cid);
|
| +}
|
| +
|
| +
|
| +static RawClass* GetClassForId(Isolate* isolate, intptr_t cid) {
|
| + ASSERT(isolate == Isolate::Current());
|
| + ASSERT(isolate != NULL);
|
| + ClassTable* class_table = isolate->class_table();
|
| + ASSERT(class_table != NULL);
|
| + return class_table->At(cid);
|
| +}
|
| +
|
| +
|
| // TODO(johnmccutchan): Split into separate file and write unit tests.
|
| class MethodParameter {
|
| public:
|
| @@ -342,6 +384,9 @@ class UIntParameter : public MethodParameter {
|
| }
|
|
|
| static intptr_t Parse(const char* value) {
|
| + if (value == NULL) {
|
| + return -1;
|
| + }
|
| char* end_ptr = NULL;
|
| uintptr_t result = strtoul(value, &end_ptr, 10);
|
| ASSERT(*end_ptr == '\0'); // Parsed full string
|
| @@ -2236,6 +2281,7 @@ static const MethodParameter* get_cpu_profile_params[] = {
|
| };
|
|
|
|
|
| +// TODO(johnmccutchan): Rename this to GetCpuSamples.
|
| static bool GetCpuProfile(Isolate* isolate, JSONStream* js) {
|
| Profile::TagOrder tag_order =
|
| EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
|
| @@ -2244,6 +2290,30 @@ static bool GetCpuProfile(Isolate* isolate, JSONStream* js) {
|
| }
|
|
|
|
|
| +static const MethodParameter* get_allocation_samples_params[] = {
|
| + ISOLATE_PARAMETER,
|
| + new EnumParameter("tags", true, tags_enum_names),
|
| + new IdParameter("classId", false),
|
| + NULL,
|
| +};
|
| +
|
| +
|
| +static bool GetAllocationSamples(Isolate* isolate, JSONStream* js) {
|
| + Profile::TagOrder tag_order =
|
| + EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
|
| + const char* class_id = js->LookupParam("classId");
|
| + intptr_t cid = -1;
|
| + GetPrefixedIntegerId(class_id, "classes/", &cid);
|
| + if (IsValidClassId(isolate, cid)) {
|
| + const Class& cls = Class::Handle(GetClassForId(isolate, cid));
|
| + ProfilerService::PrintAllocationJSON(js, tag_order, cls);
|
| + } else {
|
| + PrintInvalidParamError(js, "classId");
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| static const MethodParameter* clear_cpu_profile_params[] = {
|
| ISOLATE_PARAMETER,
|
| NULL,
|
| @@ -2751,6 +2821,31 @@ static bool SetName(Isolate* isolate, JSONStream* js) {
|
| }
|
|
|
|
|
| +static const MethodParameter* set_trace_class_allocation_params[] = {
|
| + ISOLATE_PARAMETER,
|
| + new IdParameter("classId", true),
|
| + new BoolParameter("enable", true),
|
| + NULL,
|
| +};
|
| +
|
| +
|
| +static bool SetTraceClassAllocation(Isolate* isolate, JSONStream* js) {
|
| + const char* class_id = js->LookupParam("classId");
|
| + const bool enable = BoolParameter::Parse(js->LookupParam("enable"));
|
| + intptr_t cid = -1;
|
| + GetPrefixedIntegerId(class_id, "classes/", &cid);
|
| + if (!IsValidClassId(isolate, cid)) {
|
| + PrintInvalidParamError(js, "classId");
|
| + return true;
|
| + }
|
| + const Class& cls = Class::Handle(GetClassForId(isolate, cid));
|
| + ASSERT(!cls.IsNull());
|
| + cls.SetTraceAllocation(enable);
|
| + PrintSuccess(js);
|
| + return true;
|
| +}
|
| +
|
| +
|
| static ServiceMethodDescriptor service_methods_[] = {
|
| { "_dumpIdZone", DumpIdZone, NULL },
|
| { "_echo", Echo,
|
| @@ -2775,6 +2870,8 @@ static ServiceMethodDescriptor service_methods_[] = {
|
| evaluate_in_frame_params },
|
| { "_getAllocationProfile", GetAllocationProfile,
|
| get_allocation_profile_params },
|
| + { "_getAllocationSamples", GetAllocationSamples,
|
| + get_allocation_samples_params },
|
| { "_getCallSiteData", GetCallSiteData,
|
| get_call_site_data_params },
|
| { "getClassList", GetClassList,
|
| @@ -2837,6 +2934,8 @@ static ServiceMethodDescriptor service_methods_[] = {
|
| set_library_debuggable_params },
|
| { "setName", SetName,
|
| set_name_params },
|
| + { "_setTraceClassAllocation", SetTraceClassAllocation,
|
| + set_trace_class_allocation_params },
|
| };
|
|
|
|
|
|
|