diff options
author | Ahson Ahmed Khan <ahsonkhan@users.noreply.github.com> | 2017-02-24 17:27:54 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-24 17:27:54 -0800 |
commit | da44463552689930c4d4ead5aa01a437fcbea622 (patch) | |
tree | b2c3028239006e4bec047c5f65dfc2fae975c8bb /src/mscorlib | |
parent | b927ad12373efd5840be34f011bb3c67ab1e156f (diff) | |
parent | ec6fb88e7009457f54f31ba83da915af395f4bd6 (diff) | |
download | coreclr-da44463552689930c4d4ead5aa01a437fcbea622.tar.gz coreclr-da44463552689930c4d4ead5aa01a437fcbea622.tar.bz2 coreclr-da44463552689930c4d4ead5aa01a437fcbea622.zip |
Merge pull request #9598 from ahsonkhan/OptimizeSpanClear
Optimize span clear
Diffstat (limited to 'src/mscorlib')
-rw-r--r-- | src/mscorlib/System.Private.CoreLib.csproj | 81 | ||||
-rw-r--r-- | src/mscorlib/System.Private.CoreLib.sln | 5 | ||||
-rw-r--r-- | src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs | 18 | ||||
-rw-r--r-- | src/mscorlib/src/System/Runtime/RuntimeImports.cs | 32 | ||||
-rw-r--r-- | src/mscorlib/src/System/Span.cs | 369 |
5 files changed, 441 insertions, 64 deletions
diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj index 415d04bd04..d2b443ffbd 100644 --- a/src/mscorlib/System.Private.CoreLib.csproj +++ b/src/mscorlib/System.Private.CoreLib.csproj @@ -1,14 +1,10 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <!-- Always use latest Roslyn compiler --> <Import Project="..\..\Tools\net45\roslyn\build\Microsoft.Net.Compilers.props" Condition="'$(OS)'=='Windows_NT'" /> - <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> - <!-- Include common build properties --> <Import Project="..\..\dir.props" /> - <!-- Compilation options --> <PropertyGroup> <AvailablePlatforms>amd64,x86,arm,armel,arm64</AvailablePlatforms> @@ -19,16 +15,13 @@ <Platform Condition=" '$(Platform)' == 'x64' ">amd64</Platform> <Platform Condition=" '$(Platform)' == 'armel' ">arm</Platform> <ProjectGuid>{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}</ProjectGuid> - <OutputType>Library</OutputType> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <!-- This prevents the default MsBuild targets from referencing System.Core.dll --> <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences> <!-- These prevent the default MsBuild targets from referencing System.dll and mscorlib.dll --> <NoStdLib>true</NoStdLib> <NoCompilerStandardLib>true</NoCompilerStandardLib> - <SubsystemVersion>6.00</SubsystemVersion> <UTF8OutPut>true</UTF8OutPut> <HighEntropyVA>true</HighEntropyVA> @@ -39,20 +32,16 @@ <WarningsNotAsErrors>$(WarningsNotAsErrors);618</WarningsNotAsErrors> <NoWarn>649,3019,414,169,3015</NoWarn> <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute> - <SignAssembly>true</SignAssembly> <DelaySign>true</DelaySign> - <DefineConstants>$(DefineConstants);CORECLR;_USE_NLS_PLUS_TABLE;RESOURCE_SATELLITE_CONFIG;INSIDE_CLR;CODE_ANALYSIS_BASELINE</DefineConstants> </PropertyGroup> - <!-- Add Serviceable attribute to the project's metadata --> <ItemGroup> <AssemblyMetadata Include="Serviceable"> - <Value>True</Value> + <Value>True</Value> </AssemblyMetadata> </ItemGroup> - <!-- Platform specific properties --> <PropertyGroup Condition="'$(Platform)' == 'amd64'"> <PlatformTarget>x64</PlatformTarget> @@ -73,7 +62,6 @@ <PlatformTarget>AnyCPU</PlatformTarget> <DefineConstants>BIT64;ARM64;$(DefineConstants)</DefineConstants> </PropertyGroup> - <!-- Configuration specific properties --> <PropertyGroup Condition="'$(Configuration)' == 'Debug' or '$(Configuration)' == 'Checked'"> <DebugSymbols>true</DebugSymbols> @@ -89,13 +77,11 @@ <DebugType>pdbOnly</DebugType> <DefineConstants>TRACE;$(DefineConstants)</DefineConstants> </PropertyGroup> - <!-- Roslyn does not support writing PDBs on Unix --> <PropertyGroup Condition="'$(OsEnvironment)' == 'Unix'"> <DebugSymbols>false</DebugSymbols> <DebugType>none</DebugType> </PropertyGroup> - <!-- Assembly attributes --> <PropertyGroup> <AssemblyName>System.Private.CoreLib</AssemblyName> @@ -109,7 +95,6 @@ <AssemblyInfoLines Include="[assembly: System.Runtime.InteropServices.ComVisible(false)]" /> <AssemblyInfoLines Include="[assembly: System.Resources.NeutralResourcesLanguage("en-US")]" /> </ItemGroup> - <!-- Helper Paths --> @@ -120,21 +105,17 @@ <MscorlibDir>$(MSBuildThisFileDirectory)</MscorlibDir> <NlpObjDir>$(BclSourcesRoot)\System\Globalization\Tables</NlpObjDir> </PropertyGroup> - <!-- Msbuild variables needed to get CoreCLR features to be set properly. --> <PropertyGroup> <ClrProduct>core_clr</ClrProduct> <BuildForCoreSystem>true</BuildForCoreSystem> - <!-- These are needed to make sure we have the right set of defines --> <TargetArch Condition="'$(Platform)'=='x86'">i386</TargetArch> <TargetArch Condition="'$(Platform)'!='x86'">$(Platform)</TargetArch> </PropertyGroup> - <!-- CLR Features --> <Import Project="$(MSBuildThisFileDirectory)..\..\clr.coreclr.props" /> <Import Project="$(MSBuildThisFileDirectory)..\..\clr.defines.targets" /> - <!-- Sources --> <ItemGroup> <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\AccessedThroughPropertyAttribute.cs" /> @@ -325,15 +306,15 @@ <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\RuntimeClass.cs" /> </ItemGroup> <ItemGroup Condition="'$(FeatureCominterop)' == 'true'"> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\CLRIPropertyValueImpl.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\CLRIReferenceImpl.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\IPropertyValue.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\IReference.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\WindowsFoundationEventHandler.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\ICustomPropertyProvider.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\ICustomProperty.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\CustomPropertyImpl.cs' /> - <MscorlibSources Include='$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\WindowsRuntimeBufferHelper.cs' /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\CLRIPropertyValueImpl.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\CLRIReferenceImpl.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\IPropertyValue.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\IReference.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\WindowsFoundationEventHandler.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\ICustomPropertyProvider.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\ICustomProperty.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\CustomPropertyImpl.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\WindowsRuntimeBufferHelper.cs" /> </ItemGroup> <ItemGroup Condition="'$(FeatureCominterop)' == 'true'"> <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\InteropServices\WindowsRuntime\IIterable.cs" /> @@ -761,7 +742,7 @@ <MscorlibSources Include="$(CoreFxSourcesRoot)\System\Globalization\ThaiBuddhistCalendar.cs" /> <MscorlibSources Include="$(CoreFxSourcesRoot)\System\Globalization\TimeSpanStyles.cs" /> <MscorlibSources Include="$(CoreFxSourcesRoot)\System\Globalization\UmAlQuraCalendar.cs" /> - <MscorlibSources Include="$(CoreFxSourcesRoot)\System\Globalization\UnicodeCategory.cs " /> + <MscorlibSources Include="$(CoreFxSourcesRoot)\System\Globalization\UnicodeCategory.cs " /> </ItemGroup> <ItemGroup Condition="'$(FeatureCoreFxGlobalization)' == 'true' and '$(TargetsUnix)' == 'true'"> <MscorlibSources Include="$(BclSourcesRoot)\System\Globalization\EncodingTable.Unix.cs" /> @@ -897,8 +878,8 @@ <MscorlibSources Include="$(BclSourcesRoot)\System\IO\BinaryReader.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\BinaryWriter.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\Directory.cs" /> - <MscorlibSources Include="$(BclSourcesRoot)\System\IO\SearchOption.cs" /> - <MscorlibSources Include="$(BclSourcesRoot)\System\IO\DirectoryNotFoundException.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\IO\SearchOption.cs" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\IO\DirectoryNotFoundException.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\DriveNotFoundException.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\EncodingCache.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\EndOfStreamException.cs" /> @@ -917,7 +898,7 @@ <MscorlibSources Include="$(BclSourcesRoot)\System\IO\SeekOrigin.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\Stream.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\StreamHelpers.CopyValidation.cs" /> - <MscorlibSources Include="$(BclSourcesRoot)\System\IO\TextReader.cs" Condition="'$(TargetsUnix)' == 'true'" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\IO\TextReader.cs" Condition="'$(TargetsUnix)' == 'true'" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\StreamReader.cs" Condition="'$(TargetsUnix)' == 'true'" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryAccessor.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\IO\UnmanagedMemoryStream.cs" /> @@ -1022,7 +1003,7 @@ </ItemGroup> <ItemGroup> <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\Versioning\TargetFrameworkAttribute.cs" /> - <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\Versioning\CompatibilitySwitch.cs" Condition="'$(TargetsUnix)' == 'true'" /> + <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\Versioning\CompatibilitySwitch.cs" Condition="'$(TargetsUnix)' == 'true'" /> <MscorlibSources Include="$(BclSourcesRoot)\System\Runtime\Versioning\NonVersionableAttribute.cs" /> </ItemGroup> <ItemGroup> @@ -1053,7 +1034,7 @@ <MscorlibSources Include="$(BclSourcesRoot)\System\Text\EncodingProvider.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\Text\Latin1Encoding.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\Text\Normalization.cs" /> - <MscorlibSources Include="$(BclSourcesRoot)\System\Text\Normalization.Windows.cs" Condition="'$(TargetsUnix)' != 'true'"/> + <MscorlibSources Include="$(BclSourcesRoot)\System\Text\Normalization.Windows.cs" Condition="'$(TargetsUnix)' != 'true'" /> <MscorlibSources Include="$(BclSourcesRoot)\System\Text\UnicodeEncoding.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\Text\UTF7Encoding.cs" /> <MscorlibSources Include="$(BclSourcesRoot)\System\Text\UTF8Encoding.cs" /> @@ -1213,32 +1194,27 @@ <ItemGroup> <MscorlibSources Include="$(CoreFxSourcesRoot)\Debug.cs" /> </ItemGroup> - <!-- Include additional sources shared files in the compilation --> <ItemGroup> <!-- These are files are preprocessed --> <MscorlibSources Include="$(CommonPath)\Preprocessed\AssemblyRefs.g.cs" /> - <!-- These files are shared with other framework components and don't live the same folder as the rest of them--> <MscorlibSources Include="$(CommonPath)\PinnableBufferCache.cs" /> - <!-- Include Internals visible to file in the compilation --> <MscorlibSources Include="$(BclSourcesRoot)\mscorlib.Friends.cs" /> - <!-- TODO list of types to be cleaned up from CoreLib --> <MscorlibSources Include="$(BclSourcesRoot)\CleanupToDoList.cs" /> </ItemGroup> - <ItemGroup> <!-- We want the sources to show up nicely in VS--> <Compile Include="@(MscorlibSources)"> </Compile> <Compile Include="src\System\Runtime\CompilerServices\ITuple.cs" /> <Compile Include="src\System\Runtime\CompilerServices\TupleElementNamesAttribute.cs" /> + <Compile Include="src\System\Runtime\RuntimeImports.cs" /> <Compile Include="src\System\TupleExtensions.cs" /> <Compile Include="src\System\ValueTuple.cs" /> </ItemGroup> - <!-- Resources --> <ItemGroup> <SplitTextStringResource Include="$(BclSourcesRoot)\System.Private.CoreLib.txt"> @@ -1246,11 +1222,9 @@ <ResGenDefines>$(DefineConstants)</ResGenDefines> </SplitTextStringResource> </ItemGroup> - <PropertyGroup> <CheckCDefines Condition="'$(CheckCDefines)'==''">true</CheckCDefines> </PropertyGroup> - <Target Name="CDefineChecker" BeforeTargets="Build" Condition="'$(CheckCDefines)'=='true'"> <!-- Compiler Definition Verification --> <Message Importance="High" Text="============" /> @@ -1258,46 +1232,37 @@ <IgnoreDefineConstants>FEATURE_IMPLICIT_TLS;FEATURE_HIJACK</IgnoreDefineConstants> <CMakeDefinitionSaveFile>$(IntermediateOutputPath)\cmake.definitions</CMakeDefinitionSaveFile> </PropertyGroup> - <Exec Command='python $(MSBuildThisFileDirectory)..\scripts\check-definitions.py "$(CMakeDefinitionSaveFile)" "$(DefineConstants)" "$(IgnoreDefineConstants)" ' /> + <Exec Command="python $(MSBuildThisFileDirectory)..\scripts\check-definitions.py "$(CMakeDefinitionSaveFile)" "$(DefineConstants)" "$(IgnoreDefineConstants)" " /> <Message Importance="High" Text="============" /> </Target> - <ItemGroup> <EmbeddedResource Include="$(NlpObjDir)\charinfo.nlp"> <LogicalName>charinfo.nlp</LogicalName> </EmbeddedResource> </ItemGroup> - <PropertyGroup Condition="'$(BuildOS)' == 'Windows_NT'"> <EnableDotnetAnalyzers Condition="'$(EnableDotnetAnalyzers)'==''">true</EnableDotnetAnalyzers> <UseWin32Apis>true</UseWin32Apis> <OSGroup>Windows_NT</OSGroup> </PropertyGroup> <Import Project="$(ToolsDir)\codeAnalysis.targets" /> - <Import Project="$(ToolsDir)\Microsoft.CSharp.Targets" /> - <PropertyGroup> <StrongNameSig>Silverlight</StrongNameSig> </PropertyGroup> - <!-- Import signing tools --> <Import Condition="Exists('$(ToolsDir)\sign.targets')" Project="$(ToolsDir)\sign.targets" /> - <!-- Overwrite the key that we are going to use for signing --> <PropertyGroup> <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)Tools\Signing\mscorlib.snk</AssemblyOriginatorKeyFile> </PropertyGroup> - - <Import Project="$(MSBuildThisFileDirectory)Tools\Versioning\GenerateVersionInfo.targets"/> + <Import Project="$(MSBuildThisFileDirectory)Tools\Versioning\GenerateVersionInfo.targets" /> <!-- Override versioning targets --> <Import Condition="Exists('$(ToolsDir)versioning.targets')" Project="$(ToolsDir)versioning.targets" /> - <PropertyGroup> <!-- Use a different nativeresource file to avoid conflicts with mscorlib--> <Win32Resource Condition="'$(GenerateNativeVersionInfo)'=='true'">$(IntermediateOutputPath)\System.Private.CoreLib.res</Win32Resource> </PropertyGroup> - - <Import Project="GenerateSplitStringResources.targets"/> - <Import Project="GenerateCompilerResponseFile.targets"/> -</Project> + <Import Project="GenerateSplitStringResources.targets" /> + <Import Project="GenerateCompilerResponseFile.targets" /> +</Project>
\ No newline at end of file diff --git a/src/mscorlib/System.Private.CoreLib.sln b/src/mscorlib/System.Private.CoreLib.sln index 4ab28af2d9..297d938932 100644 --- a/src/mscorlib/System.Private.CoreLib.sln +++ b/src/mscorlib/System.Private.CoreLib.sln @@ -1,5 +1,4 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 @@ -49,4 +48,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection -EndGlobal +EndGlobal
\ No newline at end of file diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs index adfa015161..1268dace36 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -4,6 +4,12 @@ using System.Runtime.Versioning; +#if BIT64 +using nuint = System.UInt64; +#else +using nuint = System.UInt32; +#endif + namespace System.Runtime.CompilerServices { // @@ -66,6 +72,18 @@ namespace System.Runtime.CompilerServices } /// <summary> + /// Adds an element offset to the given reference. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref T AddByteOffset<T>(ref T source, nuint byteOffset) + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementationForUnsafe for how this happens. + throw new InvalidOperationException(); + } + + /// <summary> /// Determines whether the specified references point to the same location. /// </summary> [NonVersionable] diff --git a/src/mscorlib/src/System/Runtime/RuntimeImports.cs b/src/mscorlib/src/System/Runtime/RuntimeImports.cs new file mode 100644 index 0000000000..b775dbf43c --- /dev/null +++ b/src/mscorlib/src/System/Runtime/RuntimeImports.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#if BIT64 +using nuint = System.UInt64; +#else + using nuint = System.UInt32; +#endif + +namespace System.Runtime +{ + public class RuntimeImports + { + // Non-inlinable wrapper around the QCall that avoids poluting the fast path + // with P/Invoke prolog/epilog. + [MethodImplAttribute(MethodImplOptions.NoInlining)] + internal unsafe static void RhZeroMemory(ref byte b, nuint byteLength) + { + fixed (byte* bytePointer = &b) + { + RhZeroMemory(bytePointer, byteLength); + } + } + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + extern private unsafe static void RhZeroMemory(byte* b, nuint byteLength); + } +} diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs index 7e93afe4f4..cb21853084 100644 --- a/src/mscorlib/src/System/Span.cs +++ b/src/mscorlib/src/System/Span.cs @@ -3,12 +3,20 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; #pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)' +#if BIT64 +using nuint = System.UInt64; +#else +using nuint = System.UInt32; +#endif + namespace System { /// <summary> @@ -234,10 +242,13 @@ namespace System [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { - // TODO: Optimize - https://github.com/dotnet/coreclr/issues/9161 - for (int i = 0; i < _length; i++) + if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) + { + SpanHelper.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)(_length * (Unsafe.SizeOf<T>() / sizeof(nuint)))); + } + else { - this[i] = default(T); + SpanHelper.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _pointer.Value), (nuint)(_length * Unsafe.SizeOf<T>())); } } @@ -625,5 +636,357 @@ namespace System } } } + + internal static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength) + { + if (byteLength == 0) + return; + + // Note: It's important that this switch handles lengths at least up to 22. + // See notes below near the main loop for why. + + // The switch will be very fast since it can be implemented using a jump + // table in assembly. See http://stackoverflow.com/a/449297/4077294 for more info. + + switch (byteLength) + { + case 1: + b = 0; + return; + case 2: + Unsafe.As<byte, short>(ref b) = 0; + return; + case 3: + Unsafe.As<byte, short>(ref b) = 0; + Unsafe.Add<byte>(ref b, 2) = 0; + return; + case 4: + Unsafe.As<byte, int>(ref b) = 0; + return; + case 5: + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.Add<byte>(ref b, 4) = 0; + return; + case 6: + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + return; + case 7: + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.Add<byte>(ref b, 6) = 0; + return; + case 8: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + return; + case 9: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.Add<byte>(ref b, 8) = 0; + return; + case 10: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + return; + case 11: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.Add<byte>(ref b, 10) = 0; + return; + case 12: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + return; + case 13: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.Add<byte>(ref b, 12) = 0; + return; + case 14: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0; + return; + case 15: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0; + Unsafe.Add<byte>(ref b, 14) = 0; + return; + case 16: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + return; + case 17: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + Unsafe.Add<byte>(ref b, 16) = 0; + return; + case 18: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0; + return; + case 19: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0; + Unsafe.Add<byte>(ref b, 18) = 0; + return; + case 20: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0; + return; + case 21: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0; + Unsafe.Add<byte>(ref b, 20) = 0; + return; + case 22: +#if BIT64 + Unsafe.As<byte, long>(ref b) = 0; + Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0; +#else + Unsafe.As<byte, int>(ref b) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0; +#endif + Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0; + Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 20)) = 0; + return; + } + + // P/Invoke into the native version for large lengths + if (byteLength >= 512) goto PInvoke; + + nuint i = 0; // byte offset at which we're copying + + if ((Unsafe.As<byte, int>(ref b) & 3) != 0) + { + if ((Unsafe.As<byte, int>(ref b) & 1) != 0) + { + Unsafe.AddByteOffset<byte>(ref b, i) = 0; + i += 1; + if ((Unsafe.As<byte, int>(ref b) & 2) != 0) + goto IntAligned; + } + Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + i += 2; + } + + IntAligned: + + // On 64-bit IntPtr.Size == 8, so we want to advance to the next 8-aligned address. If + // (int)b % 8 is 0, 5, 6, or 7, we will already have advanced by 0, 3, 2, or 1 + // bytes to the next aligned address (respectively), so do nothing. On the other hand, + // if it is 1, 2, 3, or 4 we will want to copy-and-advance another 4 bytes until + // we're aligned. + // The thing 1, 2, 3, and 4 have in common that the others don't is that if you + // subtract one from them, their 3rd lsb will not be set. Hence, the below check. + + if (((Unsafe.As<byte, int>(ref b) - 1) & 4) == 0) + { + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + i += 4; + } + + nuint end = byteLength - 16; + byteLength -= i; // lower 4 bits of byteLength represent how many bytes are left *after* the unrolled loop + + // We know due to the above switch-case that this loop will always run 1 iteration; max + // bytes we clear before checking is 23 (7 to align the pointers, 16 for 1 iteration) so + // the switch handles lengths 0-22. + Debug.Assert(end >= 7 && i <= end); + + // This is separated out into a different variable, so the i + 16 addition can be + // performed at the start of the pipeline and the loop condition does not have + // a dependency on the writes. + nuint counter; + + do + { + counter = i + 16; + + // This loop looks very costly since there appear to be a bunch of temporary values + // being created with the adds, but the jit (for x86 anyways) will convert each of + // these to use memory addressing operands. + + // So the only cost is a bit of code size, which is made up for by the fact that + // we save on writes to b. + +#if BIT64 + Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0; +#else + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0; + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0; + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 12)) = 0; +#endif + + i = counter; + + // See notes above for why this wasn't used instead + // i += 16; + } + while (counter <= end); + + if ((byteLength & 8) != 0) + { +#if BIT64 + Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; +#else + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0; +#endif + i += 8; + } + if ((byteLength & 4) != 0) + { + Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + i += 4; + } + if ((byteLength & 2) != 0) + { + Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0; + i += 2; + } + if ((byteLength & 1) != 0) + { + Unsafe.AddByteOffset<byte>(ref b, i) = 0; + // We're not using i after this, so not needed + // i += 1; + } + + return; + + PInvoke: + RuntimeImports.RhZeroMemory(ref b, byteLength); + } + + internal static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength) + { + if (pointerSizeLength == 0) + return; + + // TODO: Perhaps do switch casing to improve small size perf + + nuint i = 0; + nuint n = 0; + while ((n = i + 8) <= (pointerSizeLength)) + { + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 4) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 5) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 6) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 7) * (nuint)sizeof(IntPtr)) = default(IntPtr); + i = n; + } + if ((n = i + 4) <= (pointerSizeLength)) + { + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr); + i = n; + } + if ((n = i + 2) <= (pointerSizeLength)) + { + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr); + i = n; + } + if ((i + 1) <= (pointerSizeLength)) + { + Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); + } + } } } |