Open Bug 1198356 Opened 9 years ago Updated 2 years ago

SrcNoteLineScanner reports multiple times the same line.

Categories

(Core :: JavaScript Engine, defect)

defect

Tracking

()

Tracking Status
firefox43 --- affected

People

(Reporter: nbp, Unassigned)

References

(Blocks 1 open bug)

Details

While working on LCov instrumentation (Bug 1191289), I tried to use SrcNoteLineScanner to report the line headers while I iterate over the bytecode.

Sadly, I noticed that I cannot use such system because multiple pc are reported as being a line header of the first line.

The problem lies in the fact that we only walk to the next source note offset, as soon as we reached the next source note offset.  Which means that the initial condition to set the lineHeader variable is still true on the second call to advanceTo.

> Cannot find `LF:1` in the following Lcov result:
> TN:Compartment_0x5f0x18afdc0
> SF:/home/nicolas/mozilla/alternate-dev/js/src/jit-test/tests/coverage/simple.js line 49 > eval
> FN:1,top-level
> FNDA:1,top-level
> FNF:1
> FNH:1
> BRF:0
> BRH:0
> DA:2,1  /!\ We should only have one, and not one for each opcode.
> DA:2,1
> DA:2,1
> DA:2,1
> DA:2,1
> DA:2,1
> DA:2,1
> LF:7
> LH:7
> end_of_record
> 
> In the following source:
>   //FN:$,top-level //FNDA:1,%
>   ",".split(','); //DA:$,1
>   //FNF:1
>   //FNH:1
>   //LF:1
>   //LH:1


Fixing this issue to do the same behaviour as in Bug 1191289, causes different failures in the debugger tests:

    debug/Frame-onPop-10.js
    debug/Frame-onStep-04.js
    debug/Frame-onStep-05.js
    debug/Frame-onStep-06.js
    debug/Frame-onStep-lines-01.js
    debug/testEarlyReturnOnCall.js

These failures might be related to the use of SrcNoteLineScanner within BaselineScript::toggleDebugTraps, which would means that for such sources, we might have set multiple breakpoints at the entry of the bytecode.

I think we should fix the Debugger, at the same time as the SrcNoteLineScanner.
This bug does not really block the implementation of code coverage, but it would be nicer to have a proper implementation, in GetPCCountJSON, GetLcovInfo, and in the Debugger.
Internally, gcov works by inserting a counter into every edge in a basic block control-flow graph. (Well, it doesn't actually count all edges--but you can derive the counts of all edges from the counters given). Line counts are computed by roughly this pseudo-code:

for each bb:
  bb.count = sum(e.count for e in bb.out_edges or bb.in_edges)
  bbs[bb.line].add(bb)

for each line in bbs:
  count = sum of edge counts for incoming edges of bbs[line] that have a source not in that line
  G = induced subgraph on CFG over the nodes bbs[line]
  for each loop in G:
    loop_count = min(edge count for edges in loop)
    for edge in loop:
      edge.count -= loop_count
    count += loop_count
  counts[line] = count

(Yes, the loop count stuff is very gross. I tried writing a greenfield implementation of that logic for the loop counts, and I've been unable to match its logic for the loop algorithm, since it turns out "for each loop" is actually a very difficult construct to code (a standard DFS doesn't work, since a backedge may be part of multiple simple loops). It also produces either an infinite loop or insanely-long runtime on one file in our tree, probably due to "entire function body written as a macro on one line" (<https://dxr.mozilla.org/comm-central/source/mozilla/media/libjpeg/jchuff.c#562>)).
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.