Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
89 changes: 80 additions & 9 deletions src/coreclr/tools/Common/Compiler/NativeAotNameMangler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ private static Utf8String SanitizeNameWithHash(Utf8String literal, byte[] hash =
/// Dictionary given a mangled name for a given <see cref="TypeDesc"/>
/// </summary>
private Dictionary<TypeDesc, Utf8String> _mangledTypeNames = new Dictionary<TypeDesc, Utf8String>();
private Dictionary<string, Utf8String> _mangledAssemblyNames = new Dictionary<string, Utf8String>(StringComparer.OrdinalIgnoreCase);

/// <summary>
/// Given a set of names <param name="set"/> check if <param name="origName"/>
Expand Down Expand Up @@ -195,6 +196,84 @@ protected Utf8String NestMangledName(Utf8String name)
return Utf8String.Concat(EnterNameScopeSequence, name, ExitNameScopeSequence);
}

private Utf8String GetMangledAssemblyName(EcmaAssembly assembly)
{
string assemblyName = assembly.GetName().Name;
lock (this)
{
if (_mangledAssemblyNames.TryGetValue(assemblyName, out Utf8String mangledName))
return mangledName;

return ComputeMangledAssemblyName(assemblyName, (CompilerTypeSystemContext)assembly.Context);
Comment on lines +199 to +207
}
}

private Utf8String ComputeMangledAssemblyName(string assemblyName, CompilerTypeSystemContext context)
{
lock (this)
{
if (!_mangledAssemblyNames.TryGetValue(assemblyName, out Utf8String name))
{
var assemblies = new List<string>(context.InputFilePaths.Count + context.ReferenceFilePaths.Count + 1);
var assemblySet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (assemblySet.Add(assemblyName))
assemblies.Add(assemblyName);
foreach (string candidateAssemblyName in context.InputFilePaths.Keys)
{
if (assemblySet.Add(candidateAssemblyName))
assemblies.Add(candidateAssemblyName);
}
foreach (string candidateAssemblyName in context.ReferenceFilePaths.Keys)
{
if (assemblySet.Add(candidateAssemblyName))
assemblies.Add(candidateAssemblyName);
}
assemblies.Sort(CompareAssembliesForMangling);

var deduplicator = new HashSet<Utf8String>();
foreach (string candidateAssemblyName in assemblies)
{
if (_mangledAssemblyNames.TryGetValue(candidateAssemblyName, out Utf8String existingMangledName))
{
deduplicator.Add(existingMangledName);
continue;
}

bool isSystemPrivate = IsSystemPrivateAssemblyName(candidateAssemblyName);
string prefixAssemblyName = isSystemPrivate
? string.Concat("S.P.", candidateAssemblyName.AsSpan(15))
: candidateAssemblyName;

name = SanitizeName(new Utf8String(prefixAssemblyName));

if (!isSystemPrivate)
name = DisambiguateName(name, deduplicator);

deduplicator.Add(name);
_mangledAssemblyNames.Add(candidateAssemblyName, name);
}

name = _mangledAssemblyNames[assemblyName];
}
return name;
}

static int CompareAssembliesForMangling(string leftName, string rightName)
{
bool leftSystemPrivate = IsSystemPrivateAssemblyName(leftName);
bool rightSystemPrivate = IsSystemPrivateAssemblyName(rightName);
if (leftSystemPrivate != rightSystemPrivate)
return leftSystemPrivate ? -1 : 1;

return string.CompareOrdinal(leftName, rightName);
}

static bool IsSystemPrivateAssemblyName(string assemblyName)
{
return assemblyName.StartsWith("System.Private.", StringComparison.Ordinal);
}
Comment on lines +271 to +274
}

/// <summary>
/// If given <param name="type"/> is an <see cref="EcmaType"/> precompute its mangled type name
/// along with all the other types from the same module as <param name="type"/>.
Expand All @@ -215,15 +294,7 @@ private Utf8String ComputeMangledTypeName(TypeDesc type)
{
bool isSystemModule = ecmaType.Module == ecmaType.Context.SystemModule;

string assemblyName = ((EcmaAssembly)ecmaType.Module).GetName().Name;
bool isSystemPrivate = assemblyName.StartsWith("System.Private.");

// Abbreviate System.Private to S.P. This might conflict with user defined assembly names,
// but we already have a problem due to running SanitizeName without disambiguating the result
// This problem needs a better fix.
if (isSystemPrivate)
assemblyName = string.Concat("S.P.", assemblyName.AsSpan(15));
Utf8String prependAssemblyName = SanitizeName(new Utf8String(assemblyName));
Utf8String prependAssemblyName = GetMangledAssemblyName((EcmaAssembly)ecmaType.Module);

var deduplicator = new HashSet<Utf8String>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>A.B</AssemblyName>
</PropertyGroup>
Comment thread
MichalStrehovsky marked this conversation as resolved.
<ItemGroup>
<Compile Include="TestType.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace TestNamespace;

public sealed class TestType
{
public string Value => "A.B";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>A_B</AssemblyName>
</PropertyGroup>
Comment thread
MichalStrehovsky marked this conversation as resolved.
<ItemGroup>
<Compile Include="TestType.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace TestNamespace;

public sealed class TestType
{
public string Value => "A_B";
}
17 changes: 17 additions & 0 deletions src/tests/nativeaot/Regressions/Runtime112629/Runtime112629.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

extern alias AssemblyWithDot;
extern alias AssemblyWithUnderscore;

using Xunit;

class Program
{
[Fact]
public static void TestEntryPoint()
{
Assert.Equal("A.B", new AssemblyWithDot::TestNamespace.TestType().Value);
Assert.Equal("A_B", new AssemblyWithUnderscore::TestNamespace.TestType().Value);
}
}
10 changes: 10 additions & 0 deletions src/tests/nativeaot/Regressions/Runtime112629/Runtime112629.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
Comment thread
MichalStrehovsky marked this conversation as resolved.
<PropertyGroup>
<CLRTestPriority>0</CLRTestPriority>
</PropertyGroup>
Comment thread
MichalStrehovsky marked this conversation as resolved.
<ItemGroup>
Comment thread
MichalStrehovsky marked this conversation as resolved.
<Compile Include="Runtime112629.cs" />
<ProjectReference Include="AssemblyWithDot\AssemblyWithDot.csproj" Aliases="AssemblyWithDot" />
<ProjectReference Include="AssemblyWithUnderscore\AssemblyWithUnderscore.csproj" Aliases="AssemblyWithUnderscore" />
</ItemGroup>
</Project>
Comment on lines +1 to +10
Loading