Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeMap API (Dynamic implementation) #113954

Merged
merged 25 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bd76011
TypeMap API (Dynamic implementation)
AaronRobinsonMSFT Mar 26, 2025
a2bfc27
Add basic tests
AaronRobinsonMSFT Mar 26, 2025
7ed138b
Feedback and fixes from testing.
AaronRobinsonMSFT Mar 27, 2025
2205ac8
Testing for all attributes
AaronRobinsonMSFT Mar 27, 2025
91862d1
Convert Tuple<,> to private type.
AaronRobinsonMSFT Mar 28, 2025
cf32158
Feedback pass 1
AaronRobinsonMSFT Mar 29, 2025
60e18c9
Always fallback and validate TypeSpec.
AaronRobinsonMSFT Mar 29, 2025
fb1e1a6
Handle exceptions from managed callbacks.
AaronRobinsonMSFT Mar 29, 2025
04d9b10
Convert assert to explicit check for TypeSpec.
AaronRobinsonMSFT Mar 29, 2025
49c5ad6
Delay parsing contents until needed.
AaronRobinsonMSFT Mar 30, 2025
479c15b
Fix build
AaronRobinsonMSFT Mar 31, 2025
e7f9e6a
Call Return on ArrayPool array.
AaronRobinsonMSFT Mar 31, 2025
eb9e9e2
Remove unnecessary lock.
AaronRobinsonMSFT Mar 31, 2025
380b809
Stop processing on error.
AaronRobinsonMSFT Mar 31, 2025
e94234f
Use GetMaxCharCount to estimate needed buffer length.
AaronRobinsonMSFT Mar 31, 2025
d2123d0
Perform type loading via the TypeNameResolver.GetTypeHelper API.
AaronRobinsonMSFT Mar 31, 2025
7e99942
Move managed VersionResilientHashCode logic
AaronRobinsonMSFT Mar 31, 2025
593f09e
Use newly shared VersionResilientHashCode logic.
AaronRobinsonMSFT Mar 31, 2025
9ac6068
Remove TypeMapLazyDictionary.cs from mono build.
AaronRobinsonMSFT Mar 31, 2025
51f8342
Remove unused message.
AaronRobinsonMSFT Mar 31, 2025
697d7e1
Throw NotSupportedException for TypeMap APIs.
AaronRobinsonMSFT Mar 31, 2025
edf0a13
Feedback
AaronRobinsonMSFT Apr 1, 2025
30148a3
Remove assert
AaronRobinsonMSFT Apr 1, 2025
6c6e35c
Add message to SPCL.
AaronRobinsonMSFT Apr 1, 2025
2713896
Remove unnecessary changes.
AaronRobinsonMSFT Apr 1, 2025
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 @@ -65,25 +65,51 @@ private static unsafe partial void ProcessAttributes(
delegate* unmanaged<CallbackContext*, ProcessAttributesCallbackArg*, void> newProxyTypeEntry,
CallbackContext* context);

private static TypeName CreateNewTypeName(TypeName typeName, ReadOnlySpan<char> assemblyName)
private static TypeName NewTypeNameWithAssembly(TypeName typeName, ReadOnlySpan<char> assemblyName)
{
AssemblyNameInfo asmNameInfo = AssemblyNameInfo.Parse(assemblyName);
TypeName parsedType = typeName.WithAssemblyName(asmNameInfo);
Debug.Assert(parsedType.AssemblyName != null);
return parsedType;
}

private static ReadOnlySpan<char> ConvertUtf8ToUtf16(ReadOnlySpan<byte> utf8TypeName)
public ref struct Utf16SharedBuffer
{
int defaultUtf8StrLen = 1024;
private char[]? _backingArray;
public Utf16SharedBuffer()
{
_backingArray = null;
Buffer = default;
}

public Utf16SharedBuffer(char[] backingBuffer, int validLength)
{
_backingArray = backingBuffer;
Buffer = new ReadOnlySpan<char>(backingBuffer, 0, validLength);
}

public ReadOnlySpan<char> Buffer { get; init; }

public void Dispose()
{
if (_backingArray != null)
{
ArrayPool<char>.Shared.Return(_backingArray);
}
}
}

private static void ConvertUtf8ToUtf16(ReadOnlySpan<byte> utf8TypeName, out Utf16SharedBuffer utf16Buffer)
{
const int DefaultCharArrayLen = 1024;
const int MaxUtf8BytesPerChar = 3;
int needed = utf8TypeName.Length > (defaultUtf8StrLen * MaxUtf8BytesPerChar)
int needed = utf8TypeName.Length > (DefaultCharArrayLen * MaxUtf8BytesPerChar)
? Encoding.UTF8.GetCharCount(utf8TypeName)
: defaultUtf8StrLen;
: DefaultCharArrayLen;

char[] buffer = ArrayPool<char>.Shared.Rent(needed);
int converted = Encoding.UTF8.GetChars(utf8TypeName, buffer);
return new ReadOnlySpan<char>(buffer, 0, converted);
utf16Buffer = new Utf16SharedBuffer(buffer, converted);
}

