summaryrefslogtreecommitdiff
path: root/src/mscorlib
diff options
context:
space:
mode:
authorAhson Ahmed Khan <ahsonkhan@users.noreply.github.com>2017-02-24 17:27:54 -0800
committerGitHub <noreply@github.com>2017-02-24 17:27:54 -0800
commitda44463552689930c4d4ead5aa01a437fcbea622 (patch)
treeb2c3028239006e4bec047c5f65dfc2fae975c8bb /src/mscorlib
parentb927ad12373efd5840be34f011bb3c67ab1e156f (diff)
parentec6fb88e7009457f54f31ba83da915af395f4bd6 (diff)
downloadcoreclr-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.csproj81
-rw-r--r--src/mscorlib/System.Private.CoreLib.sln5
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs18
-rw-r--r--src/mscorlib/src/System/Runtime/RuntimeImports.cs32
-rw-r--r--src/mscorlib/src/System/Span.cs369
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(&quot;en-US&quot;)]" />
</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 &quot;$(CMakeDefinitionSaveFile)&quot; &quot;$(DefineConstants)&quot; &quot;$(IgnoreDefineConstants)&quot; " />
<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);
+ }
+ }
}
}