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/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| 11 #include "vm/json_stream.h" | 11 #include "vm/json_stream.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 | 14 |
| 15 namespace dart { | 15 namespace dart { |
| 16 | 16 |
| 17 DEFINE_FLAG(charp, coverage_dir, NULL, | 17 DEFINE_FLAG(charp, coverage_dir, NULL, |
| 18 "Enable writing coverage data into specified directory."); | 18 "Enable writing coverage data into specified directory."); |
| 19 | 19 |
| 20 | 20 |
| 21 // map[token_pos] -> line-number. | |
| 22 static void ComputeTokenPosToLineNumberMap(const Script& script, | |
| 23 GrowableArray<intptr_t>* map) { | |
| 24 const TokenStream& tkns = TokenStream::Handle(script.tokens()); | |
| 25 const intptr_t len = ExternalTypedData::Handle(tkns.GetStream()).Length(); | |
| 26 map->Clear(); | |
|
Ivan Posva
2014/06/10 21:34:48
map->ClearTo(-1);
| |
| 27 for (intptr_t i = 0; i < len; i++) { | |
| 28 map->Add(-1); | |
| 29 } | |
|
siva
2014/06/10 21:31:55
I am wondering if we should have an AddAt or Ensur
srdjan
2014/06/10 21:38:01
Agreed. Will do in a follow-up CL.
| |
| 30 TokenStream::Iterator tkit(tkns, 0, TokenStream::Iterator::kAllTokens); | |
| 31 intptr_t cur_line = script.line_offset() + 1; | |
| 32 while (tkit.CurrentTokenKind() != Token::kEOS) { | |
| 33 (*map)[tkit.CurrentPosition()] = cur_line; | |
| 34 if (tkit.CurrentTokenKind() == Token::kNEWLINE) { | |
| 35 cur_line++; | |
| 36 } | |
| 37 tkit.Advance(); | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 | |
| 21 void CodeCoverage::CompileAndAdd(const Function& function, | 42 void CodeCoverage::CompileAndAdd(const Function& function, |
| 22 const JSONArray& hits_arr) { | 43 const JSONArray& hits_arr, |
| 44 const GrowableArray<intptr_t>& pos_to_line) { | |
| 23 Isolate* isolate = Isolate::Current(); | 45 Isolate* isolate = Isolate::Current(); |
| 24 if (!function.HasCode()) { | 46 if (!function.HasCode()) { |
| 25 // If the function should not be compiled or if the compilation failed, | 47 // If the function should not be compiled or if the compilation failed, |
| 26 // then just skip this method. | 48 // then just skip this method. |
| 27 // TODO(iposva): Maybe we should skip synthesized methods in general too. | 49 // TODO(iposva): Maybe we should skip synthesized methods in general too. |
| 28 if (function.is_abstract() || function.IsRedirectingFactory()) { | 50 if (function.is_abstract() || function.IsRedirectingFactory()) { |
| 29 return; | 51 return; |
| 30 } | 52 } |
| 31 if (function.IsNonImplicitClosureFunction() && | 53 if (function.IsNonImplicitClosureFunction() && |
| 32 (function.context_scope() == ContextScope::null())) { | 54 (function.context_scope() == ContextScope::null())) { |
| 33 // TODO(iposva): This can arise if we attempt to compile an inner function | 55 // TODO(iposva): This can arise if we attempt to compile an inner function |
| 34 // before we have compiled its enclosing function or if the enclosing | 56 // before we have compiled its enclosing function or if the enclosing |
| 35 // function failed to compile. | 57 // function failed to compile. |
| 36 OS::Print("### Coverage skipped compiling: %s\n", function.ToCString()); | 58 OS::Print("### Coverage skipped compiling: %s\n", function.ToCString()); |
| 37 return; | 59 return; |
| 38 } | 60 } |
| 39 const Error& err = Error::Handle( | 61 const Error& err = Error::Handle( |
| 40 isolate, Compiler::CompileFunction(isolate, function)); | 62 isolate, Compiler::CompileFunction(isolate, function)); |
| 41 if (!err.IsNull()) { | 63 if (!err.IsNull()) { |
| 42 OS::Print("### Coverage failed compiling:\n%s\n", err.ToErrorCString()); | 64 OS::Print("### Coverage failed compiling:\n%s\n", err.ToErrorCString()); |
| 43 return; | 65 return; |
| 44 } | 66 } |
| 45 } | 67 } |
| 46 ASSERT(function.HasCode()); | 68 ASSERT(function.HasCode()); |
| 47 | 69 |
| 48 // Print the hit counts for all IC datas. | 70 // Print the hit counts for all IC datas. |
| 49 const Script& script = Script::Handle(function.script()); | |
| 50 const Code& code = Code::Handle(function.unoptimized_code()); | 71 const Code& code = Code::Handle(function.unoptimized_code()); |
| 51 const Array& ic_array = Array::Handle(code.ExtractTypeFeedbackArray()); | 72 const Array& ic_array = Array::Handle(code.ExtractTypeFeedbackArray()); |
| 52 const PcDescriptors& descriptors = PcDescriptors::Handle( | 73 const PcDescriptors& descriptors = PcDescriptors::Handle( |
| 53 code.pc_descriptors()); | 74 code.pc_descriptors()); |
| 54 ICData& ic_data = ICData::Handle(); | 75 ICData& ic_data = ICData::Handle(); |
| 55 | 76 |
| 56 for (int j = 0; j < descriptors.Length(); j++) { | 77 for (int j = 0; j < descriptors.Length(); j++) { |
| 57 HANDLESCOPE(isolate); | 78 HANDLESCOPE(isolate); |
| 58 PcDescriptors::Kind kind = descriptors.DescriptorKind(j); | 79 PcDescriptors::Kind kind = descriptors.DescriptorKind(j); |
| 59 // Only IC based calls have counting. | 80 // Only IC based calls have counting. |
| 60 if ((kind == PcDescriptors::kIcCall) || | 81 if ((kind == PcDescriptors::kIcCall) || |
| 61 (kind == PcDescriptors::kUnoptStaticCall)) { | 82 (kind == PcDescriptors::kUnoptStaticCall)) { |
| 62 intptr_t deopt_id = descriptors.DeoptId(j); | 83 intptr_t deopt_id = descriptors.DeoptId(j); |
| 63 ic_data ^= ic_array.At(deopt_id); | 84 ic_data ^= ic_array.At(deopt_id); |
| 64 if (!ic_data.IsNull()) { | 85 if (!ic_data.IsNull()) { |
| 65 intptr_t token_pos = descriptors.TokenPos(j); | 86 intptr_t token_pos = descriptors.TokenPos(j); |
| 66 intptr_t line = -1; | 87 intptr_t line = pos_to_line[token_pos]; |
| 67 script.GetTokenLocation(token_pos, &line, NULL); | 88 #if defined(DEBUG) |
| 89 const Script& script = Script::Handle(function.script()); | |
| 90 intptr_t test_line = -1; | |
| 91 script.GetTokenLocation(token_pos, &test_line, NULL); | |
| 92 ASSERT(test_line == line); | |
| 93 #endif | |
| 68 hits_arr.AddValue(line); | 94 hits_arr.AddValue(line); |
| 69 hits_arr.AddValue(ic_data.AggregateCount()); | 95 hits_arr.AddValue(ic_data.AggregateCount()); |
| 70 } | 96 } |
| 71 } | 97 } |
| 72 } | 98 } |
| 73 } | 99 } |
| 74 | 100 |
| 75 | 101 |
| 76 void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) { | 102 void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) { |
| 77 Isolate* isolate = Isolate::Current(); | 103 Isolate* isolate = Isolate::Current(); |
| 78 Array& functions = Array::Handle(cls.functions()); | 104 Array& functions = Array::Handle(cls.functions()); |
| 79 ASSERT(!functions.IsNull()); | 105 ASSERT(!functions.IsNull()); |
| 80 Function& function = Function::Handle(); | 106 Function& function = Function::Handle(); |
| 81 Script& script = Script::Handle(); | 107 Script& script = Script::Handle(); |
| 82 String& saved_url = String::Handle(); | 108 String& saved_url = String::Handle(); |
| 83 String& url = String::Handle(); | 109 String& url = String::Handle(); |
| 84 | 110 GrowableArray<intptr_t> pos_to_line; |
| 85 int i = 0; | 111 int i = 0; |
| 86 while (i < functions.Length()) { | 112 while (i < functions.Length()) { |
| 87 HANDLESCOPE(isolate); | 113 HANDLESCOPE(isolate); |
| 88 function ^= functions.At(i); | 114 function ^= functions.At(i); |
| 89 JSONObject jsobj(&jsarr); | 115 JSONObject jsobj(&jsarr); |
| 90 script = function.script(); | 116 script = function.script(); |
| 117 if (pos_to_line.is_empty()) { | |
|
Ivan Posva
2014/06/10 21:34:48
always?
srdjan
2014/06/10 21:38:01
Done.
| |
| 118 ComputeTokenPosToLineNumberMap(script, &pos_to_line); | |
| 119 } | |
| 91 saved_url = script.url(); | 120 saved_url = script.url(); |
| 92 jsobj.AddProperty("source", saved_url.ToCString()); | 121 jsobj.AddProperty("source", saved_url.ToCString()); |
| 93 jsobj.AddProperty("script", script); | 122 jsobj.AddProperty("script", script); |
| 94 JSONArray hits_arr(&jsobj, "hits"); | 123 JSONArray hits_arr(&jsobj, "hits"); |
| 95 | 124 |
| 96 // We stay within this loop while we are seeing functions from the same | 125 // We stay within this loop while we are seeing functions from the same |
| 97 // source URI. | 126 // source URI. |
| 98 while (i < functions.Length()) { | 127 while (i < functions.Length()) { |
| 99 function ^= functions.At(i); | 128 function ^= functions.At(i); |
| 100 script = function.script(); | 129 script = function.script(); |
| 101 url = script.url(); | 130 url = script.url(); |
| 102 if (!url.Equals(saved_url)) { | 131 if (!url.Equals(saved_url)) { |
| 132 pos_to_line.Clear(); | |
| 103 break; | 133 break; |
| 104 } | 134 } |
| 105 CompileAndAdd(function, hits_arr); | 135 CompileAndAdd(function, hits_arr, pos_to_line); |
| 106 if (function.HasImplicitClosureFunction()) { | 136 if (function.HasImplicitClosureFunction()) { |
| 107 function = function.ImplicitClosureFunction(); | 137 function = function.ImplicitClosureFunction(); |
| 108 CompileAndAdd(function, hits_arr); | 138 CompileAndAdd(function, hits_arr, pos_to_line); |
| 109 } | 139 } |
| 110 i++; | 140 i++; |
| 111 } | 141 } |
| 112 } | 142 } |
| 113 | 143 |
| 114 GrowableObjectArray& closures = | 144 GrowableObjectArray& closures = |
| 115 GrowableObjectArray::Handle(cls.closures()); | 145 GrowableObjectArray::Handle(cls.closures()); |
| 116 if (!closures.IsNull()) { | 146 if (!closures.IsNull()) { |
| 117 i = 0; | 147 i = 0; |
| 148 pos_to_line.Clear(); | |
| 118 // We need to keep rechecking the length of the closures array, as handling | 149 // We need to keep rechecking the length of the closures array, as handling |
| 119 // a closure potentially adds new entries to the end. | 150 // a closure potentially adds new entries to the end. |
| 120 while (i < closures.Length()) { | 151 while (i < closures.Length()) { |
| 121 HANDLESCOPE(isolate); | 152 HANDLESCOPE(isolate); |
| 122 function ^= closures.At(i); | 153 function ^= closures.At(i); |
| 123 JSONObject jsobj(&jsarr); | 154 JSONObject jsobj(&jsarr); |
| 124 script = function.script(); | 155 script = function.script(); |
| 156 if (pos_to_line.is_empty()) { | |
|
Ivan Posva
2014/06/10 21:34:48
ditto
srdjan
2014/06/10 21:38:01
Done.
| |
| 157 ComputeTokenPosToLineNumberMap(script, &pos_to_line); | |
| 158 } | |
| 125 saved_url = script.url(); | 159 saved_url = script.url(); |
| 126 jsobj.AddProperty("source", saved_url.ToCString()); | 160 jsobj.AddProperty("source", saved_url.ToCString()); |
| 127 jsobj.AddProperty("script", script); | 161 jsobj.AddProperty("script", script); |
| 128 JSONArray hits_arr(&jsobj, "hits"); | 162 JSONArray hits_arr(&jsobj, "hits"); |
| 129 | 163 |
| 130 // We stay within this loop while we are seeing functions from the same | 164 // We stay within this loop while we are seeing functions from the same |
| 131 // source URI. | 165 // source URI. |
| 132 while (i < closures.Length()) { | 166 while (i < closures.Length()) { |
| 133 function ^= closures.At(i); | 167 function ^= closures.At(i); |
| 134 script = function.script(); | 168 script = function.script(); |
| 135 url = script.url(); | 169 url = script.url(); |
| 136 if (!url.Equals(saved_url)) { | 170 if (!url.Equals(saved_url)) { |
| 171 pos_to_line.Clear(); | |
| 137 break; | 172 break; |
| 138 } | 173 } |
| 139 CompileAndAdd(function, hits_arr); | 174 CompileAndAdd(function, hits_arr, pos_to_line); |
| 140 i++; | 175 i++; |
| 141 } | 176 } |
| 142 } | 177 } |
| 143 } | 178 } |
| 144 } | 179 } |
| 145 | 180 |
| 146 | 181 |
| 147 void CodeCoverage::Write(Isolate* isolate) { | 182 void CodeCoverage::Write(Isolate* isolate) { |
| 148 if (FLAG_coverage_dir == NULL) { | 183 if (FLAG_coverage_dir == NULL) { |
| 149 return; | 184 return; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 // functions. | 231 // functions. |
| 197 PrintClass(cls, jsarr); | 232 PrintClass(cls, jsarr); |
| 198 } | 233 } |
| 199 } | 234 } |
| 200 } | 235 } |
| 201 } | 236 } |
| 202 } | 237 } |
| 203 | 238 |
| 204 | 239 |
| 205 } // namespace dart | 240 } // namespace dart |
| OLD | NEW |