Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
92 changes: 83 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<EcmaAssembly, Utf8String> _mangledAssemblyNames = new Dictionary<EcmaAssembly, Utf8String>();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Look like making this keyed on EcmaAssembly is problematic because we cannot load everything that is getting passed as input (some of the -r parameters specify garbage). Switch this back to being keyed on string where the string is the assembly file name without extension ("simple name").


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

private Utf8String GetMangledAssemblyName(EcmaAssembly assembly)
{
lock (this)
{
if (_mangledAssemblyNames.TryGetValue(assembly, out Utf8String mangledName))
return mangledName;

return ComputeMangledAssemblyName(assembly);
}
}

private Utf8String ComputeMangledAssemblyName(EcmaAssembly assembly)
{
lock (this)
{
if (!_mangledAssemblyNames.TryGetValue(assembly, out Utf8String name))
{
CompilerTypeSystemContext context = (CompilerTypeSystemContext)assembly.Context;
var assemblies = new List<EcmaAssembly>(context.InputFilePaths.Count + context.ReferenceFilePaths.Count);
var assemblySet = new HashSet<EcmaAssembly>();
foreach (string filePath in context.InputFilePaths.Values)
{
EcmaAssembly candidateAssembly = (EcmaAssembly)context.GetModuleFromPath(filePath).Assembly;
if (assemblySet.Add(candidateAssembly))
assemblies.Add(candidateAssembly);
}
foreach (string filePath in context.ReferenceFilePaths.Values)
{
EcmaAssembly candidateAssembly = (EcmaAssembly)context.GetModuleFromPath(filePath).Assembly;
if (assemblySet.Add(candidateAssembly))
assemblies.Add(candidateAssembly);
}
assemblies.Sort(CompareAssembliesForMangling);

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

string candidateAssemblyName = candidateAssembly.GetName().Name;
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(candidateAssembly, name);
}

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

static int CompareAssembliesForMangling(EcmaAssembly left, EcmaAssembly right)
{
string leftName = left.GetName().Name;
string rightName = right.GetName().Name;
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);
}
}

/// <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 +297,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
Expand Up @@ -12,6 +12,7 @@
</PropertyGroup>

<ItemGroup>
<Compile Remove="ManglerCollision.*\**" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Delete this line.

<ProjectReference Include="..\..\..\..\nativeaot\Test.CoreLib\src\Test.CoreLib.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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;

class Program
{
public static int Main()
{
if (new AssemblyWithDot::TestNamespace.TestType().Value != "A.B")
return 101;

if (new AssemblyWithUnderscore::TestNamespace.TestType().Value != "A_B")
return 102;

return 100;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
<ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestPriority>0</CLRTestPriority>
</PropertyGroup>
<ItemGroup>

<ProjectReference Include="AssemblyWithDot\AssemblyWithDot.csproj" Aliases="AssemblyWithDot" />
<ProjectReference Include="AssemblyWithUnderscore\AssemblyWithUnderscore.csproj" Aliases="AssemblyWithUnderscore" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>A.B</AssemblyName>
</PropertyGroup>
</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,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>A_B</AssemblyName>
</PropertyGroup>
</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";
}
Loading