Bug 1261826 part 10 - Only increment code coverage counters on jump targets. r=bhackett
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Tue, 17 May 2016 17:15:53 +0000
changeset 297698 2e29695fee8730d8dae52960dc98ff7ade38aacb
parent 297697 d3912b7cd8ea15d4bc426319c9a4e402738452f2
child 297699 92f26e681678e378c11c360fd419d65e24226d1b
push id76868
push usernpierron@mozilla.com
push dateTue, 17 May 2016 17:16:30 +0000
treeherdermozilla-inbound@2e29695fee87 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1261826
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 1261826 part 10 - Only increment code coverage counters on jump targets. r=bhackett
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/vm/Interpreter.cpp
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -822,27 +822,16 @@ BaselineCompiler::emitDebugTrap()
     PCMappingEntry& entry = pcMappingEntries_.back();
     MOZ_ASSERT((&offset)->offset() == entry.nativeOffset);
 #endif
 
     // Add an IC entry for the return offset -> pc mapping.
     return appendICEntry(ICEntry::Kind_DebugTrap, masm.currentOffset());
 }
 
-void
-BaselineCompiler::emitCoverage(jsbytecode* pc)
-{
-    PCCounts* counts = script->maybeGetPCCounts(pc);
-    if (!counts)
-        return;
-
-    uint64_t* counterAddr = &counts->numExec();
-    masm.inc64(AbsoluteAddress(counterAddr));
-}
-
 #ifdef JS_TRACE_LOGGING
 bool
 BaselineCompiler::emitTraceLoggerEnter()
 {
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
     AllocatableRegisterSet regs(RegisterSet::Volatile());
     Register loggerReg = regs.takeAnyGeneral();
     Register scriptReg = regs.takeAnyGeneral();
@@ -930,17 +919,16 @@ BaselineCompiler::emitProfilerExitFrame(
 MethodStatus
 BaselineCompiler::emitBody()
 {
     MOZ_ASSERT(pc == script->code());
 
     bool lastOpUnreachable = false;
     uint32_t emittedOps = 0;
     mozilla::DebugOnly<jsbytecode*> prevpc = pc;
-    bool compileCoverage = script->hasScriptCounts();
 
     while (true) {
         JSOp op = JSOp(*pc);
         JitSpew(JitSpew_BaselineOp, "Compiling op @ %d: %s",
                 int(script->pcToOffset(pc)), CodeName[op]);
 
         BytecodeInfo* info = analysis_.maybeInfo(pc);
 
@@ -985,20 +973,16 @@ BaselineCompiler::emitBody()
             ReportOutOfMemory(cx);
             return Method_Error;
         }
 
         // Emit traps for breakpoints and step mode.
         if (compileDebugInstrumentation_ && !emitDebugTrap())
             return Method_Error;
 
-        // Emit code coverage code, to fill the same data as the interpreter.
-        if (compileCoverage)
-            emitCoverage(pc);
-
         switch (op) {
           default:
             JitSpew(JitSpew_BaselineAbort, "Unhandled op: %s", CodeName[op]);
             return Method_CantCompile;
 
 #define EMIT_OP(OP)                            \
           case OP:                             \
             if (!this->emit_##OP())            \
@@ -4334,10 +4318,15 @@ BaselineCompiler::emit_JSOP_DEBUGCHECKSE
 #endif
     return true;
 
 }
 
 bool
 BaselineCompiler::emit_JSOP_JUMPTARGET()
 {
+    if (!script->hasScriptCounts())
+        return true;
+    PCCounts* counts = script->maybeGetPCCounts(pc);
+    uint64_t* counterAddr = &counts->numExec();
+    masm.inc64(AbsoluteAddress(counterAddr));
     return true;
 }
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -287,17 +287,16 @@ class BaselineCompiler : public Baseline
 
     MOZ_MUST_USE bool emitStackCheck(bool earlyCheck=false);
     MOZ_MUST_USE bool emitInterruptCheck();
     MOZ_MUST_USE bool emitWarmUpCounterIncrement(bool allowOsr=true);
     MOZ_MUST_USE bool emitArgumentTypeChecks();
     void emitIsDebuggeeCheck();
     MOZ_MUST_USE bool emitDebugPrologue();
     MOZ_MUST_USE bool emitDebugTrap();
-    void emitCoverage(jsbytecode* pc);
     MOZ_MUST_USE bool emitTraceLoggerEnter();
     MOZ_MUST_USE bool emitTraceLoggerExit();
 
     void emitProfilerEnterFrame();
     void emitProfilerExitFrame();
 
     MOZ_MUST_USE bool initScopeChain();
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1624,31 +1624,65 @@ Interpret(JSContext* cx, RunState& state
 #define BRANCH(n)                                                             \
     JS_BEGIN_MACRO                                                            \
         int32_t nlen = (n);                                                   \
         if (nlen <= 0)                                                        \
             CHECK_BRANCH();                                                   \
         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;                                                   \
+        }                                                                     \
+    JS_END_MACRO
+
+    /*
+     * Increment the code coverage counter associated with the given pc.
+     */
+#define COUNT_COVERAGE_PC(PC)                                                 \
+    JS_BEGIN_MACRO                                                            \
+        if (script->hasScriptCounts()) {                                      \
+            PCCounts* counts = script->maybeGetPCCounts(PC);                  \
+            MOZ_ASSERT(counts);                                               \
+            counts->numExec()++;                                              \
+        }                                                                     \
+    JS_END_MACRO
+
+#define COUNT_COVERAGE_MAIN()                                                 \
+    JS_BEGIN_MACRO                                                            \
+        jsbytecode* main = script->main();                                    \
+        if (!BytecodeIsJumpTarget(JSOp(*main)))                               \
+            COUNT_COVERAGE_PC(main);                                          \
+    JS_END_MACRO
+
+#define COUNT_COVERAGE()                                                      \
+    JS_BEGIN_MACRO                                                            \
+        MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc)));                     \
+        COUNT_COVERAGE_PC(REGS.pc);                                           \
+    JS_END_MACRO
+
 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
     ((dbl) = script->getConst(GET_UINT32_INDEX(REGS.pc + (PCOFF))).toDouble())
 
 #define SET_SCRIPT(s)                                                         \
     JS_BEGIN_MACRO                                                            \
         script = (s);                                                         \
         if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts()) \
             activation.enableInterruptsUnconditionally();                     \
     JS_END_MACRO
 
 #define SANITY_CHECKS()                                                       \
     JS_BEGIN_MACRO                                                            \
         js::gc::MaybeVerifyBarriers(cx);                                      \
