tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CodeCoverage.h (5274B)


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