Line data Source code
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 "vm/Printer.h"
15 :
16 : struct JSCompartment;
17 : class JSScript;
18 : class JSObject;
19 :
20 : namespace js {
21 :
22 : class ScriptSourceObject;
23 :
24 : namespace coverage {
25 :
26 : class LCovCompartment;
27 :
28 : class LCovSource
29 : {
30 : public:
31 : LCovSource(LifoAlloc* alloc, const char* name);
32 : LCovSource(LCovSource&& src);
33 : ~LCovSource();
34 :
35 : // Whether the given script name matches this LCovSource.
36 0 : bool match(const char* name) const {
37 0 : return strcmp(name_, name) == 0;
38 : }
39 :
40 : // Whether the current source is complete and if it can be flushed.
41 0 : bool isComplete() const {
42 0 : return hasTopLevelScript_;
43 : }
44 :
45 : // Iterate over the bytecode and collect the lcov output based on the
46 : // ScriptCounts counters.
47 : bool writeScript(JSScript* script);
48 :
49 : // Write the Lcov output in a buffer, such as the one associated with
50 : // the runtime code coverage trace file.
51 : void exportInto(GenericPrinter& out) const;
52 :
53 : private:
54 : // Write the script name in out.
55 : bool writeScriptName(LSprinter& out, JSScript* script);
56 :
57 : private:
58 : // Name of the source file.
59 : const char* name_;
60 :
61 : // LifoAlloc strings which hold the filename of each function as
62 : // well as the number of hits for each function.
63 : LSprinter outFN_;
64 : LSprinter outFNDA_;
65 : size_t numFunctionsFound_;
66 : size_t numFunctionsHit_;
67 :
68 : // LifoAlloc string which hold branches statistics.
69 : LSprinter outBRDA_;
70 : size_t numBranchesFound_;
71 : size_t numBranchesHit_;
72 :
73 : // LifoAlloc string which hold lines statistics.
74 : LSprinter outDA_;
75 : size_t numLinesInstrumented_;
76 : size_t numLinesHit_;
77 :
78 : // Status flags.
79 : bool hasTopLevelScript_ : 1;
80 : };
81 :
82 0 : class LCovCompartment
83 : {
84 : public:
85 : LCovCompartment();
86 :
87 : // Collect code coverage information for the given source.
88 : void collectCodeCoverageInfo(JSCompartment* comp, JSScript* topLevel, const char* name);
89 :
90 : // Write the Lcov output in a buffer, such as the one associated with
91 : // the runtime code coverage trace file.
92 : void exportInto(GenericPrinter& out, bool* isEmpty) const;
93 :
94 : private:
95 : // Write the script name in out.
96 : bool writeCompartmentName(JSCompartment* comp);
97 :
98 : // Return the LCovSource entry which matches the given ScriptSourceObject.
99 : LCovSource* lookupOrAdd(JSCompartment* comp, const char* name);
100 :
101 : private:
102 : typedef mozilla::Vector<LCovSource, 16, LifoAllocPolicy<Fallible>> LCovSourceVector;
103 :
104 : // LifoAlloc backend for all temporary allocations needed to stash the
105 : // strings to be written in the file.
106 : LifoAlloc alloc_;
107 :
108 : // LifoAlloc string which hold the name of the compartment.
109 : LSprinter outTN_;
110 :
111 : // Vector of all sources which are used in this compartment.
112 : LCovSourceVector* sources_;
113 : };
114 :
115 : class LCovRuntime
116 : {
117 : public:
118 : LCovRuntime();
119 : ~LCovRuntime();
120 :
121 : // If the environment variable JS_CODE_COVERAGE_OUTPUT_DIR is set to a
122 : // directory, create a file inside this directory which uses the process
123 : // ID, the thread ID and a timestamp to ensure the uniqueness of the
124 : // file.
125 : //
126 : // At the end of the execution, this file should contains the LCOV output of
127 : // all the scripts executed in the current JSRuntime.
128 : void init();
129 :
130 : // Check if we should collect code coverage information.
131 36906 : bool isEnabled() const { return out_.isInitialized(); }
132 :
133 : // Write the aggregated result of the code coverage of a compartment
134 : // into a file.
135 : void writeLCovResult(LCovCompartment& comp);
136 :
137 : private:
138 : // When a process forks, the file will remain open, but 2 processes will
139 : // have the same file. To avoid conflicting writes, we open a new file for
140 : // the child process.
141 : void maybeReopenAfterFork();
142 :
143 : // Fill an array with the name of the file. Return false if we are unable to
144 : // serialize the filename in this array.
145 : bool fillWithFilename(char *name, size_t length);
146 :
147 : // Finish the current opened file, and remove if it does not have any
148 : // content.
149 : void finishFile();
150 :
151 : private:
152 : // Output file which is created if code coverage is enabled.
153 : Fprinter out_;
154 :
155 : // The process' PID is used to watch for fork. When the process fork,
156 : // we want to close the current file and open a new one.
157 : uint32_t pid_;
158 :
159 : // Flag used to report if the generated file is empty or not. If it is empty
160 : // when the runtime is destroyed, then the file would be removed as an empty
161 : // file is not a valid LCov file.
162 : bool isEmpty_;
163 : };
164 :
165 : } // namespace coverage
166 : } // namespace js
167 :
168 : #endif // vm_Printer_h
169 :
|