[UnmanagedCallersOnly]
Expand Down Expand Up @@ -120,17 +146,19 @@ private static unsafe void NewProxyTypeEntry(CallbackContext* context, ProcessAt
Debug.Assert(arg->Utf8String1 != null);
Debug.Assert(arg->Utf8String2 != null);

Utf16SharedBuffer sourceTypeBuffer = new();
Utf16SharedBuffer assemblyNameBuffer = new();
try
{
ReadOnlySpan<char> sourceType = ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(arg->Utf8String1, arg->StringLen1));
ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(arg->Utf8String1, arg->StringLen1), out sourceTypeBuffer);

TypeName parsedSource = TypeNameParser.Parse(sourceType, throwOnError: true)!;
TypeName parsedSource = TypeNameParser.Parse(sourceTypeBuffer.Buffer, throwOnError: true)!;
if (parsedSource.AssemblyName is null)
{
// The assembly name is not included in the type name, so use the fallback assembly name.
Debug.Assert(arg->Utf8String3 != null);
ReadOnlySpan<char> fallbackAssemblyName = ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(arg->Utf8String3, arg->StringLen3));
parsedSource = CreateNewTypeName(parsedSource, fallbackAssemblyName);
ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(arg->Utf8String3, arg->StringLen3), out assemblyNameBuffer);
parsedSource = NewTypeNameWithAssembly(parsedSource, assemblyNameBuffer.Buffer);
}
TypeNameValue proxyTypeName = new()
{
Expand All @@ -145,6 +173,11 @@ private static unsafe void NewProxyTypeEntry(CallbackContext* context, ProcessAt
{
context->CreationException = ExceptionDispatchInfo.Capture(ex);
}
finally
{
sourceTypeBuffer.Dispose();
assemblyNameBuffer.Dispose();
}
}

private static unsafe CallbackContext CreateMaps(
Expand Down Expand Up @@ -270,15 +303,25 @@ public unsafe Type GetOrLoadType()
}
else
{
ReadOnlySpan<char> typeNameSpan = ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(_typeNameRaw.Value.Utf8TypeName, _typeNameRaw.Value.Utf8TypeNameLen));
TypeName parsedType = TypeNameParser.Parse(typeNameSpan, throwOnError: true)!;
if (parsedType.AssemblyName is null)
Utf16SharedBuffer typeNameBuffer = new();
Utf16SharedBuffer assemblyNameBuffer = new();
try
{
ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(_typeNameRaw.Value.Utf8TypeName, _typeNameRaw.Value.Utf8TypeNameLen), out typeNameBuffer);
TypeName parsedType = TypeNameParser.Parse(typeNameBuffer.Buffer, throwOnError: true)!;
if (parsedType.AssemblyName is null)
{
ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(_typeNameRaw.Value.Utf8AssemblyNameFallback, _typeNameRaw.Value.Utf8AssemblyNameFallbackLen), out assemblyNameBuffer);
parsedType = NewTypeNameWithAssembly(parsedType, assemblyNameBuffer.Buffer);
}
assemblyName = parsedType.AssemblyName!.FullName;
typeName = parsedType.FullName;
}
finally
{
ReadOnlySpan<char> fallbackAssembly = ConvertUtf8ToUtf16(new ReadOnlySpan<byte>(_typeNameRaw.Value.Utf8AssemblyNameFallback, _typeNameRaw.Value.Utf8AssemblyNameFallbackLen));
parsedType = CreateNewTypeName(parsedType, fallbackAssembly);
typeNameBuffer.Dispose();
assemblyNameBuffer.Dispose();
}
assemblyName = parsedType.AssemblyName!.FullName;
typeName = parsedType.FullName;
}

lock (this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,25 @@ internal TypeName(string? fullName,
#endif
}

#if SYSTEM_REFLECTION_METADATA
private TypeName(string? fullName,
AssemblyNameInfo? assemblyName,
TypeName? elementOrGenericType,
TypeName? declaringType,
ImmutableArray<TypeName> genericTypeArguments,
int rankOrModifier = default,
int nestedNameLength = -1)
{
_fullName = fullName;
AssemblyName = assemblyName;
_elementOrGenericType = elementOrGenericType;
_declaringType = declaringType;
_genericArguments = genericTypeArguments;
_rankOrModifier = rankOrModifier;
_nestedNameLength = nestedNameLength;
}
#endif

/// <summary>
/// The assembly-qualified name of the type; e.g., "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
/// </summary>
Expand Down
Loading