diff --git a/eng/Versions.props b/eng/Versions.props
index d9f843a36e92b..7d867a37da28d 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -46,6 +46,7 @@
6.0.0-preview1.21054.10
3.8.0-4.20503.2
+ 3.8.0
6.0.0-beta.21062.10
6.0.0-beta.21062.10
diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 36b60ed6663a3..81a1cceef3d5f 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -13,6 +13,8 @@
Debug;Release;Checked
x64;x86;arm;arm64
+ true
+
true
$(IntermediateOutputPath)System.Private.CoreLib.xml
$(MSBuildThisFileDirectory)src\ILLink\
@@ -301,7 +303,11 @@
-
+
+
+
+
+
diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln
index 5dce3334a8e89..4629497f45f7c 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln
@@ -6,6 +6,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "S
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "System.Private.CoreLib.Shared", "..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.shproj", "{845C8B26-350B-4E63-BD11-2C8150444E28}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib.Generators", "..\..\libraries\System.Private.CoreLib\generators\System.Private.CoreLib.Generators.csproj", "{7196828B-5E00-4BC6-9A1E-492C948E41A3}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{3da06c3a-2e7b-4cb7-80ed-9b12916013f9}*SharedItemsImports = 5
@@ -13,14 +15,17 @@ Global
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Checked|amd64 = Checked|amd64
+ Checked|Any CPU = Checked|Any CPU
Checked|arm = Checked|arm
Checked|arm64 = Checked|arm64
Checked|x86 = Checked|x86
Debug|amd64 = Debug|amd64
+ Debug|Any CPU = Debug|Any CPU
Debug|arm = Debug|arm
Debug|arm64 = Debug|arm64
Debug|x86 = Debug|x86
Release|amd64 = Release|amd64
+ Release|Any CPU = Release|Any CPU
Release|arm = Release|arm
Release|arm64 = Release|arm64
Release|x86 = Release|x86
@@ -28,6 +33,7 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|amd64.ActiveCfg = Checked|x64
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|amd64.Build.0 = Checked|x64
+ {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|Any CPU.ActiveCfg = Checked|x86
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|arm.ActiveCfg = Checked|arm
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|arm.Build.0 = Checked|arm
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|arm64.ActiveCfg = Checked|arm64
@@ -36,6 +42,7 @@ Global
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Checked|x86.Build.0 = Checked|x86
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|amd64.ActiveCfg = Debug|x64
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|amd64.Build.0 = Debug|x64
+ {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|Any CPU.ActiveCfg = Debug|x86
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|arm.ActiveCfg = Debug|arm
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|arm.Build.0 = Debug|arm
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|arm64.ActiveCfg = Debug|arm64
@@ -44,12 +51,43 @@ Global
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Debug|x86.Build.0 = Debug|x86
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|amd64.ActiveCfg = Release|x64
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|amd64.Build.0 = Release|x64
+ {3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|Any CPU.ActiveCfg = Release|x86
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm.ActiveCfg = Release|arm
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm.Build.0 = Release|arm
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm64.ActiveCfg = Release|arm64
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|arm64.Build.0 = Release|arm64
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|x86.ActiveCfg = Release|x86
{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}.Release|x86.Build.0 = Release|x86
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|amd64.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|amd64.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|Any CPU.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm64.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|arm64.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|x86.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Checked|x86.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|amd64.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|amd64.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm64.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|arm64.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Debug|x86.Build.0 = Debug|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|amd64.ActiveCfg = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|amd64.Build.0 = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm.ActiveCfg = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm.Build.0 = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm64.ActiveCfg = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|arm64.Build.0 = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|x86.ActiveCfg = Release|Any CPU
+ {7196828B-5E00-4BC6-9A1E-492C948E41A3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Emitter.cs b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Emitter.cs
new file mode 100644
index 0000000000000..9b30dd4de5323
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Emitter.cs
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Text;
+using System.Threading;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Generators
+{
+ public partial class EventSourceGenerator
+ {
+ private class Emitter
+ {
+ private readonly StringBuilder _builder = new StringBuilder(1024);
+ private readonly GeneratorExecutionContext _context;
+
+ public Emitter(GeneratorExecutionContext context) => _context = context;
+
+ public void Emit(EventSourceClass[] eventSources, CancellationToken cancellationToken)
+ {
+ foreach (EventSourceClass? ec in eventSources)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ // stop any additional work
+ break;
+ }
+
+ _builder.AppendLine("using System;");
+ GenType(ec);
+
+ _context.AddSource($"{ec.ClassName}.Generated", SourceText.From(_builder.ToString(), Encoding.UTF8));
+
+ _builder.Clear();
+ }
+ }
+
+ private void GenType(EventSourceClass ec)
+ {
+ if (!string.IsNullOrWhiteSpace(ec.Namespace))
+ {
+ _builder.AppendLine($@"
+namespace {ec.Namespace}
+{{");
+ }
+
+ _builder.AppendLine($@"
+ partial class {ec.ClassName}
+ {{");
+ GenerateConstructor(ec);
+
+ GenerateProviderMetadata(ec.SourceName);
+
+ _builder.AppendLine($@"
+ }}");
+
+ if (!string.IsNullOrWhiteSpace(ec.Namespace))
+ {
+ _builder.AppendLine($@"
+}}");
+ }
+ }
+
+ private void GenerateConstructor(EventSourceClass ec)
+ {
+ _builder.AppendLine($@"
+ private {ec.ClassName}() : base(new Guid({ec.Guid.ToString("x").Replace("{", "").Replace("}", "")}), ""{ec.SourceName}"") {{ }}");
+ }
+
+ private void GenerateProviderMetadata(string sourceName)
+ {
+ _builder.Append(@"
+ private protected override ReadOnlySpan ProviderMetadata => new byte[] { ");
+
+ byte[] metadataBytes = MetadataForString(sourceName);
+ foreach (byte b in metadataBytes)
+ {
+ _builder.Append($"0x{b:x}, ");
+ }
+
+ _builder.AppendLine(@"};");
+ }
+
+ // From System.Private.CoreLib
+ private static byte[] MetadataForString(string name)
+ {
+ CheckName(name);
+ int metadataSize = Encoding.UTF8.GetByteCount(name) + 3;
+ byte[]? metadata = new byte[metadataSize];
+ ushort totalSize = checked((ushort)(metadataSize));
+ metadata[0] = unchecked((byte)totalSize);
+ metadata[1] = unchecked((byte)(totalSize >> 8));
+ Encoding.UTF8.GetBytes(name, 0, name.Length, metadata, 2);
+ return metadata;
+ }
+
+ private static void CheckName(string? name)
+ {
+ if (name != null && 0 <= name.IndexOf('\0'))
+ {
+ throw new ArgumentOutOfRangeException(nameof(name));
+ }
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs
new file mode 100644
index 0000000000000..03e9dad395ad3
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs
@@ -0,0 +1,195 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Generators
+{
+ public partial class EventSourceGenerator
+ {
+ private class Parser
+ {
+ private readonly CancellationToken _cancellationToken;
+ private readonly Compilation _compilation;
+ private readonly Action _reportDiagnostic;
+
+ public Parser(Compilation compilation, Action reportDiagnostic, CancellationToken cancellationToken)
+ {
+ _compilation = compilation;
+ _cancellationToken = cancellationToken;
+ _reportDiagnostic = reportDiagnostic;
+ }
+
+ public EventSourceClass[] GetEventSourceClasses(List classDeclarations)
+ {
+ INamedTypeSymbol? autogenerateAttribute = _compilation.GetTypeByMetadataName("System.Diagnostics.Tracing.EventSourceAutoGenerateAttribute");
+ if (autogenerateAttribute is null)
+ {
+ // No EventSourceAutoGenerateAttribute
+ return Array.Empty();
+ }
+
+ INamedTypeSymbol? eventSourceAttribute = _compilation.GetTypeByMetadataName("System.Diagnostics.Tracing.EventSourceAttribute");
+ if (eventSourceAttribute is null)
+ {
+ // No EventSourceAttribute
+ return Array.Empty();
+ }
+
+ List? results = null;
+ // we enumerate by syntax tree, to minimize the need to instantiate semantic models (since they're expensive)
+ foreach (IGrouping? group in classDeclarations.GroupBy(x => x.SyntaxTree))
+ {
+ SemanticModel? sm = null;
+ EventSourceClass? eventSourceClass = null;
+ foreach (ClassDeclarationSyntax? classDef in group)
+ {
+ if (_cancellationToken.IsCancellationRequested)
+ {
+ // be nice and stop if we're asked to
+ return results?.ToArray() ?? Array.Empty();
+ }
+
+ bool autoGenerate = false;
+ foreach (AttributeListSyntax? cal in classDef.AttributeLists)
+ {
+ foreach (AttributeSyntax? ca in cal.Attributes)
+ {
+ // need a semantic model for this tree
+ sm ??= _compilation.GetSemanticModel(classDef.SyntaxTree);
+
+ if (sm.GetSymbolInfo(ca, _cancellationToken).Symbol is not IMethodSymbol caSymbol)
+ {
+ // badly formed attribute definition, or not the right attribute
+ continue;
+ }
+
+ if (autogenerateAttribute.Equals(caSymbol.ContainingType, SymbolEqualityComparer.Default))
+ {
+ autoGenerate = true;
+ continue;
+ }
+ if (eventSourceAttribute.Equals(caSymbol.ContainingType, SymbolEqualityComparer.Default))
+ {
+ string nspace = string.Empty;
+ NamespaceDeclarationSyntax? ns = classDef.Parent as NamespaceDeclarationSyntax;
+ if (ns is null)
+ {
+ if (classDef.Parent is not CompilationUnitSyntax)
+ {
+ // since this generator doesn't know how to generate a nested type...
+ continue;
+ }
+ }
+ else
+ {
+ nspace = ns.Name.ToString();
+ while (true)
+ {
+ ns = ns.Parent as NamespaceDeclarationSyntax;
+ if (ns == null)
+ {
+ break;
+ }
+
+ nspace = $"{ns.Name}.{nspace}";
+ }
+ }
+
+ string className = classDef.Identifier.ToString();
+ string name = className;
+ string guid = "";
+
+ SeparatedSyntaxList? args = ca.ArgumentList?.Arguments;
+ if (args is not null)
+ {
+ foreach (AttributeArgumentSyntax? arg in args)
+ {
+ string? argName = arg.NameEquals!.Name.Identifier.ToString();
+ string? value = sm.GetConstantValue(arg.Expression, _cancellationToken).ToString();
+
+ switch (argName)
+ {
+ case "Guid":
+ guid = value;
+ break;
+ case "Name":
+ name = value;
+ break;
+ }
+ }
+ }
+
+ if (!Guid.TryParse(guid, out Guid result))
+ {
+ result = GenerateGuidFromName(name.ToUpperInvariant());
+ }
+
+ eventSourceClass = new EventSourceClass
+ {
+ Namespace = nspace,
+ ClassName = className,
+ SourceName = name,
+ Guid = result
+ };
+ continue;
+ }
+ }
+ }
+
+ if (!autoGenerate)
+ {
+ continue;
+ }
+
+ if (eventSourceClass is null)
+ {
+ continue;
+ }
+
+ results ??= new List();
+ results.Add(eventSourceClass);
+ }
+ }
+
+ return results?.ToArray() ?? Array.Empty();
+ }
+
+ // From System.Private.CoreLib
+ private static Guid GenerateGuidFromName(string name)
+ {
+ ReadOnlySpan namespaceBytes = new byte[] // rely on C# compiler optimization to remove byte[] allocation
+ {
+ 0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
+ 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
+ };
+
+ byte[] bytes = Encoding.BigEndianUnicode.GetBytes(name);
+
+ byte[] combinedBytes = new byte[namespaceBytes.Length + bytes.Length];
+
+ bytes.CopyTo(combinedBytes, namespaceBytes.Length);
+ namespaceBytes.CopyTo(combinedBytes);
+
+ using (SHA1 sha = SHA1.Create())
+ {
+ bytes = sha.ComputeHash(combinedBytes);
+ }
+
+ Array.Resize(ref bytes, 16);
+
+ bytes[7] = unchecked((byte)((bytes[7] & 0x0F) | 0x50)); // Set high 4 bits of octet 7 to 5, as per RFC 4122
+ return new Guid(bytes);
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.cs b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.cs
new file mode 100644
index 0000000000000..b86cdebb0a1e4
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.cs
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Generators
+{
+ [Generator]
+ public partial class EventSourceGenerator : ISourceGenerator
+ {
+ // Example input:
+ //
+ // [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = "System.Runtime")]
+ // [EventSourceAutoGenerate]
+ // internal sealed partial class RuntimeEventSource : EventSource
+ //
+ // Example generated output:
+ //
+ // using System;
+ //
+ // namespace System.Diagnostics.Tracing
+ // {
+ // partial class RuntimeEventSource
+ // {
+ // private RuntimeEventSource() : base(new Guid(0x49592c0f,0x5a05,0x516d,0xaa,0x4b,0xa6,0x4e,0x02,0x02,0x6c,0x89), "System.Runtime") { }
+ //
+ // private protected override ReadOnlySpan ProviderMetadata => new byte[] { 0x11, 0x0, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x0, };
+ // }
+ // }
+
+ public void Initialize(GeneratorInitializationContext context)
+ => context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ SyntaxReceiver? receiver = context.SyntaxReceiver as SyntaxReceiver;
+ if ((receiver?.CandidateClasses?.Count ?? 0) == 0)
+ {
+ // nothing to do yet
+ return;
+ }
+
+ Parser? p = new Parser(context.Compilation, context.ReportDiagnostic, context.CancellationToken);
+ EventSourceClass[]? eventSources = p.GetEventSourceClasses(receiver.CandidateClasses);
+
+ if (eventSources?.Length > 0)
+ {
+ Emitter? e = new Emitter(context);
+ e.Emit(eventSources, context.CancellationToken);
+ }
+ }
+
+ private sealed class SyntaxReceiver : ISyntaxReceiver
+ {
+ private List? _candidateClasses;
+
+ public List? CandidateClasses => _candidateClasses;
+
+ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+ {
+ // Only add classes annotated [EventSourceAutoGenerate] to reduce busy work.
+ const string EventSourceAttribute = "EventSourceAutoGenerateAttribute";
+ const string EventSourceAttributeShort = "EventSourceAutoGenerate";
+
+ // Only clasess
+ if (syntaxNode is ClassDeclarationSyntax classDeclaration)
+ {
+ // Check if has EventSource attribute before adding to candidates
+ // as we don't want to add every class in the project
+ foreach (AttributeListSyntax? cal in classDeclaration.AttributeLists)
+ {
+ foreach (AttributeSyntax? ca in cal.Attributes)
+ {
+ // Check if Span length matches before allocating the string to check more
+ int length = ca.Name.Span.Length;
+ if (length != EventSourceAttribute.Length && length != EventSourceAttributeShort.Length)
+ {
+ continue;
+ }
+
+ // Possible match, now check the string value
+ string attrName = ca.Name.ToString();
+ if (attrName == EventSourceAttribute || attrName == EventSourceAttributeShort)
+ {
+ // Match add to candidates
+ _candidateClasses ??= new List();
+ _candidateClasses.Add(classDeclaration);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private class EventSourceClass
+ {
+ public string Namespace = string.Empty;
+ public string ClassName = string.Empty;
+ public string SourceName = string.Empty;
+ public Guid Guid = Guid.Empty;
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj b/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj
new file mode 100644
index 0000000000000..9b241b14aaf42
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj
@@ -0,0 +1,19 @@
+
+
+ netstandard2.0
+ latest
+ enable
+ false
+ $(NoWarn);CS3001
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/ArrayPoolEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/ArrayPoolEventSource.cs
index 32851bac2d36b..2f6ac1842393d 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Buffers/ArrayPoolEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/ArrayPoolEventSource.cs
@@ -6,7 +6,8 @@
namespace System.Buffers
{
[EventSource(Guid = "0866B2B8-5CEF-5DB9-2612-0C0FFD814A44", Name = "System.Buffers.ArrayPoolEventSource")]
- internal sealed class ArrayPoolEventSource : EventSource
+ [EventSourceAutoGenerate]
+ internal sealed partial class ArrayPoolEventSource : EventSource
{
internal static readonly ArrayPoolEventSource Log = new ArrayPoolEventSource();
@@ -21,8 +22,9 @@ internal enum BufferAllocatedReason : int
PoolExhausted
}
- // The ArrayPoolEventSource GUID is {0866b2b8-5cef-5db9-2612-0c0ffd814a44}
- private ArrayPoolEventSource() : base(new Guid(0x0866b2b8, 0x5cef, 0x5db9, 0x26, 0x12, 0x0c, 0x0f, 0xfd, 0x81, 0x4a, 0x44), "System.Buffers.ArrayPoolEventSource") { }
+ // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
+ // as you can't make a constructor partial.
+ private ArrayPoolEventSource(int _) { }
///
/// Event for when a buffer is rented. This is invoked once for every successful call to Rent,
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
index 1e67a98ed310f..40c64e486e990 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
@@ -182,10 +182,16 @@
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
+{
#else
namespace System.Diagnostics.Tracing
-#endif
{
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class EventSourceAutoGenerateAttribute : Attribute
+ {
+ }
+
+#endif
///
/// This class is meant to be inherited by a user-defined event source in order to define a managed
/// ETW provider. Please See DESIGN NOTES above for the internal architecture.
@@ -1471,9 +1477,14 @@ private unsafe void Initialize(Guid eventSourceGuid, string eventSourceName, str
m_activityTracker = ActivityTracker.Instance;
#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING
- // Create and register our provider traits. We do this early because it is needed to log errors
- // In the self-describing event case.
- this.InitializeProviderMetadata();
+#if !DEBUG
+ if (ProviderMetadata.Length == 0)
+#endif
+ {
+ // Create and register our provider traits. We do this early because it is needed to log errors
+ // In the self-describing event case.
+ InitializeProviderMetadata();
+ }
#endif
#if FEATURE_MANAGED_ETW
// Register the provider with ETW
@@ -1504,12 +1515,13 @@ private unsafe void Initialize(Guid eventSourceGuid, string eventSourceName, str
if (this.Name != "System.Diagnostics.Eventing.FrameworkEventSource" || Environment.IsWindows8OrAbove)
#endif
{
- fixed (byte* providerMetadata = this.providerMetadata)
+ var providerMetadata = ProviderMetadata;
+ fixed (byte* pMetadata = providerMetadata)
{
m_etwProvider.SetInformation(
Interop.Advapi32.EVENT_INFO_CLASS.SetTraits,
- providerMetadata,
- (uint)this.providerMetadata.Length);
+ pMetadata,
+ (uint)providerMetadata.Length);
}
}
#endif // TARGET_WINDOWS
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/FrameworkEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/FrameworkEventSource.cs
index 1d3b01fc0218f..d1e3cfe154e27 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/FrameworkEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/FrameworkEventSource.cs
@@ -7,7 +7,8 @@
namespace System.Diagnostics.Tracing
{
[EventSource(Guid = "8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1", Name = "System.Diagnostics.Eventing.FrameworkEventSource")]
- internal sealed class FrameworkEventSource : EventSource
+ [EventSourceAutoGenerate]
+ internal sealed partial class FrameworkEventSource : EventSource
{
public static readonly FrameworkEventSource Log = new FrameworkEventSource();
@@ -28,8 +29,9 @@ public static class Keywords
public const EventTask ThreadTransfer = (EventTask)3;
}
- // The FrameworkEventSource GUID is {8E9F5090-2D75-4d03-8A81-E5AFBF85DAF1}
- private FrameworkEventSource() : base(new Guid(0x8e9f5090, 0x2d75, 0x4d03, 0x8a, 0x81, 0xe5, 0xaf, 0xbf, 0x85, 0xda, 0xf1), "System.Diagnostics.Eventing.FrameworkEventSource") { }
+ // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
+ // as you can't make a constructor partial.
+ private FrameworkEventSource(int _) { }
// optimized for common signatures (used by the ThreadTransferSend/Receive events)
[NonEvent]
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
index 8901696a8cc2a..027e120c5a5c5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
@@ -7,14 +7,16 @@ namespace System.Diagnostics.Tracing
/// NativeRuntimeEventSource is an EventSource that represents the ETW/EventPipe events emitted by the native runtime.
/// Most of NativeRuntimeEventSource is auto-generated by scripts/genRuntimeEventSources.py based on the contents of the Microsoft-Windows-DotNETRuntime provider.
///
- [EventSource(Guid = "5E5BB766-BBFC-5662-0548-1D44FAD9BB56", Name = "Microsoft-Windows-DotNETRuntime")]
+ [EventSource(Guid = "5E5BB766-BBFC-5662-0548-1D44FAD9BB56", Name = EventSourceName)]
+ [EventSourceAutoGenerate]
internal sealed partial class NativeRuntimeEventSource : EventSource
{
internal const string EventSourceName = "Microsoft-Windows-DotNETRuntime";
internal static NativeRuntimeEventSource Log = new NativeRuntimeEventSource();
- // The NativeRuntimeEventSource GUID is {5e5bb766-bbfc-5662-0548-1d44fad9bb56}
- private NativeRuntimeEventSource() : base(new Guid(0x5e5bb766, 0xbbfc, 0x5662, 0x05, 0x48, 0x1d, 0x44, 0xfa, 0xd9, 0xbb, 0x56), EventSourceName) { }
+ // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
+ // as you can't make a constructor partial.
+ private NativeRuntimeEventSource(int _) { }
///
/// Dispatch a single event with the specified event ID and payload.
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
index 4123a54e36946..053157c01d36c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs
@@ -8,8 +8,9 @@ namespace System.Diagnostics.Tracing
///
/// RuntimeEventSource is an EventSource that represents events emitted by the managed runtime.
///
- [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = "System.Runtime")]
- internal sealed class RuntimeEventSource : EventSource
+ [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = EventSourceName)]
+ [EventSourceAutoGenerate]
+ internal sealed partial class RuntimeEventSource : EventSource
{
internal const string EventSourceName = "System.Runtime";
@@ -46,9 +47,9 @@ public static void Initialize()
s_RuntimeEventSource = new RuntimeEventSource();
}
- private RuntimeEventSource() : base(new Guid(0x49592C0F, 0x5A05, 0x516D, 0xAA, 0x4B, 0xA6, 0x4E, 0x02, 0x02, 0x6C, 0x89), EventSourceName, EventSourceSettings.EtwSelfDescribingEventFormat)
- {
- }
+ // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
+ // as you can't make a constructor partial.
+ private RuntimeEventSource(int _) { }
protected override void OnEventCommand(EventCommandEventArgs command)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
index 399fe3c889d90..4087165e75b45 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
@@ -21,15 +21,22 @@
using System.Text;
#if ES_BUILD_STANDALONE
+using System.Runtime.CompilerServices;
namespace Microsoft.Diagnostics.Tracing
#else
+using Internal.Runtime.CompilerServices;
namespace System.Diagnostics.Tracing
#endif
{
public partial class EventSource
{
#if FEATURE_MANAGED_ETW
- private byte[] providerMetadata = null!;
+ private byte[]? m_providerMetadata;
+#if ES_BUILD_STANDALONE
+ private byte[] ProviderMetadata => m_providerMetadata ?? Array.Empty();
+#else
+ private protected virtual ReadOnlySpan ProviderMetadata => m_providerMetadata;
+#endif
#endif
#if FEATURE_PERFTRACING
@@ -427,12 +434,13 @@ private unsafe void WriteMultiMergeInner(
for (int i = 0; i < pinCount; i++)
pins[i] = default;
+ var providerMetadata = ProviderMetadata;
fixed (byte*
- pMetadata0 = this.providerMetadata,
+ pMetadata0 = providerMetadata,
pMetadata1 = nameInfo.nameMetadata,
pMetadata2 = eventTypes.typeMetadata)
{
- descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
+ descriptors[0].SetMetadata(pMetadata0, providerMetadata.Length, 2);
descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
@@ -538,12 +546,13 @@ internal unsafe void WriteMultiMerge(
for (int i = 0; i < descriptorsLength; i++)
descriptors[i] = default;
+ var providerMetadata = ProviderMetadata;
fixed (byte*
- pMetadata0 = this.providerMetadata,
+ pMetadata0 = providerMetadata,
pMetadata1 = nameInfo.nameMetadata,
pMetadata2 = eventTypes.typeMetadata)
{
- descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
+ descriptors[0].SetMetadata(pMetadata0, providerMetadata.Length, 2);
descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
int numDescrs = 3;
@@ -610,12 +619,13 @@ private unsafe void WriteImpl(
for (int i = 0; i < pinCount; i++)
pins[i] = default;
+ var providerMetadata = ProviderMetadata;
fixed (byte*
- pMetadata0 = this.providerMetadata,
+ pMetadata0 = providerMetadata,
pMetadata1 = nameInfo.nameMetadata,
pMetadata2 = eventTypes.typeMetadata)
{
- descriptors[0].SetMetadata(pMetadata0, this.providerMetadata.Length, 2);
+ descriptors[0].SetMetadata(pMetadata0, providerMetadata.Length, 2);
descriptors[1].SetMetadata(pMetadata1, nameInfo.nameMetadata.Length, 1);
descriptors[2].SetMetadata(pMetadata2, eventTypes.typeMetadata.Length, 1);
#endif // FEATURE_MANAGED_ETW
@@ -749,6 +759,14 @@ private static unsafe void WriteCleanup(GCHandle* pPins, int cPins)
private void InitializeProviderMetadata()
{
#if FEATURE_MANAGED_ETW
+ bool hasProviderMetadata = ProviderMetadata.Length > 0;
+#if !DEBUG && !ES_BUILD_STANDALONE
+ if (hasProviderMetadata)
+ {
+ // Already set
+ return;
+ }
+#endif
if (m_traits != null)
{
List traitMetaData = new List(100);
@@ -778,13 +796,27 @@ private void InitializeProviderMetadata()
traitMetaData[lenPos + 1] = unchecked((byte)(valueLen >> 8));
}
}
- providerMetadata = Statics.MetadataForString(this.Name, 0, traitMetaData.Count, 0);
+ byte[] providerMetadata = Statics.MetadataForString(this.Name, 0, traitMetaData.Count, 0);
int startPos = providerMetadata.Length - traitMetaData.Count;
foreach (byte b in traitMetaData)
+ {
providerMetadata[startPos++] = b;
+ }
+
+ m_providerMetadata = providerMetadata;
}
else
- providerMetadata = Statics.MetadataForString(this.Name, 0, 0, 0);
+ {
+ m_providerMetadata = Statics.MetadataForString(this.Name, 0, 0, 0);
+ }
+
+#if DEBUG && !ES_BUILD_STANDALONE
+ if (hasProviderMetadata)
+ {
+ // Validate the provided ProviderMetadata still matches in debug
+ Debug.Assert(ProviderMetadata.SequenceEqual(m_providerMetadata));
+ }
+#endif
#endif //FEATURE_MANAGED_ETW
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs
index 65061781083b0..784f64d41c42a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs
@@ -21,7 +21,8 @@ namespace System.Threading
// provider, and update PerfView with a trace event parser for the new provider so that it knows about the events and may
// use them to identify thread pool threads.
[EventSource(Name = "Microsoft-Windows-DotNETRuntime", Guid = "e13c0d23-ccbc-4e12-931b-d9cc2eee27e4")]
- internal sealed class PortableThreadPoolEventSource : EventSource
+ [EventSourceAutoGenerate]
+ internal sealed partial class PortableThreadPoolEventSource : EventSource
{
// This value does not seem to be used, leaving it as zero for now. It may be useful for a scenario that may involve
// multiple instances of the runtime within the same process, but then it seems unlikely that both instances' thread
@@ -76,12 +77,9 @@ public enum ThreadAdjustmentReasonMap : uint
ThreadTimedOut
}
- private PortableThreadPoolEventSource()
- : base(
- new Guid(0xe13c0d23, 0xccbc, 0x4e12, 0x93, 0x1b, 0xd9, 0xcc, 0x2e, 0xee, 0x27, 0xe4),
- "Microsoft-Windows-DotNETRuntime")
- {
- }
+ // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
+ // as you can't make a constructor partial.
+ private PortableThreadPoolEventSource(int _) { }
[NonEvent]
private unsafe void WriteThreadEvent(int eventId, uint numExistingThreads)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TplEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TplEventSource.cs
index f1f12a5c0be25..4d608bdbfcf5f 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TplEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TplEventSource.cs
@@ -18,7 +18,8 @@ namespace System.Threading.Tasks
null
#endif
)]
- internal sealed class TplEventSource : EventSource
+ [EventSourceAutoGenerate]
+ internal sealed partial class TplEventSource : EventSource
{
/// Used to determine if tasks should generate Activity IDs for themselves
internal bool TasksSetActivityIds; // This keyword is set
@@ -43,12 +44,12 @@ protected override void OnEventCommand(EventCommandEventArgs command)
///
/// Defines the singleton instance for the TPL ETW provider.
- /// The TPL Event provider GUID is {2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5}.
///
public static readonly TplEventSource Log = new TplEventSource();
- /// Prevent external instantiation. All logging should go through the Log instance.
- private TplEventSource() : base(new Guid(0x2e5dba47, 0xa3d2, 0x4d16, 0x8e, 0xe0, 0x66, 0x71, 0xff, 0xdc, 0xd7, 0xb5), "System.Threading.Tasks.TplEventSource") { }
+ // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
+ // as you can't make a constructor partial.
+ private TplEventSource(int _) { }
/// Configured behavior of a task wait operation.
public enum TaskWaitBehavior : int
diff --git a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj
index a48b961b142d2..9b8fa384d7508 100644
--- a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -14,6 +14,8 @@
$(RuntimeBinDir)IL/
Debug;Release;Checked
x64;x86;arm;arm64;wasm
+
+ true
@@ -296,6 +298,10 @@
+
+
+
+