diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs index 1ad946508e33..b76113eb7d3d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs @@ -15,6 +15,7 @@ using Internal.TypeSystem.Ecma; using Debug = System.Diagnostics.Debug; +using MethodDebugInformation = Internal.IL.MethodDebugInformation; namespace ILCompiler { @@ -441,7 +442,26 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method) } } - return new SubstitutedMethodIL(method, newBody, newEHRegions.ToArray()); + // Existing debug information might not match new instruction boundaries (plus there's little point + // in generating debug information for NOPs) - generate new debug information by filtering + // out the sequence points associated with nopped out instructions. + MethodDebugInformation debugInfo = method.GetDebugInfo(); + IEnumerable oldSequencePoints = debugInfo?.GetSequencePoints(); + if (oldSequencePoints != null) + { + ArrayBuilder sequencePoints = new ArrayBuilder(); + foreach (var sequencePoint in oldSequencePoints) + { + if (sequencePoint.Offset < flags.Length && (flags[sequencePoint.Offset] & OpcodeFlags.Mark) != 0) + { + sequencePoints.Add(sequencePoint); + } + } + + debugInfo = new SubstitutedDebugInformation(debugInfo, sequencePoints.ToArray()); + } + + return new SubstitutedMethodIL(method, newBody, newEHRegions.ToArray(), debugInfo); } private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[] flags, int offset, int argIndex, out int constant) @@ -609,12 +629,14 @@ private class SubstitutedMethodIL : MethodIL private readonly byte[] _body; private readonly ILExceptionRegion[] _ehRegions; private readonly MethodIL _wrappedMethodIL; + private readonly MethodDebugInformation _debugInfo; - public SubstitutedMethodIL(MethodIL wrapped, byte[] body, ILExceptionRegion[] ehRegions) + public SubstitutedMethodIL(MethodIL wrapped, byte[] body, ILExceptionRegion[] ehRegions, MethodDebugInformation debugInfo) { _wrappedMethodIL = wrapped; _body = body; _ehRegions = ehRegions; + _debugInfo = debugInfo; } public override MethodDesc OwningMethod => _wrappedMethodIL.OwningMethod; @@ -624,6 +646,23 @@ public SubstitutedMethodIL(MethodIL wrapped, byte[] body, ILExceptionRegion[] eh public override byte[] GetILBytes() => _body; public override LocalVariableDefinition[] GetLocals() => _wrappedMethodIL.GetLocals(); public override object GetObject(int token) => _wrappedMethodIL.GetObject(token); + public override MethodDebugInformation GetDebugInfo() => _debugInfo; + } + + private class SubstitutedDebugInformation : MethodDebugInformation + { + private readonly MethodDebugInformation _originalDebugInformation; + private readonly ILSequencePoint[] _sequencePoints; + + public SubstitutedDebugInformation(MethodDebugInformation originalDebugInformation, ILSequencePoint[] newSequencePoints) + { + _originalDebugInformation = originalDebugInformation; + _sequencePoints = newSequencePoints; + } + + public override IEnumerable GetLocalVariables() => _originalDebugInformation.GetLocalVariables(); + public override IEnumerable GetParameterNames() => _originalDebugInformation.GetParameterNames(); + public override IEnumerable GetSequencePoints() => _sequencePoints; } private class FeatureSwitchHashtable : LockFreeReaderHashtable