Bug 1204554 part 3.2 - Collect the source files before any script, as they are swept first. r=terrence
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 01 Oct 2015 12:41:40 +0200
changeset 265603 c403924d9a60f483259be32ed7f33550adb2290f
parent 265602 35247eec9d6151731b08fb9f5919bbe6758a012b
child 265604 c9575abbf46ec4c672868499ad7f9a058ca3bb76
push id15472
push usercbook@mozilla.com
push dateFri, 02 Oct 2015 11:51:34 +0000
treeherderfx-team@2c33ef6b27e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1204554
milestone44.0a1
Bug 1204554 part 3.2 - Collect the source files before any script, as they are swept first. r=terrence
js/src/jsopcode.cpp
js/src/jsscript.cpp
js/src/vm/CodeCoverage.cpp
js/src/vm/CodeCoverage.h
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -2009,17 +2009,18 @@ GenerateLcovInfo(JSContext* cx, JSCompar
 
                 // Queue the script in the list of script associated to the
                 // current source.
                 if (!queue.append(fun.getOrCreateScript(cx)))
                     return false;
             }
         } while (!queue.empty());
 
-        compCover.collectCodeCoverageInfo(comp, topScript);
+        compCover.collectSourceFile(comp, &topScript->scriptSourceUnwrap());
+        compCover.collectCodeCoverageInfo(comp, topScript->sourceObject(), topScript);
     }
 
     compCover.exportInto(out);
     if (out.hadOutOfMemory())
         return false;
     return true;
 }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1502,16 +1502,22 @@ ScriptSourceObject::trace(JSTracer* trc,
         }
     }
 }
 
 void
 ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj)
 {
     ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
+
+    // If code coverage is enabled, record the filename associated with this
+    // source object.
+    if (fop->runtime()->lcovOutput.isEnabled())
+        sso->compartment()->lcovOutput.collectSourceFile(sso->compartment(), sso);
+
     sso->source()->decref();
     sso->setReservedSlot(SOURCE_SLOT, PrivateValue(nullptr));
 }
 
 const Class ScriptSourceObject::class_ = {
     "ScriptSource",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
@@ -2934,17 +2940,17 @@ JSScript::finalize(FreeOp* fop)
     // NOTE: this JSScript may be partially initialized at this point.  E.g. we
     // may have created it and partially initialized it with
     // JSScript::Create(), but not yet finished initializing it with
     // fullyInitFromEmitter() or fullyInitTrivial().
 
     // Collect code coverage information for this script and all its inner
     // scripts, and store the aggregated information on the compartment.
     if (isTopLevel() && fop->runtime()->lcovOutput.isEnabled())
-        compartment()->lcovOutput.collectCodeCoverageInfo(compartment(), this);
+        compartment()->lcovOutput.collectCodeCoverageInfo(compartment(), sourceObject(), this);
 
     fop->runtime()->spsProfiler.onScriptFinalized(this);
 
     if (types_)
         types_->destroy();
 
     jit::DestroyJitScripts(fop, this);
 
--- a/js/src/vm/CodeCoverage.cpp
+++ b/js/src/vm/CodeCoverage.cpp
@@ -57,18 +57,19 @@
 //     LH:<sum of lines hits>
 //   }
 //
 // [1] http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php
 //
 namespace js {
 namespace coverage {
 
-LCovSource::LCovSource(LifoAlloc* alloc)
-  : outSF_(alloc),
+LCovSource::LCovSource(LifoAlloc* alloc, JSObject* sso)
+  : source_(sso),
+    outSF_(alloc),
     outFN_(alloc),
     outFNDA_(alloc),
     numFunctionsFound_(0),
     numFunctionsHit_(0),
     outBRDA_(alloc),
     numBranchesFound_(0),
     numBranchesHit_(0),
     outDA_(alloc),
@@ -98,19 +99,16 @@ LCovSource::exportInto(GenericPrinter& o
     out.put("end_of_record\n");
 }
 
 bool
 LCovSource::writeTopLevelScript(JSScript* script)
 {
     MOZ_ASSERT(script->isTopLevel());
 
-    if (!writeSourceFilename(outSF_, script))
-        return false;
-
     Vector<JSScript*, 8, SystemAllocPolicy> queue;
     if (!queue.append(script))
         return false;
 
     do {
         script = queue.popCopy();
 
         // Save the lcov output of the current script.
@@ -146,20 +144,20 @@ LCovSource::writeTopLevelScript(JSScript
 
     return !(outFN_.hadOutOfMemory() ||
              outFNDA_.hadOutOfMemory() ||
              outBRDA_.hadOutOfMemory() ||
              outDA_.hadOutOfMemory());
 }
 
 bool
-LCovSource::writeSourceFilename(LSprinter& out, JSScript* script)
+LCovSource::writeSourceFilename(ScriptSourceObject* sso)
 {
-    out.printf("SF:%s\n", script->filename());
-    return !out.hadOutOfMemory();
+    outSF_.printf("SF:%s\n", sso->source()->filename());
+    return !outSF_.hadOutOfMemory();
 }
 
 bool
 LCovSource::writeScriptName(LSprinter& out, JSScript* script)
 {
     JSFunction* fun = script->functionNonDelazifying();
     if (fun && fun->displayAtom())
         return EscapedStringPrinter(out, fun->displayAtom(), 0);
@@ -283,17 +281,41 @@ LCovCompartment::LCovCompartment()
   : alloc_(4096),
     outTN_(&alloc_),
     sources_(nullptr)
 {
     MOZ_ASSERT(alloc_.isEmpty());
 }
 
 void
-LCovCompartment::collectCodeCoverageInfo(JSCompartment* comp, JSScript* topLevel)
+LCovCompartment::collectCodeCoverageInfo(JSCompartment* comp, JSObject* sso,
+                                         JSScript* topLevel)
+{
+    // Skip any operation if we already some out-of memory issues.
+    if (outTN_.hadOutOfMemory())
+        return;
+
+    // We expect to visit the source before visiting any of its scripts.
+    if (!sources_)
+        return;
+
+    // Lookup if there is already one entry.
+    LCovSource* source = lookup(sso);
+    if (!source)
+        return;
+
+    // Write code coverage data into the allocated LCovSource.
+    if (!source->writeTopLevelScript(topLevel)) {
+        outTN_.reportOutOfMemory();
+        return;
+    }
+}
+
+void
+LCovCompartment::collectSourceFile(JSCompartment* comp, ScriptSourceObject* sso)
 {
     // Skip any operation if we already some out-of memory issues.
     if (outTN_.hadOutOfMemory())
         return;
 
     // On the first call, write the compartment name, and allocate a LCovSource
     // vector in the LifoAlloc.
     if (!sources_) {
@@ -305,28 +327,43 @@ LCovCompartment::collectCodeCoverageInfo
             outTN_.reportOutOfMemory();
             return;
         }
 
         sources_ = new(raw) LCovSourceVector(alloc_);
     }
 
     // Allocate a new LCovSource for the current top-level.
-    if (!sources_->append(Move(LCovSource(&alloc_)))) {
+    if (!sources_->append(Move(LCovSource(&alloc_, sso)))) {
         outTN_.reportOutOfMemory();
         return;
     }
 
     // Write code coverage data into the allocated LCovSource.
-    if (!sources_->back().writeTopLevelScript(topLevel)) {
+    if (!sources_->back().writeSourceFilename(sso)) {
         outTN_.reportOutOfMemory();
         return;
     }
 }
 
+LCovSource*
+LCovCompartment::lookup(JSObject* sso)
+{
+    if (!sources_)
+        return nullptr;
+
+    // Find the first matching source.
+    for (LCovSource& source : *sources_) {
+        if (source.match(sso))
+            return &source;
+    }
+
+    return nullptr;
+}
+
 void
 LCovCompartment::exportInto(GenericPrinter& out) const
 {
     if (!sources_ || outTN_.hadOutOfMemory())
         return;
 
     outTN_.exportInto(out);
     for (const LCovSource& sc : *sources_)
--- a/js/src/vm/CodeCoverage.h
+++ b/js/src/vm/CodeCoverage.h
@@ -10,51 +10,63 @@
 #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);
+    explicit LCovSource(LifoAlloc* alloc, JSObject* sso);
+
+    // Wether the given script source object matches this LCovSource.
+    bool match(JSObject* sso) {
+        return sso == source_;
+    }
 
     // Visit all JSScript in pre-order, and collect the lcov output based on
     // the ScriptCounts counters.
     //
     // In case of the where this function is called during the finalization,
     // this assumes that all of the children scripts are still alive, and
     // not finalized yet.
     bool writeTopLevelScript(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 writeSourceFilename(LSprinter& out, JSScript* script);
-
-    // Write the script name in out.
     bool writeScriptName(LSprinter& out, JSScript* script);
 
     // Iterate over the bytecode and collect the lcov output based on the
     // ScriptCounts counters.
     bool writeScript(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_;
@@ -71,27 +83,33 @@ class LCovSource
     size_t numLinesHit_;
 };
 
 class LCovCompartment
 {
   public:
     LCovCompartment();
 
-    // Collect code coverage information
-    void collectCodeCoverageInfo(JSCompartment* comp, JSScript* topLevel);
+    // 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) const;
 
   private:
     // Write the script name in out.
     bool writeCompartmentName(JSCompartment* comp);
 
+    // Return the LCovSource entry which matches the given ScriptSourceObject.
+    LCovSource* lookup(JSObject* sso);
+
   private:
     typedef 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.