Bug 1263645 - Distinguish code coverage usages, and disable it by default in the interpreter. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 19 May 2016 13:28:35 +0000
changeset 298150 8550398c99fb9529416a034f6310fd2c5d0911d4
parent 298149 d30839422ea9e4afccf4f3f27a417a77c018564c
child 298151 ed89ff77c920a87da224befbe848b8cd6497fb46
push id30273
push userkwierso@gmail.com
push dateFri, 20 May 2016 21:08:12 +0000
treeherdermozilla-central@c403ac05b8f4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1263645
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1263645 - Distinguish code coverage usages, and disable it by default in the interpreter. r=jandem
js/src/jit/BaselineCompiler.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfun.cpp
js/src/jsscript.h
js/src/vm/Interpreter.cpp
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -91,19 +91,19 @@ BaselineCompiler::compile()
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
     TraceLoggerEvent scriptEvent(logger, TraceLogger_AnnotateScripts, script);
     AutoTraceLog logScript(logger, scriptEvent);
     AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
 
     if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
         return Method_Error;
 
-    // When a Debugger set the collectCoverageInfo flag, we recompile baseline
-    // scripts without entering the interpreter again. We have to create the
-    // ScriptCounts if they do not exist.
+    // When code coverage is only enabled for optimizations, or when a Debugger
+    // set the collectCoverageInfo flag, we have to create the ScriptCounts if
+    // they do not exist.
     if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) {
         if (!script->initScriptCounts(cx))
             return Method_Error;
     }
 
     // Pin analysis info during compilation.
     AutoEnterAnalysis autoEnterAnalysis(cx);
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -1106,18 +1106,30 @@ JSCompartment::updateDebuggerObservesCov
         return;
 
     clearScriptCounts();
 }
 
 bool
 JSCompartment::collectCoverage() const
 {
-    return !JitOptions.disablePgo ||
-           debuggerObservesCoverage() ||
+    return collectCoverageForPGO() ||
+           collectCoverageForDebug();
+}
+
+bool
+JSCompartment::collectCoverageForPGO() const
+{
+    return !JitOptions.disablePgo;
+}
+
+bool
+JSCompartment::collectCoverageForDebug() const
+{
+    return debuggerObservesCoverage() ||
            runtimeFromAnyThread()->profilingScripts ||
            runtimeFromAnyThread()->lcovOutput.isEnabled();
 }
 
 void
 JSCompartment::clearScriptCounts()
 {
     if (!scriptCountsMap)
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -702,16 +702,18 @@ struct JSCompartment
         static const unsigned Mask = DebuggerObservesCoverage;
         return (debugModeBits & Mask) == Mask;
     }
     void updateDebuggerObservesCoverage();
 
     // The code coverage can be enabled either for each compartment, with the
     // Debugger API, or for the entire runtime.
     bool collectCoverage() const;
+    bool collectCoverageForDebug() const;
+    bool collectCoverageForPGO() const;
     void clearScriptCounts();
 
     bool needsDelazificationForDebugger() const {
         return debugModeBits & DebuggerNeedsDelazification;
     }
 
     /*
      * Schedule the compartment to be delazified. Called from
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1674,16 +1674,21 @@ JSFunction::maybeRelazify(JSRuntime* rt)
     if (comp->hasBeenEntered() && !rt->allowRelazificationForTesting)
         return;
 
     // Don't relazify if the compartment is being debugged or is the
     // self-hosting compartment.
     if (comp->isDebuggee() || comp->isSelfHosting)
         return;
 
+    // Don't relazify if the compartment and/or runtime is instrumented to
+    // collect code coverage for analysis.
+    if (comp->collectCoverageForDebug())
+        return;
+
     // Don't relazify functions with JIT code.
     if (!u.i.s.script_->isRelazifiable())
         return;
 
     // To delazify self-hosted builtins we need the name of the function
     // to clone. This name is stored in the first extended slot. Since
     // that slot is sometimes also used for other purposes, make sure it
     // contains a string.
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1609,17 +1609,17 @@ class JSScript : public js::gc::TenuredC
     }
     static size_t offsetOfBaselineOrIonSkipArgCheck() {
         return offsetof(JSScript, baselineOrIonSkipArgCheck);
     }
 
     bool isRelazifiable() const {
         return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
                !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() &&
-               !hasScriptCounts() && !doNotRelazify_;
+               !doNotRelazify_;
     }
     void setLazyScript(js::LazyScript* lazy) {
         lazyScript = lazy;
     }
     js::LazyScript* maybeLazyScript() {
         return lazyScript;
     }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1629,19 +1629,21 @@ Interpret(JSContext* cx, RunState& state
         ADVANCE_AND_DISPATCH(nlen);                                           \
     JS_END_MACRO
 
     /*
      * Initialize code coverage vectors.
      */
 #define INIT_COVERAGE()                                                       \
     JS_BEGIN_MACRO                                                            \
-        if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) { \
-            if (!script->initScriptCounts(cx))                                \
-                goto error;                                                   \
+        if (!script->hasScriptCounts()) {                                     \
+            if (cx->compartment()->collectCoverageForDebug()) {               \
+                if (!script->initScriptCounts(cx))                            \
+                    goto error;                                               \
+            }                                                                 \
         }                                                                     \
     JS_END_MACRO
 
     /*
      * Increment the code coverage counter associated with the given pc.
      */
 #define COUNT_COVERAGE_PC(PC)                                                 \
     JS_BEGIN_MACRO                                                            \
@@ -1747,20 +1749,19 @@ Interpret(JSContext* cx, RunState& state
 
 INTERPRETER_LOOP() {
 
 CASE(EnableInterruptsPseudoOpcode)
 {
     bool moreInterrupts = false;
     jsbytecode op = *REGS.pc;
 
-    if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) {
+    if (!script->hasScriptCounts() && cx->compartment()->collectCoverageForDebug()) {
         if (!script->initScriptCounts(cx))
             goto error;
-        moreInterrupts = true;
     }
 
     if (script->isDebuggee()) {
         if (script->stepModeEnabled()) {
             RootedValue rval(cx);
             JSTrapStatus status = JSTRAP_CONTINUE;
             status = Debugger::onSingleStep(cx, &rval);
             switch (status) {