Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/src/vm/CodeCoverage.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: set ts=8 sts=4 et sw=4 tw=99:
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef vm_CodeCoverage_h
8
#define vm_CodeCoverage_h
9
10
#include "mozilla/Vector.h"
11
12
#include "ds/LifoAlloc.h"
13
14
#include "js/HashTable.h"
15
#include "js/TypeDecls.h"
16
#include "js/Utility.h"
17
18
#include "vm/Printer.h"
19
20
namespace js {
21
22
class ScriptSourceObject;
23
24
namespace coverage {
25
26
class LCovSource
27
{
28
  public:
29
    LCovSource(LifoAlloc* alloc, JS::UniqueChars name);
30
    LCovSource(LCovSource&& src);
31
0
    ~LCovSource() = default;
32
33
    // Whether the given script name matches this LCovSource.
34
0
    bool match(const char* name) const {
35
0
        return strcmp(name_.get(), name) == 0;
36
0
    }
37
38
    // Whether the current source is complete and if it can be flushed.
39
0
    bool isComplete() const {
40
0
        return hasTopLevelScript_;
41
0
    }
42
43
    // Iterate over the bytecode and collect the lcov output based on the
44
    // ScriptCounts counters.
45
    bool writeScript(JSScript* script);
46
47
    // Write the Lcov output in a buffer, such as the one associated with
48
    // the runtime code coverage trace file.
49
    void exportInto(GenericPrinter& out) const;
50
51
  private:
52
    // Write the script name in out.
53
    bool writeScriptName(LSprinter& out, JSScript* script);
54
55
  private:
56
    // Name of the source file.
57
    JS::UniqueChars name_;
58
59
    // LifoAlloc strings which hold the filename of each function as
60
    // well as the number of hits for each function.
61
    LSprinter outFN_;
62
    LSprinter outFNDA_;
63
    size_t numFunctionsFound_;
64
    size_t numFunctionsHit_;
65
66
    // LifoAlloc string which hold branches statistics.
67
    LSprinter outBRDA_;
68
    size_t numBranchesFound_;
69
    size_t numBranchesHit_;
70
71
    // Holds lines statistics. When processing a line hit count, the hit count
72
    // is added to any hit count already in the hash map so that we handle
73
    // lines that belong to more than one JSScript or function in the same
74
    // source file.
75
    HashMap<size_t, uint64_t, DefaultHasher<size_t>, SystemAllocPolicy> linesHit_;
76
    size_t numLinesInstrumented_;
77
    size_t numLinesHit_;
78
    size_t maxLineHit_;
79
80
    // Status flags.
81
    bool hasTopLevelScript_ : 1;
82
};
83
84
class LCovRealm
85
{
86
  public:
87
    LCovRealm();
88
    ~LCovRealm();
89
90
    // Collect code coverage information for the given source.
91
    void collectCodeCoverageInfo(JS::Realm* realm, JSScript* topLevel, const char* name);
92
93
    // Write the Lcov output in a buffer, such as the one associated with
94
    // the runtime code coverage trace file.
95
    void exportInto(GenericPrinter& out, bool* isEmpty) const;
96
97
  private:
98
    // Write the script name in out.
99
    bool writeRealmName(JS::Realm* realm);
100
101
    // Return the LCovSource entry which matches the given ScriptSourceObject.
102
    LCovSource* lookupOrAdd(JS::Realm* realm, const char* name);
103
104
  private:
105
    typedef mozilla::Vector<LCovSource, 16, LifoAllocPolicy<Fallible>> LCovSourceVector;
106
107
    // LifoAlloc backend for all temporary allocations needed to stash the
108
    // strings to be written in the file.
109
    LifoAlloc alloc_;
110
111
    // LifoAlloc string which hold the name of the realm.
112
    LSprinter outTN_;
113
114
    // Vector of all sources which are used in this realm.
115
    LCovSourceVector* sources_;
116
};
117
118
class LCovRuntime
119
{
120
  public:
121
    LCovRuntime();
122
    ~LCovRuntime();
123
124
    // If the environment variable JS_CODE_COVERAGE_OUTPUT_DIR is set to a
125
    // directory, create a file inside this directory which uses the process
126
    // ID, the thread ID and a timestamp to ensure the uniqueness of the
127
    // file.
128
    //
129
    // At the end of the execution, this file should contains the LCOV output of
130
    // all the scripts executed in the current JSRuntime.
131
    void init();
132
133
    // Check if we should collect code coverage information.
134
1.62k
    bool isEnabled() const { return out_.isInitialized(); }
135
136
    // Write the aggregated result of the code coverage of a realm
137
    // into a file.
138
    void writeLCovResult(LCovRealm& realm);
139
140
  private:
141
    // When a process forks, the file will remain open, but 2 processes will
142
    // have the same file. To avoid conflicting writes, we open a new file for
143
    // the child process.
144
    void maybeReopenAfterFork();
145
146
    // Fill an array with the name of the file. Return false if we are unable to
147
    // serialize the filename in this array.
148
    bool fillWithFilename(char *name, size_t length);
149
150
    // Finish the current opened file, and remove if it does not have any
151
    // content.
152
    void finishFile();
153
154
  private:
155
    // Output file which is created if code coverage is enabled.
156
    Fprinter out_;
157
158
    // The process' PID is used to watch for fork. When the process fork,
159
    // we want to close the current file and open a new one.
160
    uint32_t pid_;
161
162
    // Flag used to report if the generated file is empty or not. If it is empty
163
    // when the runtime is destroyed, then the file would be removed as an empty
164
    // file is not a valid LCov file.
165
    bool isEmpty_;
166
};
167
168
} // namespace coverage
169
} // namespace js
170
171
#endif // vm_Printer_h
172