Skip to content

Commit c6dddb5

Browse files
Document instrumentation alg (#1228)
Document instrumentation alg
1 parent 8f91b34 commit c6dddb5

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

src/coverlet.core/Instrumentation/Instrumenter.cs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -519,27 +519,34 @@ private void InstrumentMethod(MethodDefinition method)
519519
InstrumentIL(method);
520520
}
521521

522+
/// <summary>
523+
/// The base idea is to inject an int placeholder for every sequence point. We register source+placeholder+lines(from sequence point) for final accounting.
524+
/// Instrumentation alg(current instruction: instruction we're analyzing):
525+
/// 1) We get all branches for the method
526+
/// 2) We get the sequence point of every instruction of method(start line/end line)
527+
/// 3) We check if current instruction is reachable and coverable
528+
/// 4) For every sequence point of an instruction we put load(int hint placeholder)+call opcode above current instruction
529+
/// 5) We patch all jump to current instruction with first injected instruction(load)
530+
/// 6) If current instruction is a target for a branch we inject again load(int hint placeholder)+call opcode above current instruction
531+
/// 7) We patch all jump to current instruction with first injected instruction(load)
532+
/// </summary>
522533
private void InstrumentIL(MethodDefinition method)
523534
{
524535
method.Body.SimplifyMacros();
525536
ILProcessor processor = method.Body.GetILProcessor();
526-
527537
var index = 0;
528538
var count = processor.Body.Instructions.Count;
529-
530539
var branchPoints = _cecilSymbolHelper.GetBranchPoints(method);
531-
532540
var unreachableRanges = _reachabilityHelper.FindUnreachableIL(processor.Body.Instructions, processor.Body.ExceptionHandlers);
533541
var currentUnreachableRangeIx = 0;
534-
535542
for (int n = 0; n < count; n++)
536543
{
537-
var instruction = processor.Body.Instructions[index];
538-
var sequencePoint = method.DebugInformation.GetSequencePoint(instruction);
539-
var targetedBranchPoints = branchPoints.Where(p => p.EndOffset == instruction.Offset);
544+
var currentInstruction = processor.Body.Instructions[index];
545+
var sequencePoint = method.DebugInformation.GetSequencePoint(currentInstruction);
546+
var targetedBranchPoints = branchPoints.Where(p => p.EndOffset == currentInstruction.Offset);
540547

541548
// make sure we're looking at the correct unreachable range (if any)
542-
var instrOffset = instruction.Offset;
549+
var instrOffset = currentInstruction.Offset;
543550
while (currentUnreachableRangeIx < unreachableRanges.Length && instrOffset > unreachableRanges[currentUnreachableRangeIx].EndOffset)
544551
{
545552
currentUnreachableRangeIx++;
@@ -554,26 +561,26 @@ private void InstrumentIL(MethodDefinition method)
554561
}
555562

556563
// Check is both reachable, _and_ coverable
557-
if (isUnreachable || _cecilSymbolHelper.SkipNotCoverableInstruction(method, instruction))
564+
if (isUnreachable || _cecilSymbolHelper.SkipNotCoverableInstruction(method, currentInstruction))
558565
{
559566
index++;
560567
continue;
561568
}
562569

563570
if (sequencePoint != null && !sequencePoint.IsHidden)
564571
{
565-
if (_cecilSymbolHelper.SkipInlineAssignedAutoProperty(_parameters.SkipAutoProps, method, instruction))
572+
if (_cecilSymbolHelper.SkipInlineAssignedAutoProperty(_parameters.SkipAutoProps, method, currentInstruction))
566573
{
567574
index++;
568575
continue;
569576
}
570577

571-
var target = AddInstrumentationCode(method, processor, instruction, sequencePoint);
572-
foreach (var _instruction in processor.Body.Instructions)
573-
ReplaceInstructionTarget(_instruction, instruction, target);
578+
var firstInjectedInstrumentedOpCode = AddInstrumentationCode(method, processor, currentInstruction, sequencePoint);
579+
foreach (var bodyInstruction in processor.Body.Instructions)
580+
ReplaceInstructionTarget(bodyInstruction, currentInstruction, firstInjectedInstrumentedOpCode);
574581

575582
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
576-
ReplaceExceptionHandlerBoundary(handler, instruction, target);
583+
ReplaceExceptionHandlerBoundary(handler, currentInstruction, firstInjectedInstrumentedOpCode);
577584

578585
index += 2;
579586
}
@@ -589,12 +596,12 @@ private void InstrumentIL(MethodDefinition method)
589596
if (branchTarget.StartLine == -1 || branchTarget.Document == null)
590597
continue;
591598

592-
var target = AddInstrumentationCode(method, processor, instruction, branchTarget);
593-
foreach (var _instruction in processor.Body.Instructions)
594-
ReplaceInstructionTarget(_instruction, instruction, target);
599+
var firstInjectedInstrumentedOpCode = AddInstrumentationCode(method, processor, currentInstruction, branchTarget);
600+
foreach (var bodyInstruction in processor.Body.Instructions)
601+
ReplaceInstructionTarget(bodyInstruction, currentInstruction, firstInjectedInstrumentedOpCode);
595602

596603
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
597-
ReplaceExceptionHandlerBoundary(handler, instruction, target);
604+
ReplaceExceptionHandlerBoundary(handler, currentInstruction, firstInjectedInstrumentedOpCode);
598605

599606
index += 2;
600607
}
@@ -704,20 +711,20 @@ private Instruction AddInstrumentationInstructions(MethodDefinition method, ILPr
704711

705712
private static void ReplaceInstructionTarget(Instruction instruction, Instruction oldTarget, Instruction newTarget)
706713
{
707-
if (instruction.Operand is Instruction _instruction)
714+
if (instruction.Operand is Instruction operandInstruction)
708715
{
709-
if (_instruction == oldTarget)
716+
if (operandInstruction == oldTarget)
710717
{
711718
instruction.Operand = newTarget;
712719
return;
713720
}
714721
}
715-
else if (instruction.Operand is Instruction[] _instructions)
722+
else if (instruction.Operand is Instruction[] operandInstructions)
716723
{
717-
for (int i = 0; i < _instructions.Length; i++)
724+
for (int i = 0; i < operandInstructions.Length; i++)
718725
{
719-
if (_instructions[i] == oldTarget)
720-
_instructions[i] = newTarget;
726+
if (operandInstructions[i] == oldTarget)
727+
operandInstructions[i] = newTarget;
721728
}
722729
}
723730
}

0 commit comments

Comments
 (0)