Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public enum FrameInfoFlags
HasAssociatedData = 0x10,
}

public struct FrameInfo
public struct FrameInfo : IEquatable<FrameInfo>
{
public readonly FrameInfoFlags Flags;
public readonly int StartOffset;
Expand All @@ -30,6 +30,24 @@ public FrameInfo(FrameInfoFlags flags, int startOffset, int endOffset, byte[] bl
EndOffset = endOffset;
BlobData = blobData;
}

public bool Equals(FrameInfo other)
=> Flags == other.Flags
&& StartOffset == other.StartOffset
&& EndOffset == other.EndOffset
&& ((ReadOnlySpan<byte>)BlobData).SequenceEqual(other.BlobData);

public override bool Equals(object obj) => obj is FrameInfo other && Equals(other);

public override int GetHashCode()
{
HashCode hash = default;
hash.Add(Flags);
hash.Add(StartOffset);
hash.Add(EndOffset);
hash.AddBytes(BlobData);
return hash.ToHashCode();
}
}

public struct DebugEHClauseInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public virtual void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder
sb.Append("_associatedData_").Append(nameMangler.GetMangledMethodName(_methodNode.Method));
}

public static bool MethodHasAssociatedData(NodeFactory factory, IMethodNode methodNode)
public static bool MethodHasAssociatedData(IMethodNode methodNode)
{
// Instantiating unboxing stubs. We need to store their non-unboxing target pointer (looked up by runtime)
ISpecialUnboxThunkNode unboxThunk = methodNode as ISpecialUnboxThunkNode;
Expand All @@ -63,7 +63,7 @@ public static bool MethodHasAssociatedData(NodeFactory factory, IMethodNode meth

public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
{
Debug.Assert(MethodHasAssociatedData(factory, _methodNode));
Debug.Assert(MethodHasAssociatedData(_methodNode));

ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly);
objData.RequireInitialAlignment(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Internal.TypeSystem;
using Internal.TypeSystem.TypesDebugInfo;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.ObjectWriter
{
/// <summary>
Expand Down Expand Up @@ -114,6 +116,57 @@ private protected void EmitLsda(
}
}

private sealed class LsdaCache
{
private sealed class LsdaComparer : IEqualityComparer<INodeWithCodeInfo>
{
public static readonly LsdaComparer Instance = new LsdaComparer();

public bool Equals(INodeWithCodeInfo x, INodeWithCodeInfo y)
{
Debug.Assert(IsCacheable(x));
Debug.Assert(IsCacheable(y));
ReadOnlySpan<byte> xGc = x.GCInfo;
ReadOnlySpan<byte> yGc = y.GCInfo;
if (!xGc.SequenceEqual(yGc))
return false;

ReadOnlySpan<FrameInfo> xFrames = x.FrameInfos;
ReadOnlySpan<FrameInfo> yFrames = y.FrameInfos;
return xFrames.SequenceEqual(yFrames);
}

public int GetHashCode(INodeWithCodeInfo obj)
{
Debug.Assert(IsCacheable(obj));
HashCode hash = default;
hash.AddBytes(obj.GCInfo);
foreach (FrameInfo f in obj.FrameInfos)
hash.Add(f.GetHashCode());
return hash.ToHashCode();
}
}

private Dictionary<INodeWithCodeInfo, string[]> _lsdas = new Dictionary<INodeWithCodeInfo, string[]>(LsdaComparer.Instance);

public static bool IsCacheable(INodeWithCodeInfo nodeWithCodeInfo)
=> nodeWithCodeInfo.EHInfo == null && !MethodAssociatedDataNode.MethodHasAssociatedData((IMethodNode)nodeWithCodeInfo);

public string[] FindCachedLsda(INodeWithCodeInfo nodeWithCodeInfo)
{
Debug.Assert(IsCacheable(nodeWithCodeInfo));
return _lsdas.GetValueOrDefault(nodeWithCodeInfo);
}

public void AddLsdaToCache(INodeWithCodeInfo nodeWithCodeInfo, string[] symbols)
{
Debug.Assert(IsCacheable(nodeWithCodeInfo));
_lsdas.Add(nodeWithCodeInfo, symbols);
}
}

private readonly LsdaCache _lsdaCache = new LsdaCache();

private protected override void EmitUnwindInfo(
SectionWriter sectionWriter,
INodeWithCodeInfo nodeWithCodeInfo,
Expand All @@ -125,13 +178,21 @@ private protected override void EmitUnwindInfo(
bool useFrameNames = UseFrameNames;
SectionWriter lsdaSectionWriter;

string[] newLsdaSymbols = null;
string[] emittedLsdaSymbols = null;
if (ShouldShareSymbol((ObjectNode)nodeWithCodeInfo))
{
lsdaSectionWriter = GetOrCreateSection(LsdaSection, currentSymbolName, $"_lsda0{currentSymbolName}");
}
else
{
lsdaSectionWriter = _lsdaSectionWriter;
if (LsdaCache.IsCacheable(nodeWithCodeInfo))
{
emittedLsdaSymbols = _lsdaCache.FindCachedLsda(nodeWithCodeInfo);
if (emittedLsdaSymbols == null)
newLsdaSymbols = new string[frameInfos.Length];
}
}

long mainLsdaOffset = 0;
Expand All @@ -143,10 +204,20 @@ private protected override void EmitUnwindInfo(
int end = frameInfo.EndOffset;
byte[] blob = frameInfo.BlobData;

string lsdaSymbolName = $"_lsda{i}{currentSymbolName}";
string framSymbolName = $"_fram{i}{currentSymbolName}";
string lsdaSymbolName;
if (emittedLsdaSymbols != null)
{
lsdaSymbolName = emittedLsdaSymbols[i];
}
else
{
lsdaSymbolName = $"_lsda{i}{currentSymbolName}";
if (newLsdaSymbols != null)
newLsdaSymbols[i] = lsdaSymbolName;
lsdaSectionWriter.EmitSymbolDefinition(lsdaSymbolName);
}

lsdaSectionWriter.EmitSymbolDefinition(lsdaSymbolName);
string framSymbolName = $"_fram{i}{currentSymbolName}";
if (useFrameNames && start != 0)
{
sectionWriter.EmitSymbolDefinition(framSymbolName, start);
Expand All @@ -167,8 +238,12 @@ private protected override void EmitUnwindInfo(
_dwarfEhFrame.AddFde(fde);
}

EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

}

if (newLsdaSymbols != null)
_lsdaCache.AddLsdaToCache(nodeWithCodeInfo, newLsdaSymbols);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact
dependencies.Add(_ehInfo, "Exception handling information");
}

if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this))
if (MethodAssociatedDataNode.MethodHasAssociatedData(this))
{
dependencies ??= new DependencyList();
dependencies.Add(new DependencyListEntry(factory.MethodAssociatedData(this), "Method associated data"));
Expand Down Expand Up @@ -121,7 +121,7 @@ public ISymbolNode GetUnboxingThunkTarget(NodeFactory factory)

public ISymbolNode GetAssociatedDataNode(NodeFactory factory)
{
if (MethodAssociatedDataNode.MethodHasAssociatedData(factory, this))
if (MethodAssociatedDataNode.MethodHasAssociatedData(this))
return factory.MethodAssociatedData(this);

return null;
Expand Down