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