-        MOZ_ASSERT_IF(script->hasScriptCounts(),                              \
-                      activation.opMask() == EnableInterruptsPseudoOpcode);   \
     JS_END_MACRO
 
     gc::MaybeVerifyBarriers(cx, true);
     MOZ_ASSERT(!cx->zone()->types.activeAnalysis);
 
     InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
     if (!entryFrame)
         return false;
@@ -1699,18 +1733,19 @@ Interpret(JSContext* cx, RunState& state
         goto successful_return_continuation;
       case JSTRAP_THROW:
       case JSTRAP_ERROR:
         goto error;
       default:
         MOZ_CRASH("bad Debugger::onEnterFrame status");
     }
 
-    if (cx->compartment()->collectCoverage())
-        activation.enableInterruptsUnconditionally();
+    // Increment the coverage for the main entry point.
+    INIT_COVERAGE();
+    COUNT_COVERAGE_MAIN();
 
     // Enter the interpreter loop starting at the current pc.
     ADVANCE_AND_DISPATCH(0);
 
 INTERPRETER_LOOP() {
 
 CASE(EnableInterruptsPseudoOpcode)
 {
@@ -1718,23 +1753,16 @@ CASE(EnableInterruptsPseudoOpcode)
     jsbytecode op = *REGS.pc;
 
     if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) {
         if (!script->initScriptCounts(cx))
             goto error;
         moreInterrupts = true;
     }
 
-    if (script->hasScriptCounts()) {
-        PCCounts* counts = script->maybeGetPCCounts(REGS.pc);
-        if (counts)
-            counts->numExec()++;
-        moreInterrupts = true;
-    }
-
     if (script->isDebuggee()) {
         if (script->stepModeEnabled()) {
             RootedValue rval(cx);
             JSTrapStatus status = JSTRAP_CONTINUE;
             status = Debugger::onSingleStep(cx, &rval);
             switch (status) {
               case JSTRAP_ERROR:
                 goto error;
@@ -1805,30 +1833,35 @@ CASE(JSOP_UNUSED210)
 CASE(JSOP_UNUSED211)
 CASE(JSOP_UNUSED212)
 CASE(JSOP_UNUSED219)
 CASE(JSOP_UNUSED220)
 CASE(JSOP_UNUSED221)
 CASE(JSOP_UNUSED222)
 CASE(JSOP_UNUSED223)
 CASE(JSOP_CONDSWITCH)
-CASE(JSOP_TRY)
-CASE(JSOP_JUMPTARGET)
 {
     MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
     ADVANCE_AND_DISPATCH(1);
 }
 
+CASE(JSOP_TRY)
+CASE(JSOP_JUMPTARGET)
 CASE(JSOP_LOOPHEAD)
-END_CASE(JSOP_LOOPHEAD)
+{
+    MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
+    COUNT_COVERAGE();
+    ADVANCE_AND_DISPATCH(1);
+}
 
 CASE(JSOP_LABEL)
 END_CASE(JSOP_LABEL)
 
 CASE(JSOP_LOOPENTRY)
+    COUNT_COVERAGE();
     // Attempt on-stack replacement with Baseline code.
     if (jit::IsBaselineEnabled(cx)) {
         jit::MethodStatus status = jit::CanEnterBaselineAtBranch(cx, REGS.fp(), false);
         if (status == jit::Method_Error)
             goto error;
         if (status == jit::Method_Compiled) {
             bool wasSPS = REGS.fp()->hasPushedSPSFrame();
 
@@ -2073,16 +2106,17 @@ CASE(JSOP_ISNOITER)
     bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
     PUSH_BOOLEAN(b);
 }
 END_CASE(JSOP_ISNOITER)
 
 CASE(JSOP_ENDITER)
 {
     MOZ_ASSERT(REGS.stackDepth() >= 1);
+    COUNT_COVERAGE();
     ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
     bool ok = CloseIterator(cx, obj);
     REGS.sp--;
     if (!ok)
         goto error;
 }
 END_CASE(JSOP_ENDITER)
 
@@ -2914,16 +2948,20 @@ CASE(JSOP_FUNCALL)
         goto successful_return_continuation;
       case JSTRAP_THROW:
       case JSTRAP_ERROR:
         goto error;
       default:
         MOZ_CRASH("bad Debugger::onEnterFrame status");
     }
 
+    // Increment the coverage for the main entry point.
+    INIT_COVERAGE();
+    COUNT_COVERAGE_MAIN();
+
     /* Load first op and dispatch it (safe since JSOP_RETRVAL). */
     ADVANCE_AND_DISPATCH(0);
 }
 
 CASE(JSOP_OPTIMIZE_SPREADCALL)
 {
     ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);