Index: runtime/vm/coverage.cc |
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc |
deleted file mode 100644 |
index 7a678a0ce9d5cb5dc54e0721587a00891b9d144a..0000000000000000000000000000000000000000 |
--- a/runtime/vm/coverage.cc |
+++ /dev/null |
@@ -1,313 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-#include "vm/coverage.h" |
- |
-#include "include/dart_api.h" |
- |
-#include "vm/compiler.h" |
-#include "vm/isolate.h" |
-#include "vm/json_stream.h" |
-#include "vm/longjump.h" |
-#include "vm/object.h" |
-#include "vm/object_store.h" |
- |
-namespace dart { |
- |
-DEFINE_FLAG(charp, coverage_dir, NULL, |
- "Enable writing coverage data into specified directory."); |
- |
- |
-class CoverageFilterAll : public CoverageFilter { |
- public: |
- bool ShouldOutputCoverageFor(const Library& lib, |
- const Script& script, |
- const Class& cls, |
- const Function& func) const { |
- return true; |
- } |
-}; |
- |
- |
-// map[token_pos] -> line-number. |
-static void ComputeTokenPosToLineNumberMap(const Script& script, |
- GrowableArray<intptr_t>* map) { |
- const TokenStream& tkns = TokenStream::Handle(script.tokens()); |
- const intptr_t len = ExternalTypedData::Handle(tkns.GetStream()).Length(); |
- map->SetLength(len); |
-#if defined(DEBUG) |
- for (intptr_t i = 0; i < len; i++) { |
- (*map)[i] = -1; |
- } |
-#endif |
- TokenStream::Iterator tkit(tkns, |
- TokenPosition::kMinSource, |
- TokenStream::Iterator::kAllTokens); |
- intptr_t cur_line = script.line_offset() + 1; |
- while (tkit.CurrentTokenKind() != Token::kEOS) { |
- const intptr_t position = tkit.CurrentPosition().Pos(); |
- (*map)[position] = cur_line; |
- if (tkit.CurrentTokenKind() == Token::kNEWLINE) { |
- cur_line++; |
- } |
- tkit.Advance(); |
- } |
-} |
- |
- |
-void CodeCoverage::CompileAndAdd(const Function& function, |
- const JSONArray& hits_or_sites, |
- const GrowableArray<intptr_t>& pos_to_line, |
- bool as_call_sites) { |
- if (!FLAG_support_coverage) { |
- return; |
- } |
- // If the function should not be compiled for coverage analysis, then just |
- // skip this method. |
- // TODO(iposva): Maybe we should skip synthesized methods in general too. |
- if (function.is_abstract() || function.IsRedirectingFactory()) { |
- return; |
- } |
- if (function.IsNonImplicitClosureFunction() && |
- (function.context_scope() == ContextScope::null())) { |
- // TODO(iposva): This can arise if we attempt to compile an inner function |
- // before we have compiled its enclosing function or if the enclosing |
- // function failed to compile. |
- return; |
- } |
- Thread* thread = Thread::Current(); |
- Zone* zone = thread->zone(); |
- // Make sure we have the unoptimized code for this function available. |
- if (Compiler::EnsureUnoptimizedCode(thread, function) != Error::null()) { |
- // Ignore the error and this function entirely. |
- return; |
- } |
- const Code& code = Code::Handle(zone, function.unoptimized_code()); |
- ASSERT(!code.IsNull()); |
- |
- // Print the hit counts for all IC datas. |
- ZoneGrowableArray<const ICData*>* ic_data_array = |
- new(zone) ZoneGrowableArray<const ICData*>(); |
- function.RestoreICDataMap(ic_data_array, false /* clone ic-data */); |
- const PcDescriptors& descriptors = PcDescriptors::Handle( |
- zone, code.pc_descriptors()); |
- |
- const TokenPosition begin_pos = function.token_pos(); |
- const TokenPosition end_pos = function.end_token_pos(); |
- intptr_t last_line = -1; |
- intptr_t last_count = 0; |
- // Only IC based calls have counting. |
- PcDescriptors::Iterator iter(descriptors, |
- RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall); |
- while (iter.MoveNext()) { |
- HANDLESCOPE(thread); |
- const ICData* ic_data = (*ic_data_array)[iter.DeoptId()]; |
- if (!ic_data->IsNull()) { |
- const TokenPosition token_pos = iter.TokenPos(); |
- // Filter out descriptors that do not map to tokens in the source code. |
- if ((token_pos < begin_pos) || (token_pos > end_pos)) { |
- continue; |
- } |
- if (as_call_sites) { |
- bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall; |
- ic_data->PrintToJSONArray(hits_or_sites, |
- token_pos, |
- is_static_call); |
- } else { |
- intptr_t line = pos_to_line[token_pos.Pos()]; |
-#if defined(DEBUG) |
- const Script& script = Script::Handle(zone, function.script()); |
- intptr_t test_line = -1; |
- script.GetTokenLocation(token_pos, &test_line, NULL); |
- ASSERT(test_line == line); |
-#endif |
- // Merge hit data where possible. |
- if (last_line == line) { |
- last_count += ic_data->AggregateCount(); |
- } else { |
- if ((last_line != -1)) { |
- hits_or_sites.AddValue(last_line); |
- hits_or_sites.AddValue(last_count); |
- } |
- last_count = ic_data->AggregateCount(); |
- last_line = line; |
- } |
- } |
- } |
- } |
- // Write last hit value if needed. |
- if (!as_call_sites && (last_line != -1)) { |
- hits_or_sites.AddValue(last_line); |
- hits_or_sites.AddValue(last_count); |
- } |
-} |
- |
- |
-void CodeCoverage::PrintClass(const Library& lib, |
- const Class& cls, |
- const JSONArray& jsarr, |
- CoverageFilter* filter, |
- bool as_call_sites) { |
- if (!FLAG_support_coverage) { |
- return; |
- } |
- Thread* thread = Thread::Current(); |
- if (cls.EnsureIsFinalized(thread) != Error::null()) { |
- // Only classes that have been finalized do have a meaningful list of |
- // functions. |
- return; |
- } |
- Array& functions = Array::Handle(cls.functions()); |
- ASSERT(!functions.IsNull()); |
- Function& function = Function::Handle(); |
- Script& script = Script::Handle(); |
- String& saved_url = String::Handle(); |
- String& url = String::Handle(); |
- GrowableArray<intptr_t> pos_to_line; |
- int i = 0; |
- while (i < functions.Length()) { |
- HANDLESCOPE(thread); |
- function ^= functions.At(i); |
- script = function.script(); |
- saved_url = script.url(); |
- if (!filter->ShouldOutputCoverageFor(lib, script, cls, function)) { |
- i++; |
- continue; |
- } |
- if (!as_call_sites) { |
- ComputeTokenPosToLineNumberMap(script, &pos_to_line); |
- } |
- JSONObject jsobj(&jsarr); |
- jsobj.AddProperty("source", saved_url.ToCString()); |
- jsobj.AddProperty("script", script); |
- JSONArray hits_or_sites(&jsobj, as_call_sites ? "callSites" : "hits"); |
- |
- // We stay within this loop while we are seeing functions from the same |
- // source URI. |
- while (i < functions.Length()) { |
- function ^= functions.At(i); |
- script = function.script(); |
- url = script.url(); |
- if (!url.Equals(saved_url)) { |
- pos_to_line.Clear(); |
- break; |
- } |
- if (!filter->ShouldOutputCoverageFor(lib, script, cls, function)) { |
- i++; |
- continue; |
- } |
- CompileAndAdd(function, hits_or_sites, pos_to_line, as_call_sites); |
- i++; |
- } |
- } |
- |
- // TODO(turnidge): This looks like it prints closures many, many times. |
- const GrowableObjectArray& closures = GrowableObjectArray::Handle( |
- thread->isolate()->object_store()->closure_functions()); |
- pos_to_line.Clear(); |
- // We need to keep rechecking the length of the closures array, as handling |
- // a closure potentially adds new entries to the end. |
- i = 0; |
- while (i < closures.Length()) { |
- HANDLESCOPE(thread); |
- function ^= closures.At(i); |
- if (function.Owner() != cls.raw()) { |
- i++; |
- continue; |
- } |
- script = function.script(); |
- saved_url = script.url(); |
- if (!filter->ShouldOutputCoverageFor(lib, script, cls, function)) { |
- i++; |
- continue; |
- } |
- ComputeTokenPosToLineNumberMap(script, &pos_to_line); |
- JSONObject jsobj(&jsarr); |
- jsobj.AddProperty("source", saved_url.ToCString()); |
- jsobj.AddProperty("script", script); |
- JSONArray hits_or_sites(&jsobj, as_call_sites ? "callSites" : "hits"); |
- |
- // We stay within this loop while we are seeing functions from the same |
- // source URI. |
- while (i < closures.Length()) { |
- function ^= closures.At(i); |
- script = function.script(); |
- url = script.url(); |
- if (!url.Equals(saved_url)) { |
- pos_to_line.Clear(); |
- break; |
- } |
- CompileAndAdd(function, hits_or_sites, pos_to_line, as_call_sites); |
- i++; |
- } |
- } |
-} |
- |
- |
-void CodeCoverage::Write(Thread* thread) { |
- if (!FLAG_support_coverage) { |
- return; |
- } |
- if (FLAG_coverage_dir == NULL) { |
- return; |
- } |
- |
- Dart_FileOpenCallback file_open = Dart::file_open_callback(); |
- Dart_FileWriteCallback file_write = Dart::file_write_callback(); |
- Dart_FileCloseCallback file_close = Dart::file_close_callback(); |
- if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { |
- return; |
- } |
- |
- JSONStream stream; |
- PrintJSON(thread, &stream, NULL, false); |
- |
- intptr_t pid = OS::ProcessId(); |
- char* filename = OS::SCreate(thread->zone(), |
- "%s/dart-cov-%" Pd "-%" Pd64 ".json", |
- FLAG_coverage_dir, pid, thread->isolate()->main_port()); |
- void* file = (*file_open)(filename, true); |
- if (file == NULL) { |
- OS::Print("Failed to write coverage file: %s\n", filename); |
- return; |
- } |
- (*file_write)(stream.buffer()->buf(), stream.buffer()->length(), file); |
- (*file_close)(file); |
-} |
- |
- |
-void CodeCoverage::PrintJSON(Thread* thread, |
- JSONStream* stream, |
- CoverageFilter* filter, |
- bool as_call_sites) { |
- if (!FLAG_support_coverage) { |
- return; |
- } |
- CoverageFilterAll default_filter; |
- if (filter == NULL) { |
- filter = &default_filter; |
- } |
- const GrowableObjectArray& libs = GrowableObjectArray::Handle( |
- thread->zone(), |
- thread->isolate()->object_store()->libraries()); |
- Library& lib = Library::Handle(); |
- Class& cls = Class::Handle(); |
- JSONObject coverage(stream); |
- coverage.AddProperty("type", "CodeCoverage"); |
- { |
- JSONArray jsarr(&coverage, "coverage"); |
- for (int i = 0; i < libs.Length(); i++) { |
- lib ^= libs.At(i); |
- ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
- while (it.HasNext()) { |
- cls = it.GetNextClass(); |
- ASSERT(!cls.IsNull()); |
- PrintClass(lib, cls, jsarr, filter, as_call_sites); |
- } |
- } |
- } |
-} |
- |
- |
-} // namespace dart |