| 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(); |
| 27 for (intptr_t i = 0; i < len; i++) { |
| 28 map->Add(-1); |
| 29 } |
| 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 ComputeTokenPosToLineNumberMap(script, &pos_to_line); |
| 91 saved_url = script.url(); | 118 saved_url = script.url(); |
| 92 jsobj.AddProperty("source", saved_url.ToCString()); | 119 jsobj.AddProperty("source", saved_url.ToCString()); |
| 93 jsobj.AddProperty("script", script); | 120 jsobj.AddProperty("script", script); |
| 94 JSONArray hits_arr(&jsobj, "hits"); | 121 JSONArray hits_arr(&jsobj, "hits"); |
| 95 | 122 |
| 96 // We stay within this loop while we are seeing functions from the same | 123 // We stay within this loop while we are seeing functions from the same |
| 97 // source URI. | 124 // source URI. |
| 98 while (i < functions.Length()) { | 125 while (i < functions.Length()) { |
| 99 function ^= functions.At(i); | 126 function ^= functions.At(i); |
| 100 script = function.script(); | 127 script = function.script(); |
| 101 url = script.url(); | 128 url = script.url(); |
| 102 if (!url.Equals(saved_url)) { | 129 if (!url.Equals(saved_url)) { |
| 130 pos_to_line.Clear(); |
| 103 break; | 131 break; |
| 104 } | 132 } |
| 105 CompileAndAdd(function, hits_arr); | 133 CompileAndAdd(function, hits_arr, pos_to_line); |
| 106 if (function.HasImplicitClosureFunction()) { | 134 if (function.HasImplicitClosureFunction()) { |
| 107 function = function.ImplicitClosureFunction(); | 135 function = function.ImplicitClosureFunction(); |
| 108 CompileAndAdd(function, hits_arr); | 136 CompileAndAdd(function, hits_arr, pos_to_line); |
| 109 } | 137 } |
| 110 i++; | 138 i++; |
| 111 } | 139 } |
| 112 } | 140 } |
| 113 | 141 |
| 114 GrowableObjectArray& closures = | 142 GrowableObjectArray& closures = |
| 115 GrowableObjectArray::Handle(cls.closures()); | 143 GrowableObjectArray::Handle(cls.closures()); |
| 116 if (!closures.IsNull()) { | 144 if (!closures.IsNull()) { |
| 117 i = 0; | 145 i = 0; |
| 146 pos_to_line.Clear(); |
| 118 // We need to keep rechecking the length of the closures array, as handling | 147 // We need to keep rechecking the length of the closures array, as handling |
| 119 // a closure potentially adds new entries to the end. | 148 // a closure potentially adds new entries to the end. |
| 120 while (i < closures.Length()) { | 149 while (i < closures.Length()) { |
| 121 HANDLESCOPE(isolate); | 150 HANDLESCOPE(isolate); |
| 122 function ^= closures.At(i); | 151 function ^= closures.At(i); |
| 123 JSONObject jsobj(&jsarr); | 152 JSONObject jsobj(&jsarr); |
| 124 script = function.script(); | 153 script = function.script(); |
| 154 ComputeTokenPosToLineNumberMap(script, &pos_to_line); |
| 125 saved_url = script.url(); | 155 saved_url = script.url(); |
| 126 jsobj.AddProperty("source", saved_url.ToCString()); | 156 jsobj.AddProperty("source", saved_url.ToCString()); |
| 127 jsobj.AddProperty("script", script); | 157 jsobj.AddProperty("script", script); |
| 128 JSONArray hits_arr(&jsobj, "hits"); | 158 JSONArray hits_arr(&jsobj, "hits"); |
| 129 | 159 |
| 130 // We stay within this loop while we are seeing functions from the same | 160 // We stay within this loop while we are seeing functions from the same |
| 131 // source URI. | 161 // source URI. |
| 132 while (i < closures.Length()) { | 162 while (i < closures.Length()) { |
| 133 function ^= closures.At(i); | 163 function ^= closures.At(i); |
| 134 script = function.script(); | 164 script = function.script(); |
| 135 url = script.url(); | 165 url = script.url(); |
| 136 if (!url.Equals(saved_url)) { | 166 if (!url.Equals(saved_url)) { |
| 167 pos_to_line.Clear(); |
| 137 break; | 168 break; |
| 138 } | 169 } |
| 139 CompileAndAdd(function, hits_arr); | 170 CompileAndAdd(function, hits_arr, pos_to_line); |
| 140 i++; | 171 i++; |
| 141 } | 172 } |
| 142 } | 173 } |
| 143 } | 174 } |
| 144 } | 175 } |
| 145 | 176 |
| 146 | 177 |
| 147 void CodeCoverage::Write(Isolate* isolate) { | 178 void CodeCoverage::Write(Isolate* isolate) { |
| 148 if (FLAG_coverage_dir == NULL) { | 179 if (FLAG_coverage_dir == NULL) { |
| 149 return; | 180 return; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 // functions. | 227 // functions. |
| 197 PrintClass(cls, jsarr); | 228 PrintClass(cls, jsarr); |
| 198 } | 229 } |
| 199 } | 230 } |
| 200 } | 231 } |
| 201 } | 232 } |
| 202 } | 233 } |
| 203 | 234 |
| 204 | 235 |
| 205 } // namespace dart | 236 } // namespace dart |
| OLD | NEW |