summaryrefslogtreecommitdiffstats
path: root/js/src/vm/CodeCoverage.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/CodeCoverage.h')
-rw-r--r--js/src/vm/CodeCoverage.h177
1 files changed, 177 insertions, 0 deletions
diff --git a/js/src/vm/CodeCoverage.h b/js/src/vm/CodeCoverage.h
new file mode 100644
index 000000000..8ab6272d1
--- /dev/null
+++ b/js/src/vm/CodeCoverage.h
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_CodeCoverage_h
+#define vm_CodeCoverage_h
+
+#include "mozilla/Vector.h"
+
+#include "ds/LifoAlloc.h"
+
+#include "vm/Printer.h"
+
+struct JSCompartment;
+class JSScript;
+class JSObject;
+
+namespace js {
+
+class ScriptSourceObject;
+
+namespace coverage {
+
+class LCovCompartment;
+
+class LCovSource
+{
+ public:
+ explicit LCovSource(LifoAlloc* alloc, JSObject* sso);
+
+ // Whether the given script source object matches this LCovSource.
+ bool match(JSObject* sso) const {
+ return sso == source_;
+ }
+
+ // Whether the current source is complete and if it can be flushed.
+ bool isComplete() const {
+ return hasFilename_ && hasTopLevelScript_;
+ }
+
+ // Iterate over the bytecode and collect the lcov output based on the
+ // ScriptCounts counters.
+ bool writeScript(JSScript* script);
+
+ // Write the Lcov output in a buffer, such as the one associated with
+ // the runtime code coverage trace file.
+ void exportInto(GenericPrinter& out) const;
+
+ // Write the script name in out.
+ bool writeSourceFilename(ScriptSourceObject* sso);
+
+ private:
+ // Write the script name in out.
+ bool writeScriptName(LSprinter& out, JSScript* script);
+
+ private:
+ // Weak pointer of the Script Source Object used by the current source.
+ JSObject *source_;
+
+ // LifoAlloc string which hold the filename of the source.
+ LSprinter outSF_;
+
+ // LifoAlloc strings which hold the filename of each function as
+ // well as the number of hits for each function.
+ LSprinter outFN_;
+ LSprinter outFNDA_;
+ size_t numFunctionsFound_;
+ size_t numFunctionsHit_;
+
+ // LifoAlloc string which hold branches statistics.
+ LSprinter outBRDA_;
+ size_t numBranchesFound_;
+ size_t numBranchesHit_;
+
+ // LifoAlloc string which hold lines statistics.
+ LSprinter outDA_;
+ size_t numLinesInstrumented_;
+ size_t numLinesHit_;
+
+ // Status flags.
+ bool hasFilename_ : 1;
+ bool hasTopLevelScript_ : 1;
+};
+
+class LCovCompartment
+{
+ public:
+ LCovCompartment();
+
+ // Collect code coverage information for the given source.
+ void collectCodeCoverageInfo(JSCompartment* comp, JSObject* sso, JSScript* topLevel);
+
+ // Create an ebtry for the current ScriptSourceObject.
+ void collectSourceFile(JSCompartment* comp, ScriptSourceObject* sso);
+
+ // Write the Lcov output in a buffer, such as the one associated with
+ // the runtime code coverage trace file.
+ void exportInto(GenericPrinter& out, bool* isEmpty) const;
+
+ private:
+ // Write the script name in out.
+ bool writeCompartmentName(JSCompartment* comp);
+
+ // Return the LCovSource entry which matches the given ScriptSourceObject.
+ LCovSource* lookupOrAdd(JSCompartment* comp, JSObject* sso);
+
+ private:
+ typedef mozilla::Vector<LCovSource, 16, LifoAllocPolicy<Fallible>> LCovSourceVector;
+
+ // LifoAlloc backend for all temporary allocations needed to stash the
+ // strings to be written in the file.
+ LifoAlloc alloc_;
+
+ // LifoAlloc string which hold the name of the compartment.
+ LSprinter outTN_;
+
+ // Vector of all sources which are used in this compartment.
+ LCovSourceVector* sources_;
+};
+
+class LCovRuntime
+{
+ public:
+ LCovRuntime();
+ ~LCovRuntime();
+
+ // If the environment variable JS_CODE_COVERAGE_OUTPUT_DIR is set to a
+ // directory, create a file inside this directory which uses the process
+ // ID, the thread ID and a timestamp to ensure the uniqueness of the
+ // file.
+ //
+ // At the end of the execution, this file should contains the LCOV output of
+ // all the scripts executed in the current JSRuntime.
+ void init();
+
+ // Check if we should collect code coverage information.
+ bool isEnabled() const { return out_.isInitialized(); }
+
+ // Write the aggregated result of the code coverage of a compartment
+ // into a file.
+ void writeLCovResult(LCovCompartment& comp);
+
+ private:
+ // When a process forks, the file will remain open, but 2 processes will
+ // have the same file. To avoid conflicting writes, we open a new file for
+ // the child process.
+ void maybeReopenAfterFork();
+
+ // Fill an array with the name of the file. Return false if we are unable to
+ // serialize the filename in this array.
+ bool fillWithFilename(char *name, size_t length);
+
+ // Finish the current opened file, and remove if it does not have any
+ // content.
+ void finishFile();
+
+ private:
+ // Output file which is created if code coverage is enabled.
+ Fprinter out_;
+
+ // The process' PID is used to watch for fork. When the process fork,
+ // we want to close the current file and open a new one.
+ size_t pid_;
+
+ // Flag used to report if the generated file is empty or not. If it is empty
+ // when the runtime is destroyed, then the file would be removed as an empty
+ // file is not a valid LCov file.
+ bool isEmpty_;
+};
+
+} // namespace coverage
+} // namespace js
+
+#endif // vm_Printer_h
+