diff options
Diffstat (limited to 'src')
23 files changed, 491 insertions, 161 deletions
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 23392972ac..f7df61d8df 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -369,7 +369,7 @@ </ItemGroup> <ItemGroup Condition="'$(TargetsWindows)' == 'true'"> <Compile Include="$(BclSourcesRoot)\Internal\Runtime\InteropServices\InMemoryAssemblyLoader.cs" /> - <Compile Include="$(BclSourcesRoot)\System\DateTime.Windows.cs" /> + <Compile Include="$(BclSourcesRoot)\System\DateTime.Windows.CoreCLR.cs" /> <Compile Include="$(BclSourcesRoot)\Interop\Windows\OleAut32\Interop.VariantClear.cs" /> <Compile Include="$(BclSourcesRoot)\System\ApplicationModel.Windows.cs" /> <Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Windows.cs" /> diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs new file mode 100644 index 0000000000..067ee71587 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FileTimeToSystemTime.cs @@ -0,0 +1,15 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static unsafe extern Interop.BOOL FileTimeToSystemTime(long* lpFileTime, Interop.Kernel32.SYSTEMTIME* lpSystemTime); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetProcessInformation.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetProcessInformation.cs new file mode 100644 index 0000000000..22e0569375 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetProcessInformation.cs @@ -0,0 +1,23 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + internal const int ProcessLeapSecondInfo = 8; + + internal struct PROCESS_LEAP_SECOND_INFO + { + public uint Flags; + public uint Reserved; + } + + [DllImport(Libraries.Kernel32)] + internal static unsafe extern Interop.BOOL GetProcessInformation(IntPtr hProcess, int ProcessInformationClass, void* ProcessInformation, int ProcessInformationSize); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTime.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTime.cs new file mode 100644 index 0000000000..710db5e4b9 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTime.cs @@ -0,0 +1,15 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static unsafe extern void GetSystemTime(Interop.Kernel32.SYSTEMTIME* lpSystemTime); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTimeAsFileTime.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTimeAsFileTime.cs new file mode 100644 index 0000000000..e2dcd906c2 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTimeAsFileTime.cs @@ -0,0 +1,15 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static unsafe extern void GetSystemTimeAsFileTime(long* lpSystemTimeAsFileTime); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTimePreciseAsFileTime.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTimePreciseAsFileTime.cs new file mode 100644 index 0000000000..e3262799d1 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetSystemTimePreciseAsFileTime.cs @@ -0,0 +1,15 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static unsafe extern void GetSystemTimePreciseAsFileTime(long* lpSystemTimeAsFileTime); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs new file mode 100644 index 0000000000..43db7b4716 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.SystemTimeToFileTime.cs @@ -0,0 +1,14 @@ +// 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.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static unsafe extern Interop.BOOL SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* lpSystemTime, long* lpFileTime); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TzSpecificLocalTimeToSystemTime.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TzSpecificLocalTimeToSystemTime.cs new file mode 100644 index 0000000000..2cca7faed7 --- /dev/null +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TzSpecificLocalTimeToSystemTime.cs @@ -0,0 +1,18 @@ +// 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; +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static unsafe extern Interop.BOOL TzSpecificLocalTimeToSystemTime( + IntPtr lpTimeZoneInformation, + Interop.Kernel32.SYSTEMTIME* lpLocalTime, + Interop.Kernel32.SYSTEMTIME* lpUniversalTime); + } +} diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/NtDll/NtQueryInformationFile.cs b/src/System.Private.CoreLib/shared/Interop/Windows/NtDll/Interop.NtQueryInformationFile.cs index 4ba39a74e2..4ba39a74e2 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/NtDll/NtQueryInformationFile.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/NtDll/Interop.NtQueryInformationFile.cs diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 02656f57ad..cb7fec80ea 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -1005,6 +1005,7 @@ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ExpandEnvironmentStrings.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileAttributes.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FILE_INFO_BY_HANDLE_CLASS.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileTimeToSystemTime.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileTypes.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FindClose.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FindFirstFileEx.cs" /> @@ -1023,6 +1024,9 @@ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetProcessTimes.cs" Condition="'$(FeaturePerfTracing)' == 'true'" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemDirectoryW.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemInfo.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTime.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTimeAsFileTime.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTimePreciseAsFileTime.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemTimes.cs" Condition="'$(FeaturePerfTracing)' == 'true'" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempFileNameW.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs" /> @@ -1048,8 +1052,10 @@ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEndOfFile.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetThreadErrorMode.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetFilePointerEx.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SystemTimeToFileTime.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SYSTEM_INFO.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TzSpecificLocalTimeToSystemTime.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualAlloc.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualFree.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualQuery.cs" /> @@ -1057,7 +1063,6 @@ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Idna.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Normalization.cs" /> - <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs" Condition="'$(EnableWinRT)' != 'true'" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Ole32\Interop.CoCreateGuid.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Secur32\Interop.GetUserNameExW.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Shell32\Interop.SHGetKnownFolderPath.cs" /> @@ -1065,17 +1070,14 @@ <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Buffer.Windows.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Windows.cs" /> - <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" Condition="'$(EnableWinRT)' != 'true'" /> - <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Windows.cs" /> - <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" Condition="'$(EnableWinRT)' != 'true'" /> - <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Windows.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" /> @@ -1125,20 +1127,28 @@ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.Registry.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VerifyVersionExW.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VerSetConditionMask.cs" /> - <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\NtQueryInformationFile.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.Constants.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.LoadString.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.SendMessageTimeout.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Win32.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Win32.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Win32.cs" /> </ItemGroup> <ItemGroup Condition="$(TargetsWindows) and '$(EnableWinRT)' == 'true'"> + <Compile Include="$(MSBuildThisFileDirectory)System\DateTime.WinRT.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Environment.WinRT.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.WinRT.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CreateFile2.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CREATEFILE2_EXTENDED_PARAMETERS.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetProcessInformation.cs" /> </ItemGroup> <ItemGroup Condition="$(TargetsWindows) or '$(FeaturePal)'=='true'"> <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeWaitHandle.Windows.cs" /> diff --git a/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs b/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs index 6cf018115b..2c4de3e1a8 100644 --- a/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/DateTime.Unix.cs @@ -18,8 +18,8 @@ namespace System } #endif - internal static DateTime FromFileTimeLeapSecondsAware(long fileTime) => default; - internal static long ToFileTimeLeapSecondsAware(long ticks) => default; + private static DateTime FromFileTimeLeapSecondsAware(long fileTime) => default; + private static long ToFileTimeLeapSecondsAware(long ticks) => default; // IsValidTimeWithLeapSeconds is not expected to be called at all for now on non-Windows platforms internal static bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind) => false; diff --git a/src/System.Private.CoreLib/shared/System/DateTime.Win32.cs b/src/System.Private.CoreLib/shared/System/DateTime.Win32.cs new file mode 100644 index 0000000000..d742c891c7 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/DateTime.Win32.cs @@ -0,0 +1,23 @@ +// 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; + +namespace System +{ + public readonly partial struct DateTime + { + private static unsafe bool SystemSupportsLeapSeconds() + { + Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION slsi; + + return Interop.NtDll.NtQuerySystemInformation( + Interop.NtDll.SystemLeapSecondInformation, + (void *) &slsi, + sizeof(Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION), + null) == 0 && slsi.Enabled; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/DateTime.WinRT.cs b/src/System.Private.CoreLib/shared/System/DateTime.WinRT.cs new file mode 100644 index 0000000000..30a9a61aa3 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/DateTime.WinRT.cs @@ -0,0 +1,27 @@ +// 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; + +namespace System +{ + public readonly partial struct DateTime + { + private static unsafe bool SystemSupportsLeapSeconds() + { + Interop.Kernel32.PROCESS_LEAP_SECOND_INFO info; + + // Store apps don't have access to an API that would let us find out whether leap seconds have been + // disabled by policy: this implementation will produce slightly different results from what + // we have for Win32. If GetProcessInformation succeeds, we have to act as if leap seconds existed. + // They could still have been disabled by policy, but we have no way to check for that. + return Interop.Kernel32.GetProcessInformation( + Interop.Kernel32.GetCurrentProcess(), + Interop.Kernel32.ProcessLeapSecondInfo, + &info, + sizeof(Interop.Kernel32.PROCESS_LEAP_SECOND_INFO)) != Interop.BOOL.FALSE; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/DateTime.Windows.cs b/src/System.Private.CoreLib/shared/System/DateTime.Windows.cs new file mode 100644 index 0000000000..ba9df5c453 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/DateTime.Windows.cs @@ -0,0 +1,216 @@ +// 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; + +namespace System +{ + public readonly partial struct DateTime + { + internal static readonly bool s_systemSupportsLeapSeconds = SystemSupportsLeapSeconds(); + + public static unsafe DateTime UtcNow + { + get + { + if (s_systemSupportsLeapSeconds) + { + FullSystemTime time; + GetSystemTimeWithLeapSecondsHandling(&time); + return CreateDateTimeFromSystemTime(in time); + } + + return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc); + } + } + + internal static unsafe bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind) + { + DateTime dt = new DateTime(year, month, day); + FullSystemTime time = new FullSystemTime(year, month, dt.DayOfWeek, day, hour, minute, second); + + switch (kind) + { + case DateTimeKind.Local: return ValidateSystemTime(&time.systemTime, localTime: true); + case DateTimeKind.Utc: return ValidateSystemTime(&time.systemTime, localTime: false); + default: + return ValidateSystemTime(&time.systemTime, localTime: true) || ValidateSystemTime(&time.systemTime, localTime: false); + } + } + + private static unsafe DateTime FromFileTimeLeapSecondsAware(long fileTime) + { + FullSystemTime time; + if (FileTimeToSystemTime(fileTime, &time)) + { + return CreateDateTimeFromSystemTime(in time); + } + + throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_DateTimeBadTicks); + } + + private static unsafe long ToFileTimeLeapSecondsAware(long ticks) + { + FullSystemTime time = new FullSystemTime(ticks); + long fileTime; + + if (SystemTimeToFileTime(&time.systemTime, &fileTime)) + { + return fileTime + ticks % TicksPerMillisecond; + } + + throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static DateTime CreateDateTimeFromSystemTime(in FullSystemTime time) + { + long ticks = DateToTicks(time.systemTime.Year, time.systemTime.Month, time.systemTime.Day); + ticks += TimeToTicks(time.systemTime.Hour, time.systemTime.Minute, time.systemTime.Second); + ticks += time.systemTime.Milliseconds * TicksPerMillisecond; + ticks += time.hundredNanoSecond; + return new DateTime( ((UInt64)(ticks)) | KindUtc); + } + + // FullSystemTime struct is the SYSTEMTIME struct with extra hundredNanoSecond field to store more precise time. + [StructLayout(LayoutKind.Sequential)] + private struct FullSystemTime + { + internal Interop.Kernel32.SYSTEMTIME systemTime; + internal long hundredNanoSecond; + + internal FullSystemTime(int year, int month, DayOfWeek dayOfWeek, int day, int hour, int minute, int second) + { + systemTime.Year = (ushort) year; + systemTime.Month = (ushort) month; + systemTime.DayOfWeek = (ushort) dayOfWeek; + systemTime.Day = (ushort) day; + systemTime.Hour = (ushort) hour; + systemTime.Minute = (ushort) minute; + systemTime.Second = (ushort) second; + systemTime.Milliseconds = 0; + hundredNanoSecond = 0; + } + + internal FullSystemTime(long ticks) + { + DateTime dt = new DateTime(ticks); + + int year, month, day; + dt.GetDatePart(out year, out month, out day); + + systemTime.Year = (ushort) year; + systemTime.Month = (ushort) month; + systemTime.DayOfWeek = (ushort) dt.DayOfWeek; + systemTime.Day = (ushort) day; + systemTime.Hour = (ushort) dt.Hour; + systemTime.Minute = (ushort) dt.Minute; + systemTime.Second = (ushort) dt.Second; + systemTime.Milliseconds = (ushort) dt.Millisecond; + hundredNanoSecond = 0; + } + }; + +#if !CORECLR + internal static readonly bool s_systemSupportsPreciseSystemTime = SystemSupportsPreciseSystemTime(); + + private static unsafe bool SystemSupportsPreciseSystemTime() + { + if (Environment.IsWindows8OrAbove) + { + // GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on + // misconfigured systems, it's possible for the "precise" time to be inaccurate: + // https://github.com/dotnet/coreclr/issues/14187 + // If it's inaccurate, though, we expect it to be wildly inaccurate, so as a + // workaround/heuristic, we get both the "normal" and "precise" times, and as + // long as they're close, we use the precise one. This workaround can be removed + // when we better understand what's causing the drift and the issue is no longer + // a problem or can be better worked around on all targeted OSes. + + long systemTimeResult; + Interop.Kernel32.GetSystemTimeAsFileTime(&systemTimeResult); + + long preciseSystemTimeResult; + Interop.Kernel32.GetSystemTimePreciseAsFileTime(&preciseSystemTimeResult); + + return Math.Abs(preciseSystemTimeResult - systemTimeResult) <= 100 * TicksPerMillisecond; + } + + return false; + } + + private static unsafe bool ValidateSystemTime(Interop.Kernel32.SYSTEMTIME* time, bool localTime) + { + if (localTime) + { + Interop.Kernel32.SYSTEMTIME st; + return Interop.Kernel32.TzSpecificLocalTimeToSystemTime(IntPtr.Zero, time, &st) != Interop.BOOL.FALSE; + } + else + { + long timestamp; + return Interop.Kernel32.SystemTimeToFileTime(time, ×tamp) != Interop.BOOL.FALSE; + } + } + + private static unsafe bool FileTimeToSystemTime(long fileTime, FullSystemTime* time) + { + if (Interop.Kernel32.FileTimeToSystemTime(&fileTime, &time->systemTime) != Interop.BOOL.FALSE) + { + // to keep the time precision + time->hundredNanoSecond = fileTime % TicksPerMillisecond; + if (time->systemTime.Second > 59) + { + // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation. + // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds + time->systemTime.Second = 59; + time->systemTime.Milliseconds = 999; + time->hundredNanoSecond = 9999; + } + return true; + } + return false; + } + + private static unsafe void GetSystemTimeWithLeapSecondsHandling(FullSystemTime* time) + { + if (!FileTimeToSystemTime(GetSystemTimeAsFileTime(), time)) + { + Interop.Kernel32.GetSystemTime(&time->systemTime); + time->hundredNanoSecond = 0; + if (time->systemTime.Second > 59) + { + // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation. + // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds + time->systemTime.Second = 59; + time->systemTime.Milliseconds = 999; + time->hundredNanoSecond = 9999; + } + } + } + + private static unsafe bool SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* time, long* fileTime) + { + return Interop.Kernel32.SystemTimeToFileTime(time, fileTime) != Interop.BOOL.FALSE; + } + + private static unsafe long GetSystemTimeAsFileTime() + { + long timestamp; + + if (s_systemSupportsPreciseSystemTime) + { + Interop.Kernel32.GetSystemTimePreciseAsFileTime(×tamp); + } + else + { + Interop.Kernel32.GetSystemTimeAsFileTime(×tamp); + } + + return timestamp; + } +#endif + } +} diff --git a/src/System.Private.CoreLib/src/System/DateTime.Windows.CoreCLR.cs b/src/System.Private.CoreLib/src/System/DateTime.Windows.CoreCLR.cs new file mode 100644 index 0000000000..5597c137ad --- /dev/null +++ b/src/System.Private.CoreLib/src/System/DateTime.Windows.CoreCLR.cs @@ -0,0 +1,27 @@ +// 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; + +namespace System +{ + public readonly partial struct DateTime + { + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static unsafe extern bool ValidateSystemTime(Interop.Kernel32.SYSTEMTIME* time, bool localTime); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static unsafe extern bool FileTimeToSystemTime(long fileTime, FullSystemTime* time); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static unsafe extern void GetSystemTimeWithLeapSecondsHandling(FullSystemTime* time); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static unsafe extern bool SystemTimeToFileTime(Interop.Kernel32.SYSTEMTIME* time, long* fileTime); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static unsafe extern long GetSystemTimeAsFileTime(); + } +} diff --git a/src/System.Private.CoreLib/src/System/DateTime.Windows.cs b/src/System.Private.CoreLib/src/System/DateTime.Windows.cs deleted file mode 100644 index 9d0d0cd28c..0000000000 --- a/src/System.Private.CoreLib/src/System/DateTime.Windows.cs +++ /dev/null @@ -1,138 +0,0 @@ -// 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; - -namespace System -{ - public readonly partial struct DateTime - { - internal static readonly bool s_systemSupportsLeapSeconds = SystemSupportsLeapSeconds(); - - public static DateTime UtcNow - { - get - { - if (s_systemSupportsLeapSeconds) - { - GetSystemTimeWithLeapSecondsHandling(out FullSystemTime time); - return CreateDateTimeFromSystemTime(in time); - } - - return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc); - } - } - - internal static bool IsValidTimeWithLeapSeconds(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind) - { - DateTime dt = new DateTime(year, month, day); - FullSystemTime time = new FullSystemTime(year, month, dt.DayOfWeek, day, hour, minute, second); - - switch (kind) - { - case DateTimeKind.Local: return ValidateSystemTime(in time.systemTime, localTime: true); - case DateTimeKind.Utc: return ValidateSystemTime(in time.systemTime, localTime: false); - default: - return ValidateSystemTime(in time.systemTime, localTime: true) || ValidateSystemTime(in time.systemTime, localTime: false); - } - } - - internal static DateTime FromFileTimeLeapSecondsAware(long fileTime) - { - if (FileTimeToSystemTime(fileTime, out FullSystemTime time)) - { - return CreateDateTimeFromSystemTime(in time); - } - - throw new ArgumentOutOfRangeException("fileTime", SR.ArgumentOutOfRange_DateTimeBadTicks); - } - - internal static long ToFileTimeLeapSecondsAware(long ticks) - { - FullSystemTime time = new FullSystemTime(ticks); - if (SystemTimeToFileTime(in time.systemTime, out long fileTime)) - { - return fileTime + ticks % TicksPerMillisecond; - } - - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static DateTime CreateDateTimeFromSystemTime(in FullSystemTime time) - { - long ticks = DateToTicks(time.systemTime.Year, time.systemTime.Month, time.systemTime.Day); - ticks += TimeToTicks(time.systemTime.Hour, time.systemTime.Minute, time.systemTime.Second); - ticks += time.systemTime.Milliseconds * TicksPerMillisecond; - ticks += time.hundredNanoSecond; - return new DateTime( ((UInt64)(ticks)) | KindUtc); - } - - private static unsafe bool SystemSupportsLeapSeconds() - { - Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION slsi; - - return Interop.NtDll.NtQuerySystemInformation( - Interop.NtDll.SystemLeapSecondInformation, - (void *) &slsi, - sizeof(Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION), - null) == 0 && slsi.Enabled; - } - - // FullSystemTime struct is the SYSTEMTIME struct with extra hundredNanoSecond field to store more precise time. - [StructLayout(LayoutKind.Sequential)] - internal struct FullSystemTime - { - internal Interop.Kernel32.SYSTEMTIME systemTime; - internal long hundredNanoSecond; - - internal FullSystemTime(int year, int month, DayOfWeek dayOfWeek, int day, int hour, int minute, int second) - { - systemTime.Year = (ushort) year; - systemTime.Month = (ushort) month; - systemTime.DayOfWeek = (ushort) dayOfWeek; - systemTime.Day = (ushort) day; - systemTime.Hour = (ushort) hour; - systemTime.Minute = (ushort) minute; - systemTime.Second = (ushort) second; - systemTime.Milliseconds = 0; - hundredNanoSecond = 0; - } - - internal FullSystemTime(long ticks) - { - DateTime dt = new DateTime(ticks); - - int year, month, day; - dt.GetDatePart(out year, out month, out day); - - systemTime.Year = (ushort) year; - systemTime.Month = (ushort) month; - systemTime.DayOfWeek = (ushort) dt.DayOfWeek; - systemTime.Day = (ushort) day; - systemTime.Hour = (ushort) dt.Hour; - systemTime.Minute = (ushort) dt.Minute; - systemTime.Second = (ushort) dt.Second; - systemTime.Milliseconds = (ushort) dt.Millisecond; - hundredNanoSecond = 0; - } - }; - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern bool ValidateSystemTime(in Interop.Kernel32.SYSTEMTIME time, bool localTime); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern bool FileTimeToSystemTime(long fileTime, out FullSystemTime time); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern void GetSystemTimeWithLeapSecondsHandling(out FullSystemTime time); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern bool SystemTimeToFileTime(in Interop.Kernel32.SYSTEMTIME time, out long fileTime); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern long GetSystemTimeAsFileTime(); - } -} diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs index e611c604d7..9d8cc65076 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs @@ -1979,8 +1979,6 @@ namespace System.Reflection.Emit if (IsCreated()) return m_bakedRuntimeType; - ThrowIfCreated(); - if (m_typeInterfaces == null) m_typeInterfaces = new List<Type>(); diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index 55b3f0a7ba..66d5b22031 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -714,7 +714,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) BYTE* gcPtrs = gcPtrArray; unsigned gcPtrCount; // The count of GC pointers in the struct - int structSize; + unsigned structSize; bool isHfa; // This is the varNum for our load operations, @@ -764,12 +764,40 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) hiReg = addrReg; } #endif // _TARGET_ARM64_ + } + if (source->OperIs(GT_OBJ)) + { + // If the source is an OBJ node then we need to use the type information + // it provides (size and GC layout) even if the node wraps a lclvar. Due + // to struct reinterpretation (e.g. Unsafe.As<X, Y>) it is possible that + // the OBJ node has a different type than the lclvar. CORINFO_CLASS_HANDLE objClass = source->gtObj.gtClass; structSize = compiler->info.compCompHnd->getClassSize(objClass); - isHfa = compiler->IsHfa(objClass); + + // The codegen code below doesn't have proper support for struct sizes + // that are not multiple of the slot size. Call arg morphing handles this + // case by copying non-local values to temporary local variables. + // More generally, we can always round up the struct size when the OBJ node + // wraps a local variable because the local variable stack allocation size + // is also rounded up to be a multiple of the slot size. + if (varNode != nullptr) + { + structSize = roundUp(structSize, TARGET_POINTER_SIZE); + } + else + { + assert((structSize % TARGET_POINTER_SIZE) == 0); + } + + isHfa = compiler->IsHfa(objClass); + #ifdef _TARGET_ARM64_ + // On ARM32, Lowering places the correct GC layout information in the + // GenTreePutArgStk node and the code above already use that. On ARM64, + // this information is not available (in order to keep GenTreePutArgStk + // nodes small) and we need to retrieve it from the VM here. gcPtrCount = compiler->info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]); #endif } @@ -3849,7 +3877,9 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni // Generate: // - // mov rOffset, -pageSize + // mov rOffset, -pageSize // On arm, this turns out to be "movw r1, 0xf000; sxth r1, r1". + // // We could save 4 bytes in the prolog by using "movs r1, 0" at the + // // runtime expense of running a useless first loop iteration. // mov rLimit, -frameSize // loop: // ldr rTemp, [sp + rOffset] // rTemp = wzr on ARM64 diff --git a/src/jit/emit.h b/src/jit/emit.h index 1308531a90..b429920c38 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -1374,7 +1374,7 @@ protected: void emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool reloc = false); void emitDispFrameRef(int varx, int disp, int offs, bool asmfm); void emitDispInsOffs(unsigned offs, bool doffs); - void emitDispInsHex(BYTE* code, size_t sz); + void emitDispInsHex(instrDesc* id, BYTE* code, size_t sz); #else // !DEBUG #define emitVarRefOffs 0 diff --git a/src/jit/emitarm.cpp b/src/jit/emitarm.cpp index 3d7089bb8a..9e36efb4df 100644 --- a/src/jit/emitarm.cpp +++ b/src/jit/emitarm.cpp @@ -6778,7 +6778,7 @@ void emitter::emitDispGC(emitAttr attr) * Display (optionally) the instruction encoding in hex */ -void emitter::emitDispInsHex(BYTE* code, size_t sz) +void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) { // We do not display the instruction hex if we want diff-able disassembly if (!emitComp->opts.disDiffable) @@ -6791,6 +6791,27 @@ void emitter::emitDispInsHex(BYTE* code, size_t sz) { printf(" %04X %04X", (*((unsigned short*)(code + 0))), (*((unsigned short*)(code + 2)))); } + else + { + assert(sz == 0); + + // At least display the encoding size of the instruction, even if not displaying its actual encoding. + insSize isz = emitInsSize(id->idInsFmt()); + switch (isz) + { + case ISZ_16BIT: + printf(" 2B"); + break; + case ISZ_32BIT: + printf(" 4B"); + break; + case ISZ_48BIT: + printf(" 6B"); + break; + default: + unreached(); + } + } } } @@ -6822,7 +6843,7 @@ void emitter::emitDispInsHelp( /* Display the instruction hex code */ - emitDispInsHex(code, sz); + emitDispInsHex(id, code, sz); printf(" "); diff --git a/src/jit/emitarm64.cpp b/src/jit/emitarm64.cpp index afd5cf44e2..0345a361c8 100644 --- a/src/jit/emitarm64.cpp +++ b/src/jit/emitarm64.cpp @@ -10698,7 +10698,7 @@ void emitter::emitDispAddrRRExt(regNumber reg1, regNumber reg2, insOpts opt, boo * Display (optionally) the instruction encoding in hex */ -void emitter::emitDispInsHex(BYTE* code, size_t sz) +void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) { // We do not display the instruction hex if we want diff-able disassembly if (!emitComp->opts.disDiffable) @@ -10709,6 +10709,7 @@ void emitter::emitDispInsHex(BYTE* code, size_t sz) } else { + assert(sz == 0); printf(" "); } } @@ -10742,7 +10743,7 @@ void emitter::emitDispIns( /* Display the instruction hex code */ - emitDispInsHex(pCode, sz); + emitDispInsHex(id, pCode, sz); printf(" "); diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 6052b97493..f7b3c5baa4 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -8049,7 +8049,7 @@ void emitter::emitDispShift(instruction ins, int cnt) * Display (optionally) the bytes for the instruction encoding in hex */ -void emitter::emitDispInsHex(BYTE* code, size_t sz) +void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) { // We do not display the instruction hex if we want diff-able disassembly if (!emitComp->opts.disDiffable) @@ -8216,7 +8216,7 @@ void emitter::emitDispIns( { /* Display the instruction hex code */ - emitDispInsHex(code, sz); + emitDispInsHex(id, code, sz); } /* Display the instruction name */ diff --git a/src/jit/unwind.h b/src/jit/unwind.h index a78df32f1f..06396f2a9a 100644 --- a/src/jit/unwind.h +++ b/src/jit/unwind.h @@ -20,8 +20,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // You can increase this "max" number if necessary. #if defined(_TARGET_ARM_) -const unsigned MAX_PROLOG_SIZE_BYTES = 40; -const unsigned MAX_EPILOG_SIZE_BYTES = 40; +const unsigned MAX_PROLOG_SIZE_BYTES = 44; +const unsigned MAX_EPILOG_SIZE_BYTES = 44; #define UWC_END 0xFF // "end" unwind code #define UW_MAX_FRAGMENT_SIZE_BYTES (1U << 19) #define UW_MAX_CODE_WORDS_COUNT 15 // Max number that can be encoded in the "Code Words" field of the .pdata record |