{"id":45686,"date":"2023-05-16T10:05:00","date_gmt":"2023-05-16T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=45686"},"modified":"2024-12-13T14:18:47","modified_gmt":"2024-12-13T22:18:47","slug":"announcing-dotnet-8-preview-4","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-4\/","title":{"rendered":"Announcing .NET 8 Preview 4"},"content":{"rendered":"<p>We&#8217;re excited to share all the new features and improvements in <a href=\"https:\/\/dotnet.microsoft.com\/next\">.NET 8 Preview 4<\/a>! This release is a follow-up to the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-3\/\">Preview 3 release<\/a>. You&#8217;ll continue to see many more features show up with these monthly releases. .NET 6 and 7 users will want to follow this release closely since we have focused on making it a straightforward upgrade path.<\/p>\n<p>You can <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">download .NET 8 Preview 4<\/a> for Linux, macOS, and Windows.<\/p>\n<ul>\n<li><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">Installers and binaries<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/dotnet-docker\/blob\/main\/documentation\/supported-tags.md\">Container images<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/tree\/main\/release-notes\/8.0\">Release notes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/8.0\/known-issues.md\">Known issues<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\">GitHub issue tracker<\/a><\/li>\n<\/ul>\n<p>Microsoft Build 2023 is coming! The .NET team will be hosting a number of sessions, from technical deep dives to Q&amp;As with team. <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/microsoft-build-2023-and-dotnet\/\">Join the .NET Team at Microsoft Build 2023!<\/a><\/p>\n<p>Check out what&#8217;s new in <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-4\">ASP.NET Core<\/a> and <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-ef8-preview-4\">EF Core<\/a> in the Preview 4 release. Stay current with what&#8217;s new and coming in <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/whats-new\/dotnet-8\">What&#8217;s New in .NET 8<\/a>. It will be kept updated throughout the release.<\/p>\n<p>Lastly, .NET 8 has been tested with 17.7 Preview 1. We recommend that you use the <a href=\"https:\/\/visualstudio.com\/preview\">preview channel builds<\/a> if you want to try .NET 8 with the Visual Studio family of products. Visual Studio for Mac support for .NET 8 isn\u2019t yet available. If you&#8217;re sticking to the stable channel, go check out the latest features and improvements with the <a href=\"https:\/\/aka.ms\/vs\/v176GA\">Visual Studio 17.6 release<\/a>.<\/p>\n<p>Now, let&#8217;s take a look at some new .NET 8 features.<\/p>\n<p><a href=\"https:\/\/dotnet.microsoft.com\/next\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/dotnet-8-preview-4.png\" alt=\"Download .NET 8 Preview 4\" \/><\/a><\/p>\n<h2>MSBuild: New, modern terminal build output<\/h2>\n<ul>\n<li>https:\/\/github.com\/dotnet\/msbuild\/issues\/8370<\/li>\n<\/ul>\n<p>We often get feedback from users that the default MSBuild output (internally known as the console logger) is difficult to parse. It&#8217;s pretty static, often is a wall of text, and it emits errors as they are triggered during the build instead of logically showing them as part of the project being built. We think these are all great feedback, and are happy to introduce our first iteration on a newer, more modern take on MSBuild output logging. We&#8217;re calling it Terminal Logger, and it has a few main goals:<\/p>\n<ul>\n<li>Logically group errors with the project they belong with<\/li>\n<li>Present projects\/builds in a way that users think of the build (especially multi-targeted projects)<\/li>\n<li>Better differentiate the TargetFrameworks a project builds for<\/li>\n<li>Continue to provide at-a-glance information about the outputs of a project<\/li>\n<li>Provide information about what the build is doing <em>right now<\/em> over the course of a build.<\/li>\n<\/ul>\n<p>Here&#8217;s what it looks like:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/modernbuildoutput.gif\" alt=\"Screenshot showing console build output\" \/><\/p>\n<p>The new output can be enabled using <code>\/tl<\/code>, optionally with one of the following options:<\/p>\n<ul>\n<li><code>auto<\/code> &#8211; the default, which checks if the terminal is capable of using the new features and isn&#8217;t using a redirected standard output before enabling the new logger,<\/li>\n<li><code>on<\/code> &#8211; overrides the environment detection mentioned above and forces the new logger to be used<\/li>\n<li><code>off<\/code> &#8211; overrides the environment detection mentioned above and forces the previous console logger to be used<\/li>\n<\/ul>\n<p>Once enabled, the new logger shows you the restore phase, followed by the build phase. During each phase, the currently-building projects are at the bottom of the terminal, and each building project tells you both the MSBuild Target currently being built, as well as the amount of time spent on that target. We hope this information makes builds less mysterious to users, as well as giving them a place to start searches when they want to learn more about the build! As projects are fully built, a single &#8216;build completed&#8217; section is written for each build that captures <\/p>\n<ul>\n<li>The name of the built project<\/li>\n<li>The Target Framework (if multitargeted!)<\/li>\n<li>The status of that build<\/li>\n<li>The primary output of that build (hyperlinked for quick access)<\/li>\n<li>And finally any diagnostics generated by the build <em>for that project<\/em><\/li>\n<\/ul>\n<p>There weren&#8217;t any diagnostics for that example &#8211; let&#8217;s look at another build of the same project where a typo has been introduced:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/modernbuildoutputdiagnostics.gif\" alt=\"Screenshot showing console output with error diagnostics\" \/><\/p>\n<p>Here you can clearly see the project and typo error outlined.<\/p>\n<p>We think that this layout fits the modern feel of .NET and makes use of the capabilities of modern terminals to tell users more about their builds. We hope you&#8217;ll try it out and provide us feedback on how it works for you, as well as other information you&#8217;d like to see here. We hope to use this logger as the foundation for a new batch of UX improvements for MSBuild &#8211; including aspects like progress reporting and structured errors in the future!  As you use it, please give us feedback via <a href=\"https:\/\/aka.ms\/msbuild\/terminal-logger-survey\">this survey<\/a>, or via the <a href=\"https:\/\/github.com\/dotnet\/msbuild\/discussions\">Discussions<\/a> section of the MSBuild repository. We look forward to hearing from you all!<\/p>\n<p>This work was inspired and begun by Eduardo Villalpando, our intern for the Winter season, who dug into the problem and really helped blaze a trail for the rest of us to follow. It wouldn&#8217;t have been possible without his help and enthusiasm for the problem!<\/p>\n<h2>SDK: Simplified output path updates<\/h2>\n<ul>\n<li>https:\/\/github.com\/dotnet\/designs\/pull\/281<\/li>\n<li>https:\/\/github.com\/dotnet\/sdk\/pull\/31955<\/li>\n<\/ul>\n<p>In <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-3\/#simplified-output-path\">preview 3<\/a> we announced the new simplified output path layout for .NET SDK projects and asked you for your feedback and experiences using the new layout. Thank you for doing so! Your feedback spawned many discussions and based on what we heard from everyone trialing the changes we&#8217;ve made the following updates to the feature:<\/p>\n<ul>\n<li>The default path for the new layout is changing from <code>.artifacts<\/code> to <code>artifacts<\/code><\/li>\n<li>We&#8217;re removing the ability to use the feature from Project files instead of Directory.Build.props<\/li>\n<li>We&#8217;re making it easier to get started with the feature by including the required properties as an option on the <code>buildprops<\/code> template for <code>dotnet new<\/code><\/li>\n<\/ul>\n<p>I want to go into the thought process that led us to these changes. You all <em>overwhelmingly<\/em> supported removing the <code>.<\/code> from the folder name, mostly for visiblity on unix-systems, where <code>.<\/code> usually signifies a &#8216;hidden&#8217; file or folder. So we knew we wanted to make that change. However, there were two main reasons we didn&#8217;t want to use <code>artifacts<\/code> as the root path initially &#8211; <\/p>\n<ul>\n<li>.gitignore support<\/li>\n<li>.NET SDK file globbing hurdles<\/li>\n<\/ul>\n<p>We didn&#8217;t want people to suddenly have to deal with changes to their <code>.gitignore<\/code> files just to try out the feature, but after some research we discovered that some future-facing, enterprising contributor (thanks @sayedihashimi!) already made sure that <code>artifacts<\/code> is in all of the common templates for <code>.gitignore<\/code> files. This means that we didn&#8217;t have to worry about users checking in binaries unexpectedly. <\/p>\n<p>We also didn&#8217;t want to accidentally include the <code>artifacts<\/code> outputs in the default glob patterns that the .NET SDK uses to find the source files to build in a project. If we changed the root path from <code>.artifacts<\/code> to <code>artifacts<\/code> and let users use the new features from the Project-file level, then we would <em>also<\/em> have to go change all of the default includes that make SDK project files so succinct. This seemed very error prone, and frankly a pit of failure in the user experience. As a result, we&#8217;ve tightened the requirements to use the feature &#8211; you now <em>must<\/em> opt into the feature via Directory.Build.props file. This has the side effect of making the feature more stable. Before this change, the inferred root folder location would change when a Directory.Build.props file was created. Now, because a Directory.Build.props must exist, the location of the Artifacts path should remain stable.<\/p>\n<p>To try out the new version of the feature, we&#8217;ve made it easier to generate the correct Directory.Build.props file: just run <code>dotnet new buildprops --use-artifacts<\/code> and we&#8217;ll generate all you need. The generated Directory.Build.props file looks like this:<\/p>\n<pre><code class=\"language-xml\">&lt;Project&gt;\r\n  &lt;!-- See https:\/\/aka.ms\/dotnet\/msbuild\/customize for more details on customizing your build --&gt;\r\n  &lt;PropertyGroup&gt;\r\n    &lt;ArtifactsPath&gt;$(MSBuildThisFileDirectory)artifacts&lt;\/ArtifactsPath&gt;\r\n  &lt;\/PropertyGroup&gt;\r\n&lt;\/Project&gt;<\/code><\/pre>\n<p>Please go try out these changes and continue to let us know what you think at <a href=\"https:\/\/aka.ms\/dotnet\/sdk\/simplified-output-path-survey\">our survey for the feature<\/a>.<\/p>\n<h2>Template Engine: secure experience with packages from Nuget.org<\/h2>\n<p>In .NET 8 we&#8217;re integrating several of NuGet.org&#8217;s security-related features into the Template Engine, especially in the <code>dotnet new<\/code> experience.<\/p>\n<h3>Improvements<\/h3>\n<ul>\n<li>Prevent downloading packages from <code>http:\\\\<\/code> feeds, but allow overrides with the <code>--force<\/code> flag<\/li>\n<\/ul>\n<p>The NuGet team has a plan of record for gradually moving over to a secure-by-default stance. You can read more about their plan, and the timelines involved, in the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/https-everywhere\/\">HTTPS Everywhere<\/a> blog post. In support of that goal, we&#8217;re going to start erroring by default when a non-HTTPS source is used. This can be overriden with <code>--force<\/code> for the .NET 8 time frame, but the current plan is to remove this flag for the .NET 9 time frame, in line with the HTTPS Everywhere timeline.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/securetemplate1.png\" alt=\"Screenshot of terminal output showing an error message when http source is used.\" \/><\/p>\n<ul>\n<li>\n<p>Notify a customer if a template package has any vulnerabilities on install\/update\/outdated checks, and require <code>--force<\/code> to install vulnerable versions\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/securetemplate2.png\" alt=\"Screenshot of terminal output showing vulnerability warnings for insecure template packages\" \/><\/p>\n<\/li>\n<li>\n<p>Add data to the search and uninstall commands that shows if a template is installed from a package that has <a href=\"https:\/\/learn.microsoft.com\/nuget\/nuget-org\/id-prefix-reservation\">prefix reserved<\/a> in NuGet.org\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/securetemplate3.png\" alt=\"Screenshot of terminal output showing checkmark indication of trusted packages\" \/><\/p>\n<\/li>\n<li>\n<p>Add information about the template package owner. The <a href=\"https:\/\/learn.microsoft.com\/nuget\/nuget-org\/id-prefix-reservation\">ownership<\/a> is verified by nuget portal and can be considered a trustworthy characteristic.\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/securetemplate4.png\" alt=\"Screenshot of terminal showing template owner information\" \/><\/p>\n<\/li>\n<\/ul>\n<h2>NuGet: signed package verification on Linux<\/h2>\n<p>Starting with .NET 8 Preview 4 SDK, NuGet will <a href=\"https:\/\/learn.microsoft.com\/nuget\/reference\/signed-packages-reference\">verify signed packages <\/a> on Linux by default.  Verification remains enabled on Windows and disabled on macOS.<\/p>\n<p>For most Linux users, <a href=\"https:\/\/github.com\/dotnet\/sdk\/blob\/main\/src\/Layout\/redist\/trustedroots\/README.md\">verification should just work transparently<\/a>.  However, users with an existing root certificate bundle located at <code>\/etc\/pki\/ca-trust\/extracted\/pem\/objsign-ca-bundle.pem<\/code> may see trust failures accompanied by <a href=\"https:\/\/learn.microsoft.com\/nuget\/reference\/errors-and-warnings\/nu3042\">NU3042<\/a>.<\/p>\n<p>Users can opt out of verification by setting the environment variable <code>DOTNET_NUGET_SIGNATURE_VERIFICATION<\/code> to <code>false<\/code>. Please give your <a href=\"https:\/\/github.com\/NuGet\/Home\/issues\">feedback to help the NuGet team improve the experience on Linux!<\/a><\/p>\n<p>For more information, see https:\/\/github.com\/dotnet\/core\/issues\/7688.<\/p>\n<h2>NuGet: Auditing package dependencies for security vulnerabilities<\/h2>\n<ul>\n<li>https:\/\/github.com\/NuGet\/Home\/issues\/8087<\/li>\n<li>https:\/\/github.com\/NuGet\/Home\/pull\/12310<\/li>\n<\/ul>\n<p><code>dotnet restore<\/code> will produce a report of security vulnerabilities with the affected package name, the severity of the vulnerability, and a link to the advisory for more details when you opt-in to NuGet security auditing.<\/p>\n<h2>Enabling security auditing<\/h2>\n<p>At any time you wish to receive security audit reports, you can opt-in to the experience by setting the following MSBuild property in a <code>.csproj<\/code> or MSBuild file being evaluated as part of your project:<\/p>\n<pre><code class=\"language-xml\">&lt;NuGetAudit&gt;true&lt;\/NuGetAudit&gt;<\/code><\/pre>\n<p>Additionally, ensure that you have the NuGet.org central registry defined as one of your package sources to retrieve the known vulnerability dataset:<\/p>\n<pre><code class=\"language-xml\">&lt;packageSources&gt;\r\n    &lt;add key=\"nuget.org\" value=\"https:\/\/api.nuget.org\/v3\/index.json\" protocolVersion=\"3\" \/&gt;\r\n&lt;\/packageSources&gt;<\/code><\/pre>\n<h2>dotnet add package<\/h2>\n<p>When you try to add a package that has a known vulnerability, <code>dotnet restore<\/code> will be run implicitly and let you know through a warning.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/nugetaudit1.png\" alt=\"Screenshot of terminal showing warning when adding an insecure package\" \/><\/p>\n<h2>dotnet restore<\/h2>\n<p>When you restore your packages through <code>dotnet restore<\/code>, you will see warnings for each affected package and advisory.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/nugetaudit2.png\" alt=\"Screenshot of terminal window showing warnings for insecure packages after calling dotnet restore\" \/><\/p>\n<h2>Warning codes<\/h2>\n<table>\n<thead>\n<tr>\n<th>Warning Code<\/th>\n<th>Severity<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>NU1901<\/td>\n<td>low<\/td>\n<\/tr>\n<tr>\n<td>NU1902<\/td>\n<td>moderate<\/td>\n<\/tr>\n<tr>\n<td>NU1903<\/td>\n<td>high<\/td>\n<\/tr>\n<tr>\n<td>NU1904<\/td>\n<td>critical<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Setting a security audit level<\/h2>\n<p>You can set the <code>&lt;NuGetAuditLevel&gt;<\/code> MSBuild property to the desired level in which auditing will fail. Possible values are <code>low<\/code>, <code>moderate<\/code>, <code>high<\/code>, and <code>critical<\/code>. For example if you only want to see <code>moderate<\/code>, <code>high<\/code>, and <code>critical<\/code> advisories, you can set the following:<\/p>\n<pre><code class=\"language-xml\">&lt;NuGetAuditLevel&gt;moderate&lt;\/NuGetAuditLevel&gt;<\/code><\/pre>\n<h2>Libraries: UTF8 improvements<\/h2>\n<p>With .NET 8 Preview 4, we&#8217;ve introduced the new <code>IUtf8SpanFormattable<\/code> interface, which like its <code>ISpanFormattable<\/code> cousin, can be implemented on a type to enable writing out a string-like representation of that type to a destination span. Whereas <code>ISpanFormattable<\/code> targets UTF16 and <code>Span&lt;char&gt;<\/code>, <code>IUtf8SpanFormattable<\/code> targets UTF8 and <code>Span&lt;byte&gt;<\/code>.  It&#8217;s also been implemented on all of the primitive types (plus others), with the exact same shared logic (thanks to static abstract interfaces) whether targeting <code>string<\/code>, <code>Span&lt;char&gt;<\/code>, or <code>Span&lt;byte&gt;<\/code>, which means it has full support for all formats (including the &#8220;B&#8221; binary specifier that&#8217;s also new in .NET 8 Preview 4) and all cultures. This means you can now format directly to UTF8 from <code>Byte<\/code>, <code>Complex<\/code>, <code>Char<\/code>, <code>DateOnly<\/code>, <code>DateTime<\/code>, <code>DateTimeOffset<\/code>, <code>Decimal<\/code>, <code>Double<\/code>, <code>Guid<\/code>, <code>Half<\/code>, <code>IPAddress<\/code>, <code>IPNetwork<\/code>, <code>Int16<\/code>, <code>Int32<\/code>, <code>Int64<\/code>, <code>Int128<\/code>, <code>IntPtr<\/code>, <code>NFloat<\/code>, <code>SByte<\/code>, <code>Single<\/code>, <code>Rune<\/code>, <code>TimeOnly<\/code>, <code>TimeSpan<\/code>, <code>UInt16<\/code>, <code>UInt32<\/code>, <code>UInt64<\/code>, <code>UInt128<\/code>, <code>UIntPtr<\/code>, and <code>Version<\/code>.<\/p>\n<p>In addition, the new <code>Utf8.TryWrite<\/code> methods now provide a UTF8-based counterpart to the existing <code>MemoryExtensions.TryWrite<\/code> UTF16-based methods.  These methods rely on the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/string-interpolation-in-c-10-and-net-6\/\">interpolated string handler support introduced in .NET 6 and C# 10<\/a>, such that you can use interpolated string syntax to format a complex expression directly into a span of UTF8 bytes, e.g.<\/p>\n<pre><code class=\"language-C#\">static bool FormatHexVersion(short major, short minor, short build, short revision, Span&lt;byte&gt; utf8Bytes, out int bytesWritten) =&gt;\r\n    Utf8.TryWrite(utf8Bytes, CultureInfo.InvariantCulture, $\"{major:X4}.{minor:X4}.{build:X4}.{revision:X4}\", out bytesWritten);<\/code><\/pre>\n<p>The implementation recognizes <code>IUtf8SpanFormattable<\/code> on the format values and uses their implementations to write their UTF8 representations directly to the destination span.<\/p>\n<p>The implementation also utilizes the new <code>Encoding.TryGetBytes<\/code> method, which along with its <code>Encoding.TryGetChars<\/code> counterpart, supports encoding\/decoding into a destination span as long as the span is long enough to hold the resulting state, and returning false rather than throwing an exception if it&#8217;s not.<\/p>\n<p>We expect more UTF8 improvements, including but not limited to improvements to the performance of this functionality, to show up in subsequent .NET 8 previews.<\/p>\n<h2>Introducing Time abstraction<\/h2>\n<p>The introduction of the <strong>TimeProvider<\/strong> abstract class adds time abstraction, which enables time mocking in test scenarios. This functionality is also supported by other features that rely on time progression, such as <code>Task.Delay<\/code> and <code>Task.Async<\/code>. This means that even Task operations can be easily mocked using the time abstraction. The abstraction supports essential time operations such as retrieving local and UTC time, obtaining a timestamp for performance measurement, and creating timers. <\/p>\n<pre><code class=\"language-C#\">public abstract class TimeProvider\r\n{\r\n    public static TimeProvider System { get; }\r\n    protected TimeProvider() \r\n    public virtual DateTimeOffset GetUtcNow()\r\n    public DateTimeOffset GetLocalNow()\r\n    public virtual TimeZoneInfo LocalTimeZone { get; }\r\n    public virtual long TimestampFrequency { get; }\r\n    public virtual long GetTimestamp()\r\n    public TimeSpan GetElapsedTime(long startingTimestamp)\r\n    public TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp)\r\n    public virtual ITimer CreateTimer(TimerCallback callback, object? state,TimeSpan dueTime, TimeSpan period)\r\n}\r\n\r\npublic interface ITimer : IDisposable, IAsyncDisposable\r\n{\r\n    bool Change(TimeSpan dueTime, TimeSpan period);\r\n}\r\n\r\npublic partial class CancellationTokenSource : IDisposable\r\n{\r\n    public CancellationTokenSource(TimeSpan delay, TimeProvider timeProvider)\r\n}\r\n\r\npublic sealed partial class PeriodicTimer : IDisposable\r\n{\r\n    public PeriodicTimer(TimeSpan period, TimeProvider timeProvider) \r\n}\r\n\r\npublic partial class Task : IAsyncResult, IDisposable\r\n{\r\n    public static Task Delay(System.TimeSpan delay, System.TimeProvider timeProvider)\r\n    public static Task Delay(System.TimeSpan delay, System.TimeProvider timeProvider, System.Threading.CancellationToken cancellationToken)\r\n\r\n    public Task WaitAsync(TimeSpan timeout, TimeProvider timeProvider)\r\n    public Task WaitAsync(TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken) \r\n}\r\n\r\npublic partial class Task&lt;TResult&gt; : Task\r\n{\r\n    public new Task&lt;TResult&gt; WaitAsync(TimeSpan timeout, TimeProvider timeProvider)\r\n    public new Task&lt;TResult&gt; WaitAsync(TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken) \r\n}<\/code><\/pre>\n<p>Furthermore, we have made the abstraction available in .NET 8.0 and created a netstandard 2.0 library called Microsoft.Bcl.TimeProvider. This enables the use of the abstraction on supported versions of the .NET Framework and earlier versions of .NET.<\/p>\n<pre><code class=\"language-C#\">namespace System.Threading.Tasks\r\n{\r\n    public static class TimeProviderTaskExtensions\r\n    {\r\n        public static Task Delay(this TimeProvider timeProvider, TimeSpan delay, CancellationToken cancellationToken = default) \r\n        public static Task&lt;TResult&gt; WaitAsync&lt;TResult&gt;(this Task&lt;TResult&gt; task, TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken = default)\r\n        public static Tasks.Task WaitAsync(this Task task, TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken = default)\r\n        public static CancellationTokenSource CreateCancellationTokenSource(this TimeProvider timeProvider, TimeSpan delay)\r\n    }\r\n}<\/code><\/pre>\n<h3>Usage Examples<\/h3>\n<pre><code class=\"language-C#\">\/\/  Get System time\r\nDateTimeOffset utcNow= TimeProvider.System.GetUtcNow();\r\nDateTimeOffset localNow = TimeProvider.System.GetLocalNow();\r\n\r\n\/\/ Create a time provider that work with a time zone different than the local time zone \r\nprivate class ZonedTimeProvider : TimeProvider\r\n{\r\n    private TimeZoneInfo _zoneInfo;\r\n    public ZonedTimeProvider(TimeZoneInfo zoneInfo) : base()\r\n    {\r\n        _zoneInfo = zoneInfo ?? TimeZoneInfo.Local;\r\n    }\r\n    public override TimeZoneInfo LocalTimeZone { get =&gt; _zoneInfo; }\r\n    public static TimeProvider FromLocalTimeZone(TimeZoneInfo zoneInfo) =&gt; new ZonedTimeProvider(zoneInfo);\r\n}\r\n\r\n\/\/ Create a time using a time provider \r\nITimer timer = timeProvider.CreateTimer(callBack, state, delay, Timeout.InfiniteTimeSpan);\r\n\r\n\/\/ Measure a period using the system time provider \r\nlong providerTimestamp1 = TimeProvider.System.GetTimestamp();\r\nlong providerTimestamp2 = TimeProvider.System.GetTimestamp();\r\nvar period = GetElapsedTime(providerTimestamp1, providerTimestamp2);<\/code><\/pre>\n<p>https:\/\/github.com\/dotnet\/runtime\/issues\/36617<\/p>\n<h2>System.Runtime.Intrinsics.Vector512 and AVX-512<\/h2>\n<p>SIMD support has been a staple in .NET for many years, since we <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/update-to-simd-support\/\">first introduced<\/a> support back in .NET Framework. In .NET Core 3.0, we <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/hardware-intrinsics-in-net-core\/\">expanded<\/a> that support to include the platform specific hardware intrinsics APIs for x86\/x64. We expanded that again with support for Arm64 in .NET 5 and then by introducing the cross platform hardware intrinsics in .NET 7. .NET 8 is no exception and is continuing to further our support by introducing <code>System.Runtime.Intrinsics.Vector512&lt;T&gt;<\/code> and its acceleration on x86\/x64 hardware with AVX-512 support.<\/p>\n<p><code>AVX-512<\/code> itself brings along several key features of which Preview 4 adds support for the first three. The last is still a work in progress that we hope to share more details around at a future date:<\/p>\n<ul>\n<li>Support for 512-bit vector operations<\/li>\n<li>Support for an additional 16 SIMD registers<\/li>\n<li>Support for additional instructions available for 128-bit, 256-bit, and 512-bit vectors<\/li>\n<li>Support for masked vector operations<\/li>\n<\/ul>\n<p>If you have hardware that supports the functionality, then <code>Vector512.IsHardwareAccelerated<\/code> will now report <code>true<\/code>. We&#8217;ve also exposed several platform specific classes under the <code>System.Runtime.Intrinsics.X86<\/code> namespace including <code>Avx512F<\/code> (Foundational), <code>Avx512BW<\/code> (Byte and Word), <code>Avx512CD<\/code> (Conflict Detection), <code>Avx512DQ<\/code> (Doubleword and Quadword), and <code>Avx512Vbmi<\/code> (Vector Byte Manipulation Instructions). These follow the same general shape\/layout as other ISAs in that they expose an <code>IsSupported<\/code> property and an <code>X64<\/code> nested class for instructions only available to 64-bit processes. Additionally, we now have a <code>VL<\/code> nested class in each that exposes the <code>Avx512VL<\/code> (Vector Length) extensions for the corresponding instruction set.<\/p>\n<p>Because of the second and third key features listed above, even if you don&#8217;t explicitly use <code>Vector512<\/code> or <code>Avx512F<\/code> specific instructions in your code, you will likely still benefit from this feature. This is because the JIT is able to take advantage of the features implicitly when using <code>Vector128&lt;T&gt;<\/code> or <code>Vector256&lt;T&gt;<\/code>, which includes all the places in the BCL that use hardware intrinsics internally, such as most operations exposed by <code>Span&lt;T&gt;<\/code> and <code>ReadOnlySpan&lt;T&gt;<\/code>, many of the math APIs exposed for the primitive types, and much more.<\/p>\n<p>This feature has had many <a href=\"https:\/\/github.com\/dotnet\/runtime\/pulls?q=is%3Apr+label%3Aarch-avx512+is%3Aclosed+\">Pull Requests<\/a> go into it and it is the result of the work of many, particularly https:\/\/github.com\/anthonycanino, https:\/\/github.com\/DeepakRajendrakumaran, and https:\/\/github.com\/jkrishnavs.<\/p>\n<h2>Native AOT improvements<\/h2>\n<p>We&#8217;ve updated the default <code>console<\/code> template and added support for AOT out of the box. It&#8217;s now possible to invoke <code>dotnet new console --aot<\/code> to create a project that is configured for AOT compilation. The project configuration added by <code>--aot<\/code> has three effects:<\/p>\n<ul>\n<li>Publishing the project with e.g. <code>dotnet publish<\/code> or with Visual Studio will generate a native self-contained executable with native AOT.<\/li>\n<li>It will enable Roslyn-based compatibility analyzers for trimming, AOT, and single file that will mark potentially problematic parts of your project (if there are any) in your editor of choice.<\/li>\n<li>It will enable debug-time emulation of AOT so that when debugging your project without AOT compilation, you get a similar experience to AOT. This makes sure that e.g. use of Reflection.Emit in a NuGet package that wasn&#8217;t annotated for AOT (and was therefore missed by the compatibility analyzer) won&#8217;t surprise you when you try to publish the project with AOT for the first time.<\/li>\n<\/ul>\n<p>We also continue improving fundamentals like runtime throughput, memory use, and size on disk with Native AOT. In Preview 4 we&#8217;re adding a way to communicate an <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/deploying\/native-aot\/optimizing\">optimization preference<\/a> such as Speed or Size. The default settings try to strike the right balance between these two, but we&#8217;re now also introducing a way to specify which way to make tradeoffs.<\/p>\n<p>For example, optimizing the result of <code>dotnet new console --aot<\/code> for size on x64 Windows results in following savings in Preview 4:<\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Default<\/th>\n<th>Optimize for Size<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Hello World<\/td>\n<td>1.20 MB<\/td>\n<td>1.07 MB<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The above is the size of a fully self-contained application that includes the runtime (including GC) and all necessary class libraries.<\/p>\n<p>In Preview 4, we observed that optimizing for speed produces 2-3% improvements in throughput for real world workloads.<\/p>\n<h2>Linux distro version support<\/h2>\n<p>We <a href=\"https:\/\/github.com\/dotnet\/core\/issues\/8133#issuecomment-1432611595\">previously announced<\/a> that we were updating our <a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/8.0\/supported-os.md#linux\">supported Linux distro versions for .NET 8<\/a>. These changes are included in Preview 4, specifically the <code>glibc<\/code> version .NET 8 targets.<\/p>\n<p>.NET 8 is <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/83428\">built targeting Ubuntu 16.04<\/a>, for all architectures. That&#8217;s primarily important for defining the minimum <code>glibc<\/code> version for .NET 8. .NET 8 will fail to start on distro versions that include an older <code>glibc<\/code>, such as Ubuntu 14.04 or Red Hat Enterprise Linux 7.<\/p>\n<p>We are also in the process of updating the .NET 8 Linux build to use <a href=\"https:\/\/www.phoronix.com\/news\/LLVM-16.0-Released\">clang 16<\/a>. We expect that change to be included in Preview 5. We won&#8217;t make a separate announcement for that change.<\/p>\n<p>There are no other significant changes. We will continue to support .NET on Linux on Arm32, Arm64, and x64 architectures.<\/p>\n<h2>System.Text.Json: Populating read-only members<\/h2>\n<p>Starting with .NET 8 Preview 4, System.Text.Json introduces the ability to deserialize onto read-only properties or fields.<\/p>\n<p>We&#8217;ve also introduced option which allows developers to enable it for all properties which are capable of populating &#8211; for example custom converters might not be compatible with this feature:<\/p>\n<pre><code class=\"language-csharp\">JsonSerializerOptions options = new()\r\n{\r\n  PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate\r\n};<\/code><\/pre>\n<p>For existing applications which would like to use this feature but compatibility is a concern this can also be enabled granularly by placing <code>[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]<\/code> attribute on type which properties are to be populated.<\/p>\n<p>For example, to enable populating for all properties of a specific class:<\/p>\n<pre><code class=\"language-csharp\">using System.Text.Json;\r\nusing System.Text.Json.Serialization;\r\n\r\nJsonSerializerOptions options = new()\r\n{\r\n    WriteIndented = true,\r\n    \/\/ Instead of granular control we could also enable this globally like this:\r\n    \/\/ PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate\r\n};\r\n\r\nCustomerInfo customer = JsonSerializer.Deserialize&lt;CustomerInfo&gt;(\"\"\"{\"Person\":{\"Name\":\"John\"},\"Company\":{\"Name\":\"John and Son\"}}\"\"\", options)!;\r\n\r\nConsole.WriteLine(JsonSerializer.Serialize(customer, options));\r\n\r\nclass PersonInfo\r\n{\r\n    \/\/ there is nothing here to be populated since string cannot be re-used\r\n    public required string Name { get; set; }\r\n    public string? Title { get; set; }\r\n}\r\n\r\nclass CompanyInfo\r\n{\r\n    public required string Name { get; set; }\r\n    public string? Address { get; set; }\r\n    public string? PhoneNumber { get; set; }\r\n    public string? Email { get; set; }\r\n}\r\n\r\n\/\/ notes:\r\n\/\/ - attribute does not apply to the `CustomerInfo` class itself: i.e. properties of type `CustomerInfo` wouldn't be auto-populated\r\n\/\/     - automatic rules like these can be implemented with contract customization\r\n\/\/ - attribute do apply to `Person` and `Company` properties\r\n\/\/ - attribute can also be placed on individual properties\r\n[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]\r\nclass CustomerInfo\r\n{\r\n    private const string NA = \"N\/A\";\r\n\r\n    \/\/ note how neither of these have setters\r\n    public PersonInfo Person { get; } = new PersonInfo() { Name = \"Anonymous\", Title = \"Software Developer\" };\r\n    public CompanyInfo Company { get; } = new CompanyInfo() { Name = NA, Address = NA, PhoneNumber = NA, Email = NA };\r\n}<\/code><\/pre>\n<p>The output of above is identical output to that which would be achieved by global option:<\/p>\n<pre><code class=\"language-json\">{\r\n  \"Person\": {\r\n    \"Name\": \"John\",\r\n    \"Title\": \"Software Developer\"\r\n  },\r\n  \"Company\": {\r\n    \"Name\": \"John and Son\",\r\n    \"Address\": \"N\/A\",\r\n    \"PhoneNumber\": \"N\/A\",\r\n    \"Email\": \"N\/A\"\r\n  }\r\n}<\/code><\/pre>\n<p>for comparison previously we&#8217;d see our input but since there was no settable property <code>Person<\/code> or <code>Company<\/code> to deserialize into we&#8217;d ignore input completely and output would only show default values:<\/p>\n<pre><code class=\"language-json\">{\r\n  \"Person\": {\r\n    \"Name\": \"Anonymous\",\r\n    \"Title\": \"Software Developer\"\r\n  },\r\n  \"Company\": {\r\n    \"Name\": \"N\/A\",\r\n    \"Address\": \"N\/A\",\r\n    \"PhoneNumber\": \"N\/A\",\r\n    \"Email\": \"N\/A\"\r\n  }\r\n}<\/code><\/pre>\n<h3>Other notes for populating read-only members<\/h3>\n<ul>\n<li>For more information see original issue with the design: https:\/\/github.com\/dotnet\/runtime\/issues\/78556<\/li>\n<li>Structs can also be populated but population happens by first creating a copy and then setting it back to the property and therefore such properties also require a setters<\/li>\n<li>Populating of collections happens in additive manner &#8211; existing collection with all its content is treated as original object and therefore all existing elements are preserved &#8211; this behavior can be changed with contract customization and\/or deserialization callbacks<\/li>\n<\/ul>\n<h2>System.Text.Json Improvements<\/h2>\n<h3><code>JsonSerializer.IsReflectionEnabledByDefault<\/code><\/h3>\n<ul>\n<li>https:\/\/github.com\/dotnet\/runtime\/pull\/83844<\/li>\n<\/ul>\n<p>The <code>JsonSerializer<\/code> class exposes a number of serialization and deserialization methods that accept an optional <code>JsonSerializerOptions<\/code> parameter. If left unspecified, these methods will default to using the reflection-based serializer. In the context of trimmed\/Native AOT applications, this default can create issues with respect to application size: even if the user takes care to pass a source generated <code>JsonSerializerOptions<\/code> value, it will still result in the reflection components being rooted by the trimmer.<\/p>\n<p>System.Text.Json now ships with the <code>System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault<\/code> feature switch that controls default behavior of the <code>JsonSerializer<\/code> methods. Setting the switch to <code>false<\/code> at publish time now avoids accidental rooting of reflection components. It should be noted that with the switch disabled this code<\/p>\n<pre><code class=\"language-C#\">JsonSerializer.Serialize(new { Value = 42 });<\/code><\/pre>\n<p>will now fail with a <code>NotSupportedException<\/code>. A configured <code>JsonSerializerOptions<\/code> will need to be passed explicitly for the method to work.<\/p>\n<p>Furthermore, the value of the feature switch is reflected in the <code>JsonSerializer.IsReflectionEnabledByDefault<\/code> property which is treated as a link-time constant. Library authors building on top of System.Text.Json can rely on the property to configure their defaults without accidentally rooting reflection components:<\/p>\n<pre><code class=\"language-C#\">static JsonSerializerOptions GetDefaultOptions()\r\n{\r\n    if (JsonSerializer.IsReflectionEnabledByDefault)\r\n    {\r\n        \/\/ This branch has a dependency on DefaultJsonTypeInfo\r\n        \/\/ but will get trimmed away by the linker if the feature switch is disabled.\r\n        return new JsonSerializerOptions\r\n        {\r\n              TypeInfoResolver = new DefaultJsonTypeInfoResolver(),\r\n              PropertyNamingPolicy = JsonNamingPolicy.KebabCase,\r\n        }\r\n    }\r\n\r\n    return new() { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower } ;\r\n}<\/code><\/pre>\n<h3><code>JsonSerializerOptions.TypeInfoResolverChain<\/code><\/h3>\n<ul>\n<li>https:\/\/github.com\/dotnet\/runtime\/issues\/83095<\/li>\n<\/ul>\n<p>When shipped in .NET 7, the contract customization feature added support for chaining source generators by means of the <code>JsonTypeInfoResolver.Combine<\/code> method:<\/p>\n<pre><code class=\"language-C#\">var options = new JsonSerializerOptions\r\n{\r\n    TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default);\r\n};<\/code><\/pre>\n<p>Based on feedback we&#8217;ve received, this approach has a couple of usability issues:<\/p>\n<ol>\n<li>It necessitates specifying all chained components at one call site &#8212; resolvers cannot be prepended or appended to the chain after the fact.<\/li>\n<li>Because the chaining implementation is abstracted behind a <code>IJsonTypeInfoResolver<\/code> implementation, there is no way for users to introspect the chain or remove components from it.<\/li>\n<\/ol>\n<p>The <code>JsonSerializerOptions<\/code> class now includes a <code>TypeInfoResolverChain<\/code> property that is complementary to <code>TypeInfoResolver<\/code>:<\/p>\n<pre><code class=\"language-C#\">namespace System.Text.Json;\r\n\r\npublic partial class JsonSerializerOptions\r\n{\r\n    public IJsonTypeInfoResolver? TypeInfoResolver { get; set; }\r\n    public IList&lt;IJsonTypeInfoResolver&gt; TypeInfoResolverChain { get; }\r\n}<\/code><\/pre>\n<p>The options instance as defined in the original example can now be manipulated as follows:<\/p>\n<pre><code class=\"language-C#\">options.TypeInfoResolverChain.Count; \/\/ 3\r\noptions.TypeInfoResolverChain.RemoveAt(0);\r\noptions.TypeInfoResolverChain.Count; \/\/ 2<\/code><\/pre>\n<p>It should be noted that the <code>TypeInfoResolver<\/code> and <code>TypeInfoResolverChain<\/code> properties are always kept in sync, so a change to one property will force an update to the other.<\/p>\n<h3>Obsoleting <code>JsonSerializerOptions.AddContext<\/code><\/h3>\n<ul>\n<li>https:\/\/github.com\/dotnet\/runtime\/issues\/83280<\/li>\n<\/ul>\n<p>The <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.text.json.jsonserializeroptions.addcontext?view=net-8.0\"><code>JsonSerializerOptions.AddContext<\/code><\/a> has been superseded by the <code>TypeInfoResolver<\/code> and <code>TypeInfoResolverChain<\/code> properties, so it is now being marked as obsolete.<\/p>\n<h3>Unspeakable type support<\/h3>\n<ul>\n<li>https:\/\/github.com\/dotnet\/runtime\/issues\/82457<\/li>\n<\/ul>\n<p>Compiler-generated or &#8220;unspeakable&#8221; types have been challenging to support in weakly typed source gen scenaria. In .NET 7, the following application<\/p>\n<pre><code class=\"language-C#\">object value = Test();\r\nJsonSerializer.Serialize(value, MyContext.Default.Options);\r\n\r\nasync IAsyncEnumerable&lt;int&gt; Test()\r\n{\r\n    for (int i = 0; i &lt; 10; i++)\r\n    {\r\n        await Task.Delay(1000);\r\n        yield return i;\r\n    }\r\n}\r\n\r\n[JsonSerializable(typeof(IAsyncEnumerable&lt;int&gt;))]\r\ninternal partial class MyContext : JsonSerializerContext {}<\/code><\/pre>\n<p>fails with the error<\/p>\n<pre><code class=\"language-text\">Metadata for type 'Program+&lt;&lt;&lt;Main&gt;$&gt;g__Test|0_5&gt;d' was not provided by TypeInfoResolver of type 'MyContext'<\/code><\/pre>\n<p>Which is because the compiler-generated type <code>Program+&lt;&lt;&lt;Main&gt;$&gt;g__Test|0_5&gt;d<\/code> cannot be explicitly specified by the source generator.<\/p>\n<p>Starting with Preview 4, System.Text.Json will perform run-time nearest-ancestor resolution to determine the most appropriate supertype with which to serialize the value (in this case, <code>IAsyncEnumerable&lt;int&gt;<\/code>).<\/p>\n<h3><code>JsonSerializerOptions.TryGetTypeInfo<\/code><\/h3>\n<ul>\n<li>https:\/\/github.com\/dotnet\/runtime\/pull\/84411<\/li>\n<\/ul>\n<p>Preview 4 now includes a <code>Try-<\/code> variant of the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.text.json.jsonserializeroptions.gettypeinfo?view=net-8.0\"><code>GetTypeInfo<\/code><\/a> method which returns false if no metadata for the specified type has been found.<\/p>\n<h2>Codegen<\/h2>\n<h3>Consecutive Registers Allocation<\/h3>\n<p>In this preview release, we have introduced a new feature in our register allocator called &#8220;consecutive register&#8221; allocation. Before we delve into the details of what it entails and why it was necessary, let&#8217;s first review what register allocation is and how it works in RyuJIT.<\/p>\n<p>The register allocation algorithm used in RyuJIT is based on a &#8220;Linear Scan&#8221; approach. It scans the program to identify the lifetime of all variables, referred to as &#8220;intervals&#8221; in the literature, and assigns a single register to each variable at each use. To determine the best register to assign at a given point, the algorithm needs to identify which variables are live at that point and do not overlap with other variables. It then selects a register from a set of available free registers, using heuristics to determine the best register set at the point of allocation. If no registers are available because they are all assigned to intervals, the algorithm identifies the best register that can be &#8220;spilled&#8221; and assigned at that location. Spilling involves storing the value of a register on the stack and retrieving it later when needed, which is an expensive operation that the register allocator tries to minimize.<\/p>\n<p>Arm64 has two instructions, <a href=\"https:\/\/developer.arm.com\/documentation\/dui0801\/g\/A64-SIMD-Vector-Instructions\/TBL--vector-\">TBL<\/a> and <a href=\"https:\/\/developer.arm.com\/documentation\/dui0801\/g\/A64-SIMD-Vector-Instructions\/TBX--vector-\">TBX<\/a>, which are used for table vector lookup. These instructions take a &#8220;tuple&#8221; as one of their operands, which can contain 2, 3, or 4 entities. In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/80297\">PR# 80297<\/a>, we added two sets of APIs, VectorTableLookup and VectorTableLookupExtension, under the AdvSimd namespace for these instructions. However, these instructions require that all entities in the tuple are present in consecutive registers. To better understand this requirement, let&#8217;s look at an example.<\/p>\n<pre><code class=\"language-c#\">public static Vector128&lt;byte&gt; Test(float f)\r\n{\r\n        var a = Produce1();\r\n        var b = Produce2();\r\n        var c = a + b;      \r\n        var d = c + a;      \r\n        var e = d + b;     \r\n        d = AdvSimd.Arm64.VectorTableLookup((d, e, e, b), c); \r\n}<\/code><\/pre>\n<p>Here is the generated code for the method.<\/p>\n<pre><code class=\"language-asm\">            movz    x0, #0xD1FFAB1E      \/\/ code for helloworld:Produce1():System.Runtime.Intrinsics.Vector128`1[ubyte]\r\n            movk    x0, #0xD1FFAB1E LSL #16\r\n            movk    x0, #0xD1FFAB1E LSL #32\r\n            ldr     x0, [x0]\r\n            blr     x0\r\n            str     q0, [fp, #0x20] \/\/ [V01 loc0]\r\n            movz    x0, #0xD1FFAB1E      \/\/ code for helloworld:Produce2():System.Runtime.Intrinsics.Vector128`1[ubyte]\r\n            movk    x0, #0xD1FFAB1E LSL #16\r\n            movk    x0, #0xD1FFAB1E LSL #32\r\n            ldr     x0, [x0]\r\n            blr     x0\r\n            ldr     q16, [fp, #0x20]    \/\/ [V01 loc0]\r\n            add     v17.16b, v16.16b, v0.16b\r\n            str     q17, [fp, #0x10]    \/\/ [V03 loc2]\r\n            add     v16.16b, v17.16b, v16.16b\r\n            add     v18.16b, v16.16b, v0.16b\r\n            mov     v17.16b, v18.16b\r\n            mov     v19.16b, v0.16b\r\n            ldr     q20, [fp, #0x10]    \/\/ [V03 loc2]\r\n            tbl     v16.16b, {v16.16b, v17.16b, v18.16b, v19.16b}, v20.16b\r\n            add     v0.16b, v0.16b, v16.16b\r\n<\/code><\/pre>\n<p>In the given example, VectorTableLookup() takes a tuple consisting of 4 vectors d, e, e, and b, which are passed in consecutive registers v16 through v19. Even though the 2nd and 3rd value are the same variable e, they are still passed in different registers v17 and v18. This introduces the complexity of finding not only multiple free (or busy) registers (2, 3, or 4) for instructions tbl and tbx, but also consecutive registers. In order to accommodate this new requirement, our algorithm had to be updated at various stages, such as checking ahead of time if consecutive registers are free when assigning a register to the first entity of the tuple, ensuring that assigned registers are consecutive if the variables are already assigned registers and they are not consecutive, and adding stress testing scenarios to handle alternate registers when available.\nIn <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/85189\">PR #85189<\/a>, @MihaZupan used the VectorTableLookup in ProbabilisticMap\u2019s IndexOf method and got 30% improvement. <\/p>\n<h3>Optimized ThreadStatic field access<\/h3>\n<p>Accessing fields that are marked with <code>ThreadStatic<\/code> had to go through the helper calls which would access the thread local storage (TLS) of current thread and module before accessing the field data. In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/82973\">PR #82973<\/a>, we inlined all that code and with that, the field\u2019s value can be retrieved without going into the helper. This improves the performance of field access by 10X. <\/p>\n<h3>Arm64<\/h3>\n<p>We continued improving the code quality of Arm64 and our friends @SwapnilGaikwad and @a74nh at Arm made some good contributions in this release.<\/p>\n<ul>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84350\">PR #84350<\/a>, pairs of &#8220;str wzr&#8221; were optimized and replaced with &#8220;str xzr&#8221;.<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84135\">PR #84135<\/a>, peephole optimizations of ldp\/stp were enable for SIMD registers.<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83458\">PR #83458<\/a>, a load was replaced with cheaper mov instruction when possible.<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/79283\">PR #79283<\/a>, conditions in if clause were combined with compare chains.<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/82031\">PR #82031<\/a>, started using cinc instead of csel when possible.<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84667\">PR #84667<\/a>, Combine &#8216;neg&#8217; and &#8216;cmp&#8217; to &#8216;cmn&#8217;<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84605\">PR #84605<\/a>, Combine cmp and shift ops into a single cmp op<\/li>\n<li>In <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83694\">PR #83694<\/a>, Add IsVNNeverNegative (improved all arches, but had big impact on ARM64)<\/li>\n<\/ul>\n<p>Until now, the load\/store pair peephole optimization was not performed if one of the values is from local variable. <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84399\">PR #84399<\/a> fixed that limitation and enabled the peephole optimization broadly.<\/p>\n<p><code>&gt;&gt;&gt;<\/code> operator is optimized to ShiftRightLogical intrinsics on Arm64 in <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/85258\">PR#85258<\/a>.<\/p>\n<h3>Community PRs (Many thanks to JIT community contributors!)<\/h3>\n<ul>\n<li>@SingleAccretion contributed <a href=\"https:\/\/github.com\/dotnet\/runtime\/pulls?q=is%3Apr+is%3Amerged+label%3Aarea-CodeGen-coreclr+closed%3A2023-03-21..2023-04-25++-milestone%3A7.0.x+author%3Asingleaccretion\">20 PRs<\/a> in Preview 4. Much of this work focused on internal cleanup and simplifying of the concepts required to be understood by everyone working on the JIT. For example, many node types in the JIT\u2019s internal IR were completely removed in favor of more regular or simpler representations.<\/li>\n<li>@Ruihan-Yin added a macro on zmm registers on LinearScan::buildPhysRegRecords, <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83862\">PR#83862<\/a>.<\/li>\n<li>Please refer CodeGen Arm64 section for the contributions from @a74nh and @SwapnilGaikwad.<\/li>\n<\/ul>\n<h3>Code vectorization<\/h3>\n<p>JIT\/NativeAOT can now unroll and auto-vectorize various memory operations such as comparison, copying and zeroing with SIMD (including AVX-512 instructions on x64!) if it can determinate their sizes in compile time:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83255\">PR#83255<\/a> made stackalloc zeroing 2-3X faster with SIMD<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83638\">PR#83638<\/a>, <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83740\">PR#83740<\/a> and <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84530\">PR#84530<\/a> enabled auto-vectorization for various &#8220;copy buffer&#8221; like operations.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83945\">PR#83945<\/a> did the same for comparisons including SequenceEqual and StartsWith for all types of primitives.\nA good example of a pattern JIT can now auto-vectorize is the following snippet:<\/li>\n<\/ul>\n<pre><code class=\"language-csharp\">bool CopyFirst50Items(ReadOnlySpan&lt;int&gt; src, Span&lt;int&gt; dst) =&gt; \r\n    src.Slice(0, 50).TryCopyTo(dst);\r\n```csharp\r\n```asm\r\n; Method CopyFirst50Items\r\n       push     rbp\r\n       vzeroupper \r\n       mov      rbp, rsp\r\n       cmp      edx, 50 ;; src.Length &gt;= 50 ?\r\n       jb       SHORT G_M1291_IG05\r\n       xor      eax, eax\r\n       cmp      r8d, 50 ;; dst.Length &gt;= 50 ?\r\n       jb       SHORT G_M1291_IG04\r\n       vmovdqu  zmm0, zmmword ptr [rsi]\r\n       vmovdqu  zmm1, zmmword ptr [rsi+40H]\r\n       vmovdqu  zmm2, zmmword ptr [rsi+80H]\r\n       vmovdqu  xmm3, xmmword ptr [rsi+B8H]\r\n       vmovdqu  zmmword ptr [rcx], zmm0\r\n       vmovdqu  zmmword ptr [rcx+40H], zmm1\r\n       vmovdqu  zmmword ptr [rcx+80H], zmm2\r\n       vmovdqu  xmmword ptr [rcx+B8H], xmm3\r\n       mov      eax, 1\r\nG_M1291_IG04:\r\n       pop      rbp\r\n       ret      \r\nG_M1291_IG05:\r\n       call     [System.ThrowHelper:ThrowArgumentOutOfRangeException()]\r\n       int3     \r\n; Total bytes of code: 96<\/code><\/pre>\n<p>Here JIT used 3 ZMM (AVX-512) registers to perform memmove-like operation inlined (even if src and dst overlap). A similar codegen will be generated for compile-time constant data e.g. utf8 literals:<\/p>\n<pre><code class=\"language-csharp\">bool WriteHeader(Span&lt;int&gt; dst) =&gt; \"text\/html\"u8.CopyTo(dst);\r\nbool StartsWithHeader(Span&lt;int&gt; dst) =&gt; dst.StartsWith(\"text\/html\"u8);<\/code><\/pre>\n<h3>General Optimizations<\/h3>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83911\">PR#83911<\/a> Static initializations are now cheaper in NativeAOT.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84213\">PR#84213<\/a> and <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84231\">PR#84231<\/a> improved bound check elimination for <code>arr[arr.Length - cns]<\/code> and <code>arr[index % arr.Length]<\/code> patterns.<\/li>\n<li>Forward substitution optimization is enabled for more cases such as small types, <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/83969\">PR#83969<\/a>.<\/li>\n<li>Improved some cases of spills during register allocation with <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/85251\">PR#85251<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84427\">PR#84427<\/a> improved the scalability of PGO instrumentation<\/li>\n<li>We continued to improve JIT loop optimization capabilities. In preview 4, we improved reachability sets computation, <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84204\">PR#84204<\/a>.<\/li>\n<\/ul>\n<h2>Community spotlight (<a href=\"https:\/\/github.com\/elachlan\">Lachlan Ennis<\/a>)<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/lachlanennis.png\" alt=\"Lachlan Ennis\" \/><\/p>\n<p>My name is Lachlan Ennis and I am a Full Stack Software Developer at Expert1 writing software for small\/medium sized finance companies in Australia.I live in the city of Brisbane in Queensland, Australia. I graduated from QUT (Queensland University of Technology) with a Bachelors in Information Technology, but learnt most of my coding skills on the job. We write out software primarily in .NET using MSSQL. We also use Winforms for our products.<\/p>\n<p>My first contributions to .NET were in dotnet\/msbuild, where I used code analysis to improve code quality and performance. This helped msbuild get closer in line with dotnet\/runtime with its coding standards and enabled code analysis rules. I then moved to working on winforms when I stumbled on an issue discussing the interop layer of winforms and how to improve it. I had previously done some minor work in msbuild around some interop and saw how difficult it could be. I suggested that Winforms use CsWin32 as it used source generators to create the PInvokes as well as friendly overloads. This then led down a rabbit hole of raised issues and PRs in Microsoft\/CsWin32 and Microsoft\/Win32Metadata to get the required APIs made available for Winforms.<\/p>\n<p>After working on the interop changes I moved to the issue queue to help investigate the backlog. Often the issues need someone to drive the investigation until there is enough information for the winforms team to take over, or if it&#8217;s obvious enough a PR to fix the issue. I also helped build on the community effort to null annotate the winforms code base.<\/p>\n<p>Working on dotnet open source software has really helped expand my knowledge in dotnet, C#, and winforms. The Winforms team has been incredibly helpful in that regard with thorough reviews and advice in PRs and issues.<\/p>\n<h2>Summary<\/h2>\n<p>.NET 8 Preview 4 contains exciting new features and improvements that would not be possible without the hard work and dedication of a diverse team of engineers at Microsoft and a passionate open source community. We want to extend our <a href=\"https:\/\/dotnet.microsoft.com\/thanks\">sincere thanks to everyone who has contributed to .NET 8 so far<\/a>, whether it was through code contributions, bug reports, or providing feedback.<\/p>\n<p>Your contributions have been instrumental in the making .NET 8 Previews, and we look forward to continuing to work together to build a brighter future for .NET and the entire technology community.<\/p>\n<p>Curious about what is coming? <a href=\"https:\/\/dotnet.microsoft.com\/next\">Go see what&#8217;s next in .NET!<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 Preview 4 contains many exciting new features for the runtime and libraries, Native AOT improvements, modern build output and simplified paths, NuGet package security auditing, and much more!<\/p>\n","protected":false},"author":551,"featured_media":45954,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7233,7509,327,756,7600],"tags":[7701],"class_list":["post-45686","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-maui","category-aspnetcore","category-azure","category-csharp","category-maintenance-and-updates","tag-dotnet-8"],"acf":[],"blog_post_summary":"<p>.NET 8 Preview 4 contains many exciting new features for the runtime and libraries, Native AOT improvements, modern build output and simplified paths, NuGet package security auditing, and much more!<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/45686","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/551"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=45686"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/45686\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/45954"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=45686"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=45686"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=45686"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}