| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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/source_report.h" | 5 #include "vm/source_report.h" |
| 6 | 6 |
| 7 #include "vm/compiler.h" | 7 #include "vm/compiler.h" |
| 8 #include "vm/object.h" | 8 #include "vm/object.h" |
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 SourceReport::SourceReport(intptr_t report_set, CompileMode compile_mode) | 13 SourceReport::SourceReport(intptr_t report_set, CompileMode compile_mode) |
| 14 : report_set_(report_set), | 14 : report_set_(report_set), |
| 15 compile_mode_(compile_mode), | 15 compile_mode_(compile_mode), |
| 16 thread_(NULL), | 16 thread_(NULL), |
| 17 script_(NULL), | 17 script_(NULL), |
| 18 start_pos_(-1), | 18 start_pos_(TokenPosition::kNoSource), |
| 19 end_pos_(-1), | 19 end_pos_(TokenPosition::kNoSource), |
| 20 next_script_index_(0) { | 20 next_script_index_(0) { |
| 21 } | 21 } |
| 22 | 22 |
| 23 | 23 |
| 24 void SourceReport::Init(Thread* thread, | 24 void SourceReport::Init(Thread* thread, |
| 25 const Script* script, | 25 const Script* script, |
| 26 intptr_t start_pos, | 26 TokenPosition start_pos, |
| 27 intptr_t end_pos) { | 27 TokenPosition end_pos) { |
| 28 thread_ = thread; | 28 thread_ = thread; |
| 29 script_ = script; | 29 script_ = script; |
| 30 start_pos_ = start_pos; | 30 start_pos_ = start_pos; |
| 31 end_pos_ = end_pos; | 31 end_pos_ = end_pos; |
| 32 script_table_entries_.Clear(); | 32 script_table_entries_.Clear(); |
| 33 script_table_.Clear(); | 33 script_table_.Clear(); |
| 34 next_script_index_ = 0; | 34 next_script_index_ = 0; |
| 35 } | 35 } |
| 36 | 36 |
| 37 | 37 |
| 38 bool SourceReport::IsReportRequested(ReportKind report_kind) { | 38 bool SourceReport::IsReportRequested(ReportKind report_kind) { |
| 39 return (report_set_ & report_kind) != 0; | 39 return (report_set_ & report_kind) != 0; |
| 40 } | 40 } |
| 41 | 41 |
| 42 | 42 |
| 43 bool SourceReport::ShouldSkipFunction(const Function& func) { | 43 bool SourceReport::ShouldSkipFunction(const Function& func) { |
| 44 if (script_ != NULL && !script_->IsNull()) { | 44 if (script_ != NULL && !script_->IsNull()) { |
| 45 if (func.script() != script_->raw()) { | 45 if (func.script() != script_->raw()) { |
| 46 // The function is from the wrong script. | 46 // The function is from the wrong script. |
| 47 return true; | 47 return true; |
| 48 } | 48 } |
| 49 if (((start_pos_ > 0) && (func.end_token_pos() < start_pos_)) || | 49 if (((start_pos_ > TokenPosition::kMinSource) && |
| 50 ((end_pos_ > 0) && (func.token_pos() > end_pos_))) { | 50 (func.end_token_pos() < start_pos_)) || |
| 51 ((end_pos_ > TokenPosition::kMinSource) && |
| 52 (func.token_pos() > end_pos_))) { |
| 51 // The function does not intersect with the requested token range. | 53 // The function does not intersect with the requested token range. |
| 52 return true; | 54 return true; |
| 53 } | 55 } |
| 54 } | 56 } |
| 55 | 57 |
| 56 switch (func.kind()) { | 58 switch (func.kind()) { |
| 57 case RawFunction::kRegularFunction: | 59 case RawFunction::kRegularFunction: |
| 58 case RawFunction::kClosureFunction: | 60 case RawFunction::kClosureFunction: |
| 59 case RawFunction::kGetterFunction: | 61 case RawFunction::kGetterFunction: |
| 60 case RawFunction::kSetterFunction: | 62 case RawFunction::kSetterFunction: |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 return true; | 106 return true; |
| 105 } | 107 } |
| 106 } | 108 } |
| 107 return false; | 109 return false; |
| 108 } | 110 } |
| 109 | 111 |
| 110 | 112 |
| 111 void SourceReport::PrintCallSitesData(JSONObject* jsobj, | 113 void SourceReport::PrintCallSitesData(JSONObject* jsobj, |
| 112 const Function& func, | 114 const Function& func, |
| 113 const Code& code) { | 115 const Code& code) { |
| 114 const intptr_t begin_pos = func.token_pos(); | 116 const TokenPosition begin_pos = func.token_pos(); |
| 115 const intptr_t end_pos = func.end_token_pos(); | 117 const TokenPosition end_pos = func.end_token_pos(); |
| 116 | 118 |
| 117 ZoneGrowableArray<const ICData*>* ic_data_array = | 119 ZoneGrowableArray<const ICData*>* ic_data_array = |
| 118 new(zone()) ZoneGrowableArray<const ICData*>(); | 120 new(zone()) ZoneGrowableArray<const ICData*>(); |
| 119 func.RestoreICDataMap(ic_data_array, false /* clone descriptors */); | 121 func.RestoreICDataMap(ic_data_array, false /* clone descriptors */); |
| 120 const PcDescriptors& descriptors = PcDescriptors::Handle( | 122 const PcDescriptors& descriptors = PcDescriptors::Handle( |
| 121 zone(), code.pc_descriptors()); | 123 zone(), code.pc_descriptors()); |
| 122 | 124 |
| 123 JSONArray sites(jsobj, "callSites"); | 125 JSONArray sites(jsobj, "callSites"); |
| 124 | 126 |
| 125 PcDescriptors::Iterator iter( | 127 PcDescriptors::Iterator iter( |
| 126 descriptors, | 128 descriptors, |
| 127 RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall); | 129 RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall); |
| 128 while (iter.MoveNext()) { | 130 while (iter.MoveNext()) { |
| 129 HANDLESCOPE(thread()); | 131 HANDLESCOPE(thread()); |
| 130 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; | 132 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; |
| 131 if (!ic_data->IsNull()) { | 133 if (!ic_data->IsNull()) { |
| 132 const intptr_t token_pos = iter.TokenPos(); | 134 const TokenPosition token_pos = iter.TokenPos(); |
| 133 if ((token_pos < begin_pos) || (token_pos > end_pos)) { | 135 if ((token_pos < begin_pos) || (token_pos > end_pos)) { |
| 134 // Does not correspond to a valid source position. | 136 // Does not correspond to a valid source position. |
| 135 continue; | 137 continue; |
| 136 } | 138 } |
| 137 bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall; | 139 bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall; |
| 138 ic_data->PrintToJSONArrayNew(sites, token_pos, is_static_call); | 140 ic_data->PrintToJSONArrayNew(sites, token_pos, is_static_call); |
| 139 } | 141 } |
| 140 } | 142 } |
| 141 } | 143 } |
| 142 | 144 |
| 143 void SourceReport::PrintCoverageData(JSONObject* jsobj, | 145 void SourceReport::PrintCoverageData(JSONObject* jsobj, |
| 144 const Function& func, | 146 const Function& func, |
| 145 const Code& code) { | 147 const Code& code) { |
| 146 const intptr_t begin_pos = func.token_pos(); | 148 const TokenPosition begin_pos = func.token_pos(); |
| 147 const intptr_t end_pos = func.end_token_pos(); | 149 const TokenPosition end_pos = func.end_token_pos(); |
| 148 | 150 |
| 149 ZoneGrowableArray<const ICData*>* ic_data_array = | 151 ZoneGrowableArray<const ICData*>* ic_data_array = |
| 150 new(zone()) ZoneGrowableArray<const ICData*>(); | 152 new(zone()) ZoneGrowableArray<const ICData*>(); |
| 151 func.RestoreICDataMap(ic_data_array, false /* clone descriptors */); | 153 func.RestoreICDataMap(ic_data_array, false /* clone descriptors */); |
| 152 const PcDescriptors& descriptors = PcDescriptors::Handle( | 154 const PcDescriptors& descriptors = PcDescriptors::Handle( |
| 153 zone(), code.pc_descriptors()); | 155 zone(), code.pc_descriptors()); |
| 154 | 156 |
| 155 const int kCoverageNone = 0; | 157 const int kCoverageNone = 0; |
| 156 const int kCoverageMiss = 1; | 158 const int kCoverageMiss = 1; |
| 157 const int kCoverageHit = 2; | 159 const int kCoverageHit = 2; |
| 158 | 160 |
| 159 intptr_t func_length = (end_pos - begin_pos) + 1; | 161 intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1; |
| 160 GrowableArray<char> coverage(func_length); | 162 GrowableArray<char> coverage(func_length); |
| 161 coverage.SetLength(func_length); | 163 coverage.SetLength(func_length); |
| 162 for (int i = 0; i < func_length; i++) { | 164 for (int i = 0; i < func_length; i++) { |
| 163 coverage[i] = kCoverageNone; | 165 coverage[i] = kCoverageNone; |
| 164 } | 166 } |
| 165 | 167 |
| 166 PcDescriptors::Iterator iter( | 168 PcDescriptors::Iterator iter( |
| 167 descriptors, | 169 descriptors, |
| 168 RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall); | 170 RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall); |
| 169 while (iter.MoveNext()) { | 171 while (iter.MoveNext()) { |
| 170 HANDLESCOPE(thread()); | 172 HANDLESCOPE(thread()); |
| 171 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; | 173 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; |
| 172 if (!ic_data->IsNull()) { | 174 if (!ic_data->IsNull()) { |
| 173 const intptr_t token_pos = iter.TokenPos(); | 175 const TokenPosition token_pos = iter.TokenPos(); |
| 174 if ((token_pos < begin_pos) || (token_pos > end_pos)) { | 176 if ((token_pos < begin_pos) || (token_pos > end_pos)) { |
| 175 // Does not correspond to a valid source position. | 177 // Does not correspond to a valid source position. |
| 176 continue; | 178 continue; |
| 177 } | 179 } |
| 178 intptr_t count = ic_data->AggregateCount(); | 180 intptr_t count = ic_data->AggregateCount(); |
| 179 intptr_t token_offset = token_pos - begin_pos; | 181 intptr_t token_offset = token_pos.Pos() - begin_pos.Pos(); |
| 180 if (count > 0) { | 182 if (count > 0) { |
| 181 coverage[token_offset] = kCoverageHit; | 183 coverage[token_offset] = kCoverageHit; |
| 182 } else { | 184 } else { |
| 183 if (coverage[token_offset] == kCoverageNone) { | 185 if (coverage[token_offset] == kCoverageNone) { |
| 184 coverage[token_offset] = kCoverageMiss; | 186 coverage[token_offset] = kCoverageMiss; |
| 185 } | 187 } |
| 186 } | 188 } |
| 187 } | 189 } |
| 188 } | 190 } |
| 189 | 191 |
| 190 JSONObject cov(jsobj, "coverage"); | 192 JSONObject cov(jsobj, "coverage"); |
| 191 { | 193 { |
| 192 JSONArray hits(&cov, "hits"); | 194 JSONArray hits(&cov, "hits"); |
| 193 for (int i = 0; i < func_length; i++) { | 195 for (int i = 0; i < func_length; i++) { |
| 194 if (coverage[i] == kCoverageHit) { | 196 if (coverage[i] == kCoverageHit) { |
| 195 hits.AddValue(begin_pos + i); // Add the token position of the hit. | 197 // Add the token position of the hit. |
| 198 hits.AddValue(begin_pos.Pos() + i); |
| 196 } | 199 } |
| 197 } | 200 } |
| 198 } | 201 } |
| 199 { | 202 { |
| 200 JSONArray misses(&cov, "misses"); | 203 JSONArray misses(&cov, "misses"); |
| 201 for (int i = 0; i < func_length; i++) { | 204 for (int i = 0; i < func_length; i++) { |
| 202 if (coverage[i] == kCoverageMiss) { | 205 if (coverage[i] == kCoverageMiss) { |
| 203 misses.AddValue(begin_pos + i); // Add the token position of the miss. | 206 // Add the token position of the miss. |
| 207 misses.AddValue(begin_pos.Pos() + i); |
| 204 } | 208 } |
| 205 } | 209 } |
| 206 } | 210 } |
| 207 } | 211 } |
| 208 | 212 |
| 209 void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj, | 213 void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj, |
| 210 const Function& func, | 214 const Function& func, |
| 211 const Code& code) { | 215 const Code& code) { |
| 212 const uint8_t kSafepointKind = (RawPcDescriptors::kIcCall | | 216 const uint8_t kSafepointKind = (RawPcDescriptors::kIcCall | |
| 213 RawPcDescriptors::kUnoptStaticCall | | 217 RawPcDescriptors::kUnoptStaticCall | |
| 214 RawPcDescriptors::kRuntimeCall); | 218 RawPcDescriptors::kRuntimeCall); |
| 215 const intptr_t begin_pos = func.token_pos(); | 219 const TokenPosition begin_pos = func.token_pos(); |
| 216 const intptr_t end_pos = func.end_token_pos(); | 220 const TokenPosition end_pos = func.end_token_pos(); |
| 217 | 221 |
| 218 const PcDescriptors& descriptors = PcDescriptors::Handle( | 222 const PcDescriptors& descriptors = PcDescriptors::Handle( |
| 219 zone(), code.pc_descriptors()); | 223 zone(), code.pc_descriptors()); |
| 220 | 224 |
| 221 intptr_t func_length = (end_pos - begin_pos) + 1; | 225 intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1; |
| 222 GrowableArray<char> possible(func_length); | 226 GrowableArray<char> possible(func_length); |
| 223 possible.SetLength(func_length); | 227 possible.SetLength(func_length); |
| 224 for (int i = 0; i < func_length; i++) { | 228 for (int i = 0; i < func_length; i++) { |
| 225 possible[i] = false; | 229 possible[i] = false; |
| 226 } | 230 } |
| 227 | 231 |
| 228 PcDescriptors::Iterator iter(descriptors, kSafepointKind); | 232 PcDescriptors::Iterator iter(descriptors, kSafepointKind); |
| 229 while (iter.MoveNext()) { | 233 while (iter.MoveNext()) { |
| 230 const intptr_t token_pos = iter.TokenPos(); | 234 const TokenPosition token_pos = iter.TokenPos(); |
| 231 if ((token_pos < begin_pos) || (token_pos > end_pos)) { | 235 if ((token_pos < begin_pos) || (token_pos > end_pos)) { |
| 232 // Does not correspond to a valid source position. | 236 // Does not correspond to a valid source position. |
| 233 continue; | 237 continue; |
| 234 } | 238 } |
| 235 intptr_t token_offset = token_pos - begin_pos; | 239 intptr_t token_offset = token_pos.Pos() - begin_pos.Pos(); |
| 236 possible[token_offset] = true; | 240 possible[token_offset] = true; |
| 237 } | 241 } |
| 238 | 242 |
| 239 JSONArray bpts(jsobj, "possibleBreakpoints"); | 243 JSONArray bpts(jsobj, "possibleBreakpoints"); |
| 240 for (int i = 0; i < func_length; i++) { | 244 for (int i = 0; i < func_length; i++) { |
| 241 if (possible[i]) { | 245 if (possible[i]) { |
| 242 bpts.AddValue(begin_pos + i); // Add the token position. | 246 // Add the token position. |
| 247 bpts.AddValue(begin_pos.Pos() + i); |
| 243 } | 248 } |
| 244 } | 249 } |
| 245 } | 250 } |
| 246 | 251 |
| 247 | 252 |
| 248 void SourceReport::PrintScriptTable(JSONArray* scripts) { | 253 void SourceReport::PrintScriptTable(JSONArray* scripts) { |
| 249 for (int i = 0; i < script_table_entries_.length(); i++) { | 254 for (int i = 0; i < script_table_entries_.length(); i++) { |
| 250 const Script* script = script_table_entries_[i].script; | 255 const Script* script = script_table_entries_[i].script; |
| 251 scripts->AddValue(*script); | 256 scripts->AddValue(*script); |
| 252 } | 257 } |
| 253 } | 258 } |
| 254 | 259 |
| 255 | 260 |
| 256 void SourceReport::VisitFunction(JSONArray* jsarr, const Function& func) { | 261 void SourceReport::VisitFunction(JSONArray* jsarr, const Function& func) { |
| 257 if (ShouldSkipFunction(func)) { | 262 if (ShouldSkipFunction(func)) { |
| 258 return; | 263 return; |
| 259 } | 264 } |
| 260 | 265 |
| 261 const Script& script = Script::Handle(zone(), func.script()); | 266 const Script& script = Script::Handle(zone(), func.script()); |
| 262 const intptr_t begin_pos = func.token_pos(); | 267 const TokenPosition begin_pos = func.token_pos(); |
| 263 const intptr_t end_pos = func.end_token_pos(); | 268 const TokenPosition end_pos = func.end_token_pos(); |
| 264 | 269 |
| 265 Code& code = Code::Handle(zone(), func.unoptimized_code()); | 270 Code& code = Code::Handle(zone(), func.unoptimized_code()); |
| 266 if (code.IsNull()) { | 271 if (code.IsNull()) { |
| 267 if (func.HasCode() || (compile_mode_ == kForceCompile)) { | 272 if (func.HasCode() || (compile_mode_ == kForceCompile)) { |
| 268 if (Compiler::EnsureUnoptimizedCode(thread(), func) != Error::null()) { | 273 if (Compiler::EnsureUnoptimizedCode(thread(), func) != Error::null()) { |
| 269 // Ignore the error and this function entirely. | 274 // Ignore the error and this function entirely. |
| 270 return; | 275 return; |
| 271 } | 276 } |
| 272 code = func.unoptimized_code(); | 277 code = func.unoptimized_code(); |
| 273 } else { | 278 } else { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 Function& func = Function::Handle(zone()); | 339 Function& func = Function::Handle(zone()); |
| 335 for (int i = 0; i < closures.Length(); i++) { | 340 for (int i = 0; i < closures.Length(); i++) { |
| 336 func ^= closures.At(i); | 341 func ^= closures.At(i); |
| 337 VisitFunction(jsarr, func); | 342 VisitFunction(jsarr, func); |
| 338 } | 343 } |
| 339 } | 344 } |
| 340 | 345 |
| 341 | 346 |
| 342 void SourceReport::PrintJSON(JSONStream* js, | 347 void SourceReport::PrintJSON(JSONStream* js, |
| 343 const Script& script, | 348 const Script& script, |
| 344 intptr_t start_pos, intptr_t end_pos) { | 349 TokenPosition start_pos, |
| 350 TokenPosition end_pos) { |
| 345 Init(Thread::Current(), &script, start_pos, end_pos); | 351 Init(Thread::Current(), &script, start_pos, end_pos); |
| 346 | 352 |
| 347 JSONObject report(js); | 353 JSONObject report(js); |
| 348 report.AddProperty("type", "SourceReport"); | 354 report.AddProperty("type", "SourceReport"); |
| 349 { | 355 { |
| 350 JSONArray ranges(&report, "ranges"); | 356 JSONArray ranges(&report, "ranges"); |
| 351 | 357 |
| 352 const GrowableObjectArray& libs = GrowableObjectArray::Handle( | 358 const GrowableObjectArray& libs = GrowableObjectArray::Handle( |
| 353 zone(), thread()->isolate()->object_store()->libraries()); | 359 zone(), thread()->isolate()->object_store()->libraries()); |
| 354 | 360 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 365 VisitClosures(&ranges); | 371 VisitClosures(&ranges); |
| 366 } | 372 } |
| 367 | 373 |
| 368 // Print the script table. | 374 // Print the script table. |
| 369 JSONArray scripts(&report, "scripts"); | 375 JSONArray scripts(&report, "scripts"); |
| 370 PrintScriptTable(&scripts); | 376 PrintScriptTable(&scripts); |
| 371 } | 377 } |
| 372 | 378 |
| 373 | 379 |
| 374 } // namespace dart | 380 } // namespace dart |
| OLD | NEW |