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