| 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
|
|
|