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/coverage.h" | 5 #include "vm/coverage.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 | 8 |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/json_stream.h" | 10 #include "vm/json_stream.h" |
| 11 #include "vm/object.h" | 11 #include "vm/object.h" |
| 12 #include "vm/object_store.h" | 12 #include "vm/object_store.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 DEFINE_FLAG(charp, coverage_dir, NULL, | 16 DEFINE_FLAG(charp, coverage_dir, NULL, |
| 17 "Enable writing coverage data into specified directory."); | 17 "Enable writing coverage data into specified directory."); |
| 18 | 18 |
| 19 void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) { | 19 |
| 20 const Array& functions = Array::Handle(cls.functions()); | 20 int CodeCoverage::PrintFunctionsInSource(const String& source, |
| 21 ASSERT(!functions.IsNull()); | 21 const Array& functions, |
| 22 int index, | |
| 23 const JSONArray& hits_arr) { | |
| 24 Isolate* isolate = Isolate::Current(); | |
| 25 Code& code = Code::Handle(); | |
| 22 Function& function = Function::Handle(); | 26 Function& function = Function::Handle(); |
| 23 Code& code = Code::Handle(); | |
| 24 Script& script = Script::Handle(); | 27 Script& script = Script::Handle(); |
| 25 String& url = String::Handle(); | 28 String& url = String::Handle(); |
| 26 String& name = String::Handle(); | |
| 27 PcDescriptors& descriptors = PcDescriptors::Handle(); | 29 PcDescriptors& descriptors = PcDescriptors::Handle(); |
| 28 Array& ic_array = Array::Handle(); | 30 Array& ic_array = Array::Handle(); |
| 29 ICData& ic_data = ICData::Handle(); | 31 ICData& ic_data = ICData::Handle(); |
| 30 for (int i = 0; i < functions.Length(); i++) { | 32 // 2^64-1: 20 digits. String format: "<line>-<line>\0". |
| 31 function ^= functions.At(i); | 33 const intptr_t kMaxLineRangeLen = 42; |
| 34 char line_str[kMaxLineRangeLen]; | |
| 32 | 35 |
| 33 JSONObject jsobj(&jsarr); | 36 while (index < functions.Length()) { |
| 37 HANDLESCOPE(isolate); | |
| 38 function ^= functions.At(index); | |
| 39 | |
| 34 script = function.script(); | 40 script = function.script(); |
| 35 url = script.url(); | 41 url = script.url(); |
| 36 name = function.QualifiedUserVisibleName(); | 42 if (!url.Equals(source)) { |
| 37 jsobj.AddProperty("source", url.ToCString()); | 43 // Abort adding hitcounts to this particular script file entry as soon as |
| 38 jsobj.AddProperty("function", name.ToCString()); | 44 // we find a function residing in a different script. |
| 39 | 45 return index; |
| 40 JSONArray jsarr(&jsobj, "hits"); | 46 } |
| 41 | 47 |
| 42 if (function.HasCode()) { | 48 if (function.HasCode()) { |
|
Ivan Posva
2013/09/27 20:19:54
As we discussed to get more complete coverage of f
Michael Lippautz (Google)
2013/09/27 21:46:50
Done.
| |
| 43 // Print the hit counts for all IC datas. | 49 // Print the hit counts for all IC datas. |
| 44 code = function.unoptimized_code(); | 50 code = function.unoptimized_code(); |
| 45 ic_array = code.ExtractTypeFeedbackArray(); | 51 ic_array = code.ExtractTypeFeedbackArray(); |
| 46 descriptors = code.pc_descriptors(); | 52 descriptors = code.pc_descriptors(); |
| 47 | 53 |
| 48 for (int j = 0; j < descriptors.Length(); j++) { | 54 for (int j = 0; j < descriptors.Length(); j++) { |
| 55 HANDLESCOPE(isolate); | |
| 49 PcDescriptors::Kind kind = descriptors.DescriptorKind(j); | 56 PcDescriptors::Kind kind = descriptors.DescriptorKind(j); |
| 50 // Only IC based calls have counting. | 57 // Only IC based calls have counting. |
| 51 if ((kind == PcDescriptors::kIcCall) || | 58 if ((kind == PcDescriptors::kIcCall) || |
| 52 (kind == PcDescriptors::kUnoptStaticCall)) { | 59 (kind == PcDescriptors::kUnoptStaticCall)) { |
| 53 intptr_t deopt_id = descriptors.DeoptId(j); | 60 intptr_t deopt_id = descriptors.DeoptId(j); |
| 54 ic_data ^= ic_array.At(deopt_id); | 61 ic_data ^= ic_array.At(deopt_id); |
| 55 if (!ic_data.IsNull()) { | 62 if (!ic_data.IsNull()) { |
| 56 intptr_t token_pos = descriptors.TokenPos(j); | 63 intptr_t token_pos = descriptors.TokenPos(j); |
| 57 intptr_t line = -1; | 64 intptr_t line = -1; |
| 58 intptr_t col = -1; | 65 script.GetTokenLocation(token_pos, &line, NULL); |
| 59 script.GetTokenLocation(token_pos, &line, &col); | 66 hits_arr.AddValue(line); |
| 60 JSONObject ic_info(&jsarr); | 67 hits_arr.AddValue(ic_data.AggregateCount()); |
| 61 ic_info.AddProperty("line", line); | |
| 62 ic_info.AddProperty("col", col); | |
| 63 ic_info.AddProperty("count", ic_data.AggregateCount()); | |
| 64 } | 68 } |
| 65 } | 69 } |
| 66 } | 70 } |
| 67 } else { | 71 } else { |
| 68 // The function has no code so it was never executed and thus we add one | 72 // The function has no code so it was never executed and thus we add a |
| 69 // zero count hit at the first token index. | 73 // zero count hit for the line (or range of lines) the function is defined |
| 70 intptr_t line = -1; | 74 // on. |
| 71 intptr_t col = -1; | 75 intptr_t start_line = -1; |
| 72 script.GetTokenLocation(function.token_pos(), &line, &col); | 76 intptr_t end_line = -1; |
| 73 JSONObject func_info(&jsarr); | 77 script.GetTokenLocation(function.token_pos(), &start_line, NULL); |
| 74 func_info.AddProperty("line", line); | 78 script.GetTokenLocation(function.end_token_pos(), &end_line, NULL); |
| 75 func_info.AddProperty("col", col); | 79 if (start_line == end_line) { |
| 76 func_info.AddProperty("count", static_cast<intptr_t>(0)); | 80 hits_arr.AddValue(start_line); |
| 81 hits_arr.AddValue(static_cast<intptr_t>(0)); | |
| 82 } else { | |
| 83 OS::SNPrint(line_str, kMaxLineRangeLen, "%d-%d", start_line, end_line); | |
|
Ivan Posva
2013/09/27 20:19:54
Please remove the : from the description of the ch
Michael Lippautz (Google)
2013/09/27 21:46:50
Done. There are no ranges anymore.
| |
| 84 hits_arr.AddValue(line_str); | |
| 85 hits_arr.AddValue(static_cast<intptr_t>(0)); | |
| 86 } | |
| 77 } | 87 } |
| 88 | |
| 89 index++; | |
| 90 } | |
| 91 return index; | |
| 92 } | |
| 93 | |
| 94 void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) { | |
| 95 Isolate* isolate = Isolate::Current(); | |
| 96 const Array& functions = Array::Handle(cls.functions()); | |
| 97 ASSERT(!functions.IsNull()); | |
| 98 Function& function = Function::Handle(); | |
| 99 Script& script = Script::Handle(); | |
| 100 String& url = String::Handle(); | |
| 101 int i = 0; | |
| 102 while (i < functions.Length()) { | |
|
Ivan Posva
2013/09/27 20:19:54
As discussed off-line we also need to iterate over
Michael Lippautz (Google)
2013/09/27 21:46:50
Done.
| |
| 103 HANDLESCOPE(isolate); | |
| 104 function ^= functions.At(i); | |
| 105 | |
| 106 JSONObject jsobj(&jsarr); | |
| 107 script = function.script(); | |
| 108 url = script.url(); | |
| 109 jsobj.AddProperty("source", url.ToCString()); | |
| 110 | |
| 111 JSONArray hits_arr(&jsobj, "hits"); | |
| 112 i = PrintFunctionsInSource(url, functions, i, hits_arr); | |
| 78 } | 113 } |
| 79 } | 114 } |
| 80 | 115 |
| 81 | 116 |
| 82 void CodeCoverage::Write(Isolate* isolate) { | 117 void CodeCoverage::Write(Isolate* isolate) { |
| 83 if (FLAG_coverage_dir == NULL) { | 118 if (FLAG_coverage_dir == NULL) { |
| 84 return; | 119 return; |
| 85 } | 120 } |
| 86 | 121 |
| 87 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 122 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
| 88 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 123 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
| 89 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 124 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
| 90 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { | 125 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { |
| 91 return; | 126 return; |
| 92 } | 127 } |
| 93 | 128 |
| 94 JSONStream stream; | 129 JSONStream stream; |
| 95 { | 130 { |
| 96 const GrowableObjectArray& libs = GrowableObjectArray::Handle( | 131 const GrowableObjectArray& libs = GrowableObjectArray::Handle( |
| 97 isolate, isolate->object_store()->libraries()); | 132 isolate, isolate->object_store()->libraries()); |
| 98 Library& lib = Library::Handle(); | 133 Library& lib = Library::Handle(); |
| 99 Class& cls = Class::Handle(); | 134 Class& cls = Class::Handle(); |
| 100 JSONArray jsarr(&stream); | 135 JSONArray jsarr(&stream); |
| 101 for (int i = 0; i < libs.Length(); i++) { | 136 for (int i = 0; i < libs.Length(); i++) { |
| 102 lib ^= libs.At(i); | 137 lib ^= libs.At(i); |
| 103 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | 138 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
| 104 while (it.HasNext()) { | 139 while (it.HasNext()) { |
| 105 cls = it.GetNextClass(); | 140 cls = it.GetNextClass(); |
| 106 if (cls.is_finalized()) { | 141 if (cls.is_finalized()) { |
|
Ivan Posva
2013/09/27 20:19:54
To have a more complete picture we should call Ens
Michael Lippautz (Google)
2013/09/27 21:46:50
Done.
| |
| 107 // Only classes that have been finalized do have a meaningful list of | 142 // Only classes that have been finalized do have a meaningful list of |
| 108 // functions. | 143 // functions. |
| 109 PrintClass(cls, jsarr); | 144 PrintClass(cls, jsarr); |
| 110 } | 145 } |
| 111 } | 146 } |
| 112 } | 147 } |
| 113 } | 148 } |
| 114 | 149 |
| 115 const char* format = "%s/dart-cov-%" Pd "-%" Pd ".json"; | 150 const char* format = "%s/dart-cov-%" Pd "-%" Pd ".json"; |
| 116 intptr_t pid = OS::ProcessId(); | 151 intptr_t pid = OS::ProcessId(); |
| 117 intptr_t len = OS::SNPrint(NULL, 0, format, | 152 intptr_t len = OS::SNPrint(NULL, 0, format, |
| 118 FLAG_coverage_dir, pid, isolate->main_port()); | 153 FLAG_coverage_dir, pid, isolate->main_port()); |
| 119 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 154 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 120 OS::SNPrint(filename, len + 1, format, | 155 OS::SNPrint(filename, len + 1, format, |
| 121 FLAG_coverage_dir, pid, isolate->main_port()); | 156 FLAG_coverage_dir, pid, isolate->main_port()); |
| 122 void* file = (*file_open)(filename, true); | 157 void* file = (*file_open)(filename, true); |
| 123 if (file == NULL) { | 158 if (file == NULL) { |
| 124 OS::Print("Failed to write coverage file: %s\n", filename); | 159 OS::Print("Failed to write coverage file: %s\n", filename); |
| 125 return; | 160 return; |
| 126 } | 161 } |
| 127 (*file_write)(stream.buffer()->buf(), stream.buffer()->length(), file); | 162 (*file_write)(stream.buffer()->buf(), stream.buffer()->length(), file); |
| 128 (*file_close)(file); | 163 (*file_close)(file); |
| 129 } | 164 } |
| 130 | 165 |
| 131 } // namespace dart | 166 } // namespace dart |
| OLD | NEW |