Leap Seconds Support (#21420)
authorTarek Mahmoud Sayed <tarekms@microsoft.com>
Sat, 8 Dec 2018 20:40:13 +0000 (12:40 -0800)
committerGitHub <noreply@github.com>
Sat, 8 Dec 2018 20:40:13 +0000 (12:40 -0800)
* Leap Seconds Support

* Address Feedback

* More feedback addressing

src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/System.Private.CoreLib/shared/Interop/Windows/NtDll/Interop.NtQuerySystemInformation.cs [new file with mode: 0644]
src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
src/System.Private.CoreLib/shared/System/DateTime.cs
src/System.Private.CoreLib/shared/System/DateTimeOffset.cs
src/System.Private.CoreLib/src/System/DateTime.CoreCLR.cs [deleted file]
src/System.Private.CoreLib/src/System/DateTime.Unix.cs [new file with mode: 0644]
src/System.Private.CoreLib/src/System/DateTime.Windows.cs [new file with mode: 0644]
src/classlibnative/bcltype/system.cpp
src/classlibnative/bcltype/system.h
src/vm/ecalllist.h

index 3d53137..a4c9bec 100644 (file)
     <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\EqualityComparer.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\ObjectModel\ReadOnlyDictionary.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Currency.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\DateTime.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\DefaultBinder.CanConvert.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Delegate.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Contracts\Contracts.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Variant.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
+    <Compile Include="$(BclSourcesRoot)\System\DateTime.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\Interop\Unix\Interop.Libraries.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Unix.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Unix.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+    <Compile Include="$(BclSourcesRoot)\System\DateTime.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\Interop\Windows\Kernel32\Interop.GetSystemDirectoryW.cs" />
     <Compile Include="$(BclSourcesRoot)\System\ApplicationModel.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\DebugProvider.Windows.cs" />
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/NtDll/Interop.NtQuerySystemInformation.cs b/src/System.Private.CoreLib/shared/Interop/Windows/NtDll/Interop.NtQuerySystemInformation.cs
new file mode 100644 (file)
index 0000000..16f05e3
--- /dev/null
@@ -0,0 +1,24 @@
+// 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 NtDll
+    {
+        [DllImport(Libraries.NtDll)]
+        internal static unsafe extern int NtQuerySystemInformation(int SystemInformationClass, void* SystemInformation, int SystemInformationLength, uint* ReturnLength);
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct SYSTEM_LEAP_SECOND_INFORMATION
+        {
+            public bool Enabled;
+            public uint Flags;
+        }
+
+        internal const int SystemLeapSecondInformation = 206;
+    }
+}
index 56a0b13..0c40e26 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Idna.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Normalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+    <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\OleAut32\Interop.SysAllocStringLen.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs" />
index 4cba9f0..1a33479 100644 (file)
@@ -196,6 +196,14 @@ namespace System
         //
         public DateTime(int year, int month, int day, int hour, int minute, int second)
         {
+            if (second == 60 && s_systemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, second, DateTimeKind.Unspecified))
+            {
+                // if we have leap second (second = 60) then we'll need to check if it is valid time.
+                // if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
+                // in the specified minute.
+                // if it is not valid time, we'll eventually throw.
+                second = 59;
+            }
             _dateData = (ulong)(DateToTicks(year, month, day) + TimeToTicks(hour, minute, second));
         }
 
@@ -205,6 +213,16 @@ namespace System
             {
                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
             }
+
+            if (second == 60 && s_systemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, second, kind))
+            {
+                // if we have leap second (second = 60) then we'll need to check if it is valid time.
+                // if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
+                // in the specified minute.
+                // if it is not valid time, we'll eventually throw.
+                second = 59;
+            }
+
             long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
             _dateData = ((ulong)ticks | ((ulong)kind << KindShift));
         }
@@ -216,7 +234,24 @@ namespace System
         {
             if (calendar == null)
                 throw new ArgumentNullException(nameof(calendar));
+
+            int originalSecond = second;
+            if (second == 60 && s_systemSupportsLeapSeconds)
+            {
+                // Reset the second value now and then we'll validate it later when we get the final Gregorian date.
+                second = 59;
+            }
+
             _dateData = (ulong)calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
+
+            if (originalSecond == 60)
+            {
+                DateTime dt = new DateTime(_dateData);
+                if (!IsValidTimeWithLeapSeconds(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 60, DateTimeKind.Unspecified))
+                {
+                    throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+                }
+            }
         }
 
         // Constructs a DateTime from a given year, month, day, hour,
@@ -228,6 +263,16 @@ namespace System
             {
                 throw new ArgumentOutOfRangeException(nameof(millisecond), SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1));
             }
+
+            if (second == 60 && s_systemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, second, DateTimeKind.Unspecified))
+            {
+                // if we have leap second (second = 60) then we'll need to check if it is valid time.
+                // if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
+                // in the specified minute.
+                // if it is not valid time, we'll eventually throw.
+                second = 59;
+            }
+
             long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
             ticks += millisecond * TicksPerMillisecond;
             if (ticks < MinTicks || ticks > MaxTicks)
@@ -245,6 +290,16 @@ namespace System
             {
                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
             }
+
+            if (second == 60 && s_systemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, second, kind))
+            {
+                // if we have leap second (second = 60) then we'll need to check if it is valid time.
+                // if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
+                // in the specified minute.
+                // if it is not valid time, we'll eventually throw.
+                second = 59;
+            }
+
             long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
             ticks += millisecond * TicksPerMillisecond;
             if (ticks < MinTicks || ticks > MaxTicks)
@@ -263,11 +318,28 @@ namespace System
             {
                 throw new ArgumentOutOfRangeException(nameof(millisecond), SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1));
             }
+
+            int originalSecond = second;
+            if (second == 60 && s_systemSupportsLeapSeconds)
+            {
+                // Reset the second value now and then we'll validate it later when we get the final Gregorian date.
+                second = 59;
+            }
+
             long ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
             ticks += millisecond * TicksPerMillisecond;
             if (ticks < MinTicks || ticks > MaxTicks)
                 throw new ArgumentException(SR.Arg_DateTimeRange);
             _dateData = (ulong)ticks;
+
+            if (originalSecond == 60)
+            {
+                DateTime dt = new DateTime(_dateData);
+                if (!IsValidTimeWithLeapSeconds(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 60, DateTimeKind.Unspecified))
+                {
+                    throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+                }
+            }
         }
 
         public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind)
@@ -282,11 +354,28 @@ namespace System
             {
                 throw new ArgumentException(SR.Argument_InvalidDateTimeKind, nameof(kind));
             }
+
+            int originalSecond = second;
+            if (second == 60 && s_systemSupportsLeapSeconds)
+            {
+                // Reset the second value now and then we'll validate it later when we get the final Gregorian date.
+                second = 59;
+            }
+
             long ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks;
             ticks += millisecond * TicksPerMillisecond;
             if (ticks < MinTicks || ticks > MaxTicks)
                 throw new ArgumentException(SR.Arg_DateTimeRange);
             _dateData = ((ulong)ticks | ((ulong)kind << KindShift));
+
+            if (originalSecond == 60)
+            {
+                DateTime dt = new DateTime(_dateData);
+                if (!IsValidTimeWithLeapSeconds(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 60, kind))
+                {
+                    throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+                }
+            }
         }
 
         private DateTime(SerializationInfo info, StreamingContext context)
@@ -338,8 +427,6 @@ namespace System
             }
         }
 
-
-
         internal long InternalTicks
         {
             get
@@ -722,6 +809,11 @@ namespace System
                 throw new ArgumentOutOfRangeException(nameof(fileTime), SR.ArgumentOutOfRange_FileTimeInvalid);
             }
 
+            if (s_systemSupportsLeapSeconds)
+            {
+                return FromFileTimeLeapSecondsAware(fileTime);
+            }
+
             // This is the ticks in Universal time for this fileTime.
             long universalTicks = fileTime + FileTimeOffset;
             return new DateTime(universalTicks, DateTimeKind.Utc);
@@ -1223,11 +1315,18 @@ namespace System
         {
             // Treats the input as universal if it is not specified
             long ticks = ((InternalKind & LocalMask) != 0) ? ToUniversalTime().InternalTicks : this.InternalTicks;
+
+            if (s_systemSupportsLeapSeconds)
+            {
+                return ToFileTimeLeapSecondsAware(ticks);
+            }
+
             ticks -= FileTimeOffset;
             if (ticks < 0)
             {
                 throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_FileTimeInvalid);
             }
+
             return ticks;
         }
 
@@ -1574,7 +1673,7 @@ namespace System
             {
                 return false;
             }
-            if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60)
+            if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second > 60)
             {
                 return false;
             }
@@ -1582,6 +1681,24 @@ namespace System
             {
                 return false;
             }
+
+            if (second == 60)
+            {
+                if (s_systemSupportsLeapSeconds && IsValidTimeWithLeapSeconds(year, month, day, hour, minute, second, DateTimeKind.Unspecified))
+                {
+                    // if we have leap second (second = 60) then we'll need to check if it is valid time.
+                    // if it is valid, then we adjust the second to 59 so DateTime will consider this second is last second
+                    // of this minute.
+                    // if it is not valid time, we'll eventually throw.
+                    // although this is unspecified datetime kind, we'll assume the passed time is UTC to check the leap seconds.
+                    second = 59;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
             long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
 
             ticks += millisecond * TicksPerMillisecond;
index e89cbc6..6fc5dfc 100644 (file)
@@ -9,14 +9,14 @@ using System.Runtime.Serialization;
 
 namespace System
 {
-    // DateTimeOffset is a value type that consists of a DateTime and a time zone offset, 
+    // DateTimeOffset is a value type that consists of a DateTime and a time zone offset,
     // ie. how far away the time is from GMT. The DateTime is stored whole, and the offset
-    // is stored as an Int16 internally to save space, but presented as a TimeSpan. 
+    // is stored as an Int16 internally to save space, but presented as a TimeSpan.
     //
     // The range is constrained so that both the represented clock time and the represented
     // UTC time fit within the boundaries of MaxValue. This gives it the same range as DateTime
     // for actual UTC times, and a slightly constrained range on one end when an offset is
-    // present. 
+    // present.
     //
     // This class should be substitutable for date time in most cases; so most operations
     // effectively work on the clock time. However, the underlying UTC time is what counts
@@ -30,7 +30,7 @@ namespace System
 
     [StructLayout(LayoutKind.Auto)]
     [Serializable]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] 
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public readonly struct DateTimeOffset : IComparable, IFormattable, IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>, ISerializable, IDeserializationCallback, ISpanFormattable
     {
         // Constants
@@ -109,7 +109,21 @@ namespace System
         public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, TimeSpan offset)
         {
             _offsetMinutes = ValidateOffset(offset);
+
+            int originalSecond = second;
+            if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
+            {
+                // Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
+                second = 59;
+            }
+
             _dateTime = ValidateDate(new DateTime(year, month, day, hour, minute, second), offset);
+
+            if (originalSecond == 60 &&
+               !DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year, _dateTime.Month, _dateTime.Day, _dateTime.Hour, _dateTime.Minute, 60, DateTimeKind.Utc))
+            {
+                throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+            }
         }
 
         // Constructs a DateTimeOffset from a given year, month, day, hour,
@@ -117,7 +131,21 @@ namespace System
         public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, TimeSpan offset)
         {
             _offsetMinutes = ValidateOffset(offset);
+
+            int originalSecond = second;
+            if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
+            {
+                // Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
+                second = 59;
+            }
+
             _dateTime = ValidateDate(new DateTime(year, month, day, hour, minute, second, millisecond), offset);
+
+            if (originalSecond == 60 &&
+               !DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year, _dateTime.Month, _dateTime.Day, _dateTime.Hour, _dateTime.Minute, 60, DateTimeKind.Utc))
+            {
+                throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+            }
         }
 
         // Constructs a DateTimeOffset from a given year, month, day, hour,
@@ -125,7 +153,21 @@ namespace System
         public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, TimeSpan offset)
         {
             _offsetMinutes = ValidateOffset(offset);
+
+            int originalSecond = second;
+            if (second == 60 && DateTime.s_systemSupportsLeapSeconds)
+            {
+                // Reset the leap second to 59 for now and then we'll validate it after getting the final UTC time.
+                second = 59;
+            }
+
             _dateTime = ValidateDate(new DateTime(year, month, day, hour, minute, second, millisecond, calendar), offset);
+
+            if (originalSecond == 60 &&
+               !DateTime.IsValidTimeWithLeapSeconds(_dateTime.Year, _dateTime.Month, _dateTime.Day, _dateTime.Hour, _dateTime.Minute, 60, DateTimeKind.Utc))
+            {
+                throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+            }
         }
 
         // Returns a DateTimeOffset representing the current date and time. The
@@ -596,7 +638,7 @@ namespace System
         // Constructs a DateTimeOffset from a string. The string must specify a
         // date and optionally a time in a culture-specific or universal format.
         // Leading and trailing whitespace characters are allowed.
-        // 
+        //
         public static DateTimeOffset Parse(string input)
         {
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
@@ -612,7 +654,7 @@ namespace System
         // Constructs a DateTimeOffset from a string. The string must specify a
         // date and optionally a time in a culture-specific or universal format.
         // Leading and trailing whitespace characters are allowed.
-        // 
+        //
         public static DateTimeOffset Parse(string input, IFormatProvider formatProvider)
         {
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
@@ -642,7 +684,7 @@ namespace System
         // Constructs a DateTimeOffset from a string. The string must specify a
         // date and optionally a time in a culture-specific or universal format.
         // Leading and trailing whitespace characters are allowed.
-        // 
+        //
         public static DateTimeOffset ParseExact(string input, string format, IFormatProvider formatProvider)
         {
             if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
@@ -653,7 +695,7 @@ namespace System
         // Constructs a DateTimeOffset from a string. The string must specify a
         // date and optionally a time in a culture-specific or universal format.
         // Leading and trailing whitespace characters are allowed.
-        // 
+        //
         public static DateTimeOffset ParseExact(string input, string format, IFormatProvider formatProvider, DateTimeStyles styles)
         {
             styles = ValidateStyles(styles, nameof(styles));
@@ -943,7 +985,7 @@ namespace System
             // RoundtripKind does not make sense for DateTimeOffset; ignore this flag for backward compatibility with DateTime
             style &= ~DateTimeStyles.RoundtripKind;
 
-            // AssumeLocal is also ignored as that is what we do by default with DateTimeOffset.Parse             
+            // AssumeLocal is also ignored as that is what we do by default with DateTimeOffset.Parse
             style &= ~DateTimeStyles.AssumeLocal;
 
             return style;
diff --git a/src/System.Private.CoreLib/src/System/DateTime.CoreCLR.cs b/src/System.Private.CoreLib/src/System/DateTime.CoreCLR.cs
deleted file mode 100644 (file)
index c9a0f23..0000000
+++ /dev/null
@@ -1,27 +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;
-
-namespace System
-{
-    public readonly partial struct DateTime
-    {
-        public static DateTime UtcNow
-        {
-            get
-            {
-                // following code is tuned for speed. Don't change it without running benchmark.
-                long ticks = 0;
-                ticks = GetSystemTimeAsFileTime();
-
-                return new DateTime(((ulong)(ticks + FileTimeOffset)) | KindUtc);
-            }
-        }
-
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern long GetSystemTimeAsFileTime();
-    }
-}
diff --git a/src/System.Private.CoreLib/src/System/DateTime.Unix.cs b/src/System.Private.CoreLib/src/System/DateTime.Unix.cs
new file mode 100644 (file)
index 0000000..f5982fa
--- /dev/null
@@ -0,0 +1,30 @@
+// 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;
+
+namespace System
+{
+    public readonly partial struct DateTime
+    {
+        internal const bool s_systemSupportsLeapSeconds = false;
+
+        public static DateTime UtcNow
+        {
+            get
+            {
+                return new DateTime(((ulong)(GetSystemTimeAsFileTime() + FileTimeOffset)) | KindUtc);
+            }
+        }
+
+        internal static DateTime FromFileTimeLeapSecondsAware(long fileTime) => default(DateTime);
+        internal static long ToFileTimeLeapSecondsAware(long ticks) => default(long);
+
+        // 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;
+
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal static 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
new file mode 100644 (file)
index 0000000..f34a6e0
--- /dev/null
@@ -0,0 +1,137 @@
+// 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 = new Interop.NtDll.SYSTEM_LEAP_SECOND_INFORMATION();
+            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();
+    }
+}
index d525f87..bd1db8f 100644 (file)
@@ -76,7 +76,7 @@ void WINAPI InitializeGetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
     {
         func = &::GetSystemTimeAsFileTime;
     }
-    
+
     g_pfnGetSystemTimeAsFileTime = func;
     func(lpSystemTimeAsFileTime);
 }
@@ -99,12 +99,90 @@ FCIMPL0(INT64, SystemNative::__GetSystemTimeAsFileTime)
 FCIMPLEND;
 
 
+#ifndef FEATURE_PAL
+
+FCIMPL1(VOID, SystemNative::GetSystemTimeWithLeapSecondsHandling, FullSystemTime *time)
+{
+    FCALL_CONTRACT;
+    INT64 timestamp;
+
+    g_pfnGetSystemTimeAsFileTime((FILETIME*)&timestamp);
+
+    if (::FileTimeToSystemTime((FILETIME*)&timestamp, &(time->systemTime)))
+    {
+        // to keep the time precision
+        time->hundredNanoSecond = timestamp % 10000; // 10000 is the number of 100-nano seconds per Millisecond
+    }
+    else
+    {
+        ::GetSystemTime(&(time->systemTime));
+        time->hundredNanoSecond = 0;
+    }
+
+    if (time->systemTime.wSecond > 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.wSecond = 59;
+        time->systemTime.wMilliseconds = 999;
+        time->hundredNanoSecond = 9999;
+    }
+}
+FCIMPLEND;
+
+FCIMPL2(FC_BOOL_RET, SystemNative::FileTimeToSystemTime, INT64 fileTime, FullSystemTime *time)
+{
+    FCALL_CONTRACT;
+    if (::FileTimeToSystemTime((FILETIME*)&fileTime, (LPSYSTEMTIME) time))
+    {
+        // to keep the time precision
+        time->hundredNanoSecond = fileTime % 10000; // 10000 is the number of 100-nano seconds per Millisecond
+        if (time->systemTime.wSecond > 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.wSecond = 59;
+            time->systemTime.wMilliseconds = 999;
+            time->hundredNanoSecond = 9999;
+        }
+        FC_RETURN_BOOL(TRUE);
+    }
+    FC_RETURN_BOOL(FALSE);
+}
+FCIMPLEND;
+
+FCIMPL2(FC_BOOL_RET, SystemNative::ValidateSystemTime, SYSTEMTIME *time, CLR_BOOL localTime)
+{
+    FCALL_CONTRACT;
+
+    if (localTime)
+    {
+        SYSTEMTIME st;
+        FC_RETURN_BOOL(::TzSpecificLocalTimeToSystemTime(NULL, time, &st));
+    }
+    else
+    {
+        FILETIME timestamp;
+        FC_RETURN_BOOL(::SystemTimeToFileTime(time, &timestamp));
+    }
+}
+FCIMPLEND;
+
+FCIMPL2(FC_BOOL_RET, SystemNative::SystemTimeToFileTime, SYSTEMTIME *time, INT64 *pFileTime)
+{
+    FCALL_CONTRACT;
+
+    BOOL ret = ::SystemTimeToFileTime(time, (LPFILETIME) pFileTime);
+    FC_RETURN_BOOL(ret);
+}
+FCIMPLEND;
+#endif // FEATURE_PAL
 
 
 FCIMPL0(UINT32, SystemNative::GetTickCount)
 {
     FCALL_CONTRACT;
-    
+
     return ::GetTickCount();
 }
 FCIMPLEND;
@@ -132,7 +210,7 @@ VOID QCALLTYPE SystemNative::Exit(INT32 exitcode)
 FCIMPL1(VOID,SystemNative::SetExitCode,INT32 exitcode)
 {
     FCALL_CONTRACT;
-    
+
     // The exit code for the process is communicated in one of two ways.  If the
     // entrypoint returns an 'int' we take that.  Otherwise we take a latched
     // process exit code.  This can be modified by the app via setting
@@ -144,7 +222,7 @@ FCIMPLEND
 FCIMPL0(INT32, SystemNative::GetExitCode)
 {
     FCALL_CONTRACT;
-    
+
     // Return whatever has been latched so far.  This is uninitialized to 0.
     return GetLatchedExitCode();
 }
@@ -161,7 +239,7 @@ void QCALLTYPE SystemNative::_GetCommandLine(QCall::StringHandleOnStack retStrin
     commandLine = WszGetCommandLine();
     if (commandLine==NULL)
         COMPlusThrowOM();
-    
+
     retString.Set(commandLine);
 
     END_QCALL;
@@ -187,10 +265,10 @@ FCIMPL0(Object*, SystemNative::GetCommandLineArgs)
         COMPlusThrowOM();
 
     _ASSERTE(numArgs > 0);
-    
+
     strArray = (PTRARRAYREF) AllocateObjectArray(numArgs, g_pStringClass);
     // Copy each argument into new Strings.
-    for(unsigned int i=0; i<numArgs; i++) 
+    for(unsigned int i=0; i<numArgs; i++)
     {
         STRINGREF str = StringObject::NewString(argv[i]);
         STRINGREF * destData = ((STRINGREF*)(strArray->GetDataPtr())) + i;
@@ -200,7 +278,7 @@ FCIMPL0(Object*, SystemNative::GetCommandLineArgs)
 
     HELPER_METHOD_FRAME_END();
 
-    return OBJECTREFToObject(strArray); 
+    return OBJECTREFToObject(strArray);
 }
 FCIMPLEND
 
@@ -208,7 +286,7 @@ FCIMPLEND
 FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE)
 {
     FCALL_CONTRACT;
-    
+
     I1ARRAYREF pArray(static_cast<I1Array *>(pStackTraceUNSAFE));
     StackTraceArray stackArray(pArray);
 
@@ -276,7 +354,7 @@ FCIMPL0(FC_BOOL_RET, SystemNative::HasShutdownStarted)
 {
     FCALL_CONTRACT;
 
-    // Return true if the EE has started to shutdown and is now going to 
+    // Return true if the EE has started to shutdown and is now going to
     // aggressively finalize objects referred to by static variables OR
     // if someone is unloading the current AppDomain AND we have started
     // finalizing objects referred to by static variables.
@@ -304,7 +382,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
         SO_TOLERANT;
     }CONTRACTL_END;
 
-    struct 
+    struct
     {
         STRINGREF refMesgString;
         EXCEPTIONREF refExceptionForWatsonBucketing;
@@ -313,7 +391,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
     ZeroMemory(&gc, sizeof(gc));
 
     GCPROTECT_BEGIN(gc);
-    
+
     gc.refMesgString = refMesgString;
     gc.refExceptionForWatsonBucketing = refExceptionForWatsonBucketing;
     gc.refErrorSourceString = refErrorSourceString;
@@ -344,12 +422,12 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
 
     WCHAR * errorSourceString = NULL;
 
-    if (gc.refErrorSourceString != NULL) 
+    if (gc.refErrorSourceString != NULL)
     {
         DWORD cchErrorSource = gc.refErrorSourceString->GetStringLength();
         errorSourceString = new (nothrow) WCHAR[cchErrorSource + 1];
 
-        if (errorSourceString != NULL) 
+        if (errorSourceString != NULL)
         {
             memcpyNoGCRefs(errorSourceString, gc.refErrorSourceString->GetBuffer(), cchErrorSource * sizeof(WCHAR));
             errorSourceString[cchErrorSource] = W('\0');
@@ -372,7 +450,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
             pszMessage = g_szFailFastBuffer;
         }
     }
-    
+
     if (cchMessage > 0)
         memcpyNoGCRefs(pszMessage, gc.refMesgString->GetBuffer(), cchMessage * sizeof(WCHAR));
     pszMessage[cchMessage] = W('\0');
@@ -396,7 +474,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
 
     Thread *pThread = GetThread();
 
-#ifndef FEATURE_PAL    
+#ifndef FEATURE_PAL
     // If we have the exception object, then try to setup
     // the watson bucket if it has any details.
     // On CoreCLR, Watson may not be enabled. Thus, we should
@@ -430,18 +508,18 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
 }
 
 // Note: Do not merge this FCALL method with any other FailFast overloads.
-// Watson uses the managed FailFast method with one String for crash dump bucketization. 
+// Watson uses the managed FailFast method with one String for crash dump bucketization.
 FCIMPL1(VOID, SystemNative::FailFast, StringObject* refMessageUNSAFE)
-{   
+{
     FCALL_CONTRACT;
 
     STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
-    
+
     HELPER_METHOD_FRAME_BEGIN_1(refMessage);
 
     // The HelperMethodFrame knows how to get the return address.
     UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
-    
+
     // Call the actual worker to perform failfast
     GenericFailFast(refMessage, NULL, retaddr, COR_E_FAILFAST, NULL);
 
@@ -450,16 +528,16 @@ FCIMPL1(VOID, SystemNative::FailFast, StringObject* refMessageUNSAFE)
 FCIMPLEND
 
 FCIMPL2(VOID, SystemNative::FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode)
-{   
+{
     FCALL_CONTRACT;
 
     STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
-    
+
     HELPER_METHOD_FRAME_BEGIN_1(refMessage);
 
     // The HelperMethodFrame knows how to get the return address.
     UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
-    
+
     // Call the actual worker to perform failfast
     GenericFailFast(refMessage, NULL, retaddr, exitCode, NULL);
 
@@ -468,7 +546,7 @@ FCIMPL2(VOID, SystemNative::FailFastWithExitCode, StringObject* refMessageUNSAFE
 FCIMPLEND
 
 FCIMPL2(VOID, SystemNative::FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE)
-{   
+{
     FCALL_CONTRACT;
 
     STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
@@ -478,7 +556,7 @@ FCIMPL2(VOID, SystemNative::FailFastWithException, StringObject* refMessageUNSAF
 
     // The HelperMethodFrame knows how to get the return address.
     UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
-    
+
     // Call the actual worker to perform failfast
     GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, NULL);
 
@@ -498,7 +576,7 @@ FCIMPL3(VOID, SystemNative::FailFastWithExceptionAndSource, StringObject* refMes
 
     // The HelperMethodFrame knows how to get the return address.
     UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
-    
+
     // Call the actual worker to perform failfast
     GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, errorSource);
 
@@ -534,6 +612,6 @@ BOOL QCALLTYPE SystemNative::WinRTSupported()
 
 
 
-       
+
 
 
index 9480ee9..803f1df 100644 (file)
 #include "fcall.h"
 #include "qcall.h"
 
+struct FullSystemTime
+{
+    SYSTEMTIME systemTime;
+    INT64 hundredNanoSecond;
+};
+
 class SystemNative
 {
     friend class DebugStackTrace;
@@ -38,6 +44,12 @@ private:
 
 public:
     // Functions on the System.Environment class
+#ifndef FEATURE_PAL
+    static FCDECL1(VOID, GetSystemTimeWithLeapSecondsHandling, FullSystemTime *time);
+    static FCDECL2(FC_BOOL_RET, ValidateSystemTime, SYSTEMTIME *time, CLR_BOOL localTime);
+    static FCDECL2(FC_BOOL_RET, FileTimeToSystemTime, INT64 fileTime, FullSystemTime *time);
+    static FCDECL2(FC_BOOL_RET, SystemTimeToFileTime, SYSTEMTIME *time, INT64 *pFileTime);
+#endif // FEATURE_PAL
     static FCDECL0(INT64, __GetSystemTimeAsFileTime);
     static FCDECL0(UINT32, GetTickCount);
 
index 04c9fba..2db7b70 100644 (file)
@@ -80,7 +80,7 @@ FCFuncStart(gEnumFuncs)
     QCFuncElement("GetEnumValuesAndNames",  ReflectionEnum::GetEnumValuesAndNames)
     FCFuncElement("InternalBoxEnum", ReflectionEnum::InternalBoxEnum)
     FCFuncElement("Equals", ReflectionEnum::InternalEquals)
-    FCFuncElement("InternalCompareTo", ReflectionEnum::InternalCompareTo)    
+    FCFuncElement("InternalCompareTo", ReflectionEnum::InternalCompareTo)
     FCFuncElement("InternalHasFlag", ReflectionEnum::InternalHasFlag)
 FCFuncEnd()
 
@@ -137,6 +137,12 @@ FCFuncStart(gDiagnosticsStackTrace)
 FCFuncEnd()
 
 FCFuncStart(gDateTimeFuncs)
+#if !defined(FEATURE_PAL)
+    FCFuncElement("GetSystemTimeWithLeapSecondsHandling", SystemNative::GetSystemTimeWithLeapSecondsHandling)
+    FCFuncElement("ValidateSystemTime", SystemNative::ValidateSystemTime)
+    FCFuncElement("FileTimeToSystemTime", SystemNative::FileTimeToSystemTime)
+    FCFuncElement("SystemTimeToFileTime", SystemNative::SystemTimeToFileTime)
+#endif // FEATURE_PAL
     FCFuncElement("GetSystemTimeAsFileTime", SystemNative::__GetSystemTimeAsFileTime)
 FCFuncEnd()
 
@@ -211,7 +217,7 @@ FCFuncStart(gSystem_RuntimeType)
     FCFuncElement("IsTypeExportedToWindowsRuntime", RuntimeTypeHandle::IsTypeExportedToWindowsRuntime)
 #endif
     FCFuncElement("IsWindowsRuntimeObjectType", RuntimeTypeHandle::IsWindowsRuntimeObjectType)
-#endif // defined(FEATURE_COMINTEROP) 
+#endif // defined(FEATURE_COMINTEROP)
 FCFuncEnd()
 
 FCFuncStart(gJitHelpers)
@@ -279,31 +285,31 @@ FCFuncStart(gCOMTypeHandleFuncs)
 FCFuncEnd()
 
 FCFuncStart(gMetaDataImport)
-    FCFuncElement("_GetDefaultValue", MetaDataImport::GetDefaultValue) 
-    FCFuncElement("_GetName", MetaDataImport::GetName) 
-    FCFuncElement("_GetUserString", MetaDataImport::GetUserString) 
-    FCFuncElement("_GetScopeProps", MetaDataImport::GetScopeProps)  
-    FCFuncElement("_GetClassLayout", MetaDataImport::GetClassLayout) 
-    FCFuncElement("_GetSignatureFromToken", MetaDataImport::GetSignatureFromToken) 
-    FCFuncElement("_GetNamespace", MetaDataImport::GetNamespace) 
+    FCFuncElement("_GetDefaultValue", MetaDataImport::GetDefaultValue)
+    FCFuncElement("_GetName", MetaDataImport::GetName)
+    FCFuncElement("_GetUserString", MetaDataImport::GetUserString)
+    FCFuncElement("_GetScopeProps", MetaDataImport::GetScopeProps)
+    FCFuncElement("_GetClassLayout", MetaDataImport::GetClassLayout)
+    FCFuncElement("_GetSignatureFromToken", MetaDataImport::GetSignatureFromToken)
+    FCFuncElement("_GetNamespace", MetaDataImport::GetNamespace)
     FCFuncElement("_GetEventProps", MetaDataImport::GetEventProps)
     FCFuncElement("_GetFieldDefProps", MetaDataImport::GetFieldDefProps)
-    FCFuncElement("_GetPropertyProps", MetaDataImport::GetPropertyProps)  
-    FCFuncElement("_GetParentToken", MetaDataImport::GetParentToken)  
-    FCFuncElement("_GetParamDefProps", MetaDataImport::GetParamDefProps) 
-    FCFuncElement("_GetGenericParamProps", MetaDataImport::GetGenericParamProps) 
-    
-    FCFuncElement("_Enum", MetaDataImport::Enum) 
-    FCFuncElement("_GetMemberRefProps", MetaDataImport::GetMemberRefProps) 
-    FCFuncElement("_GetCustomAttributeProps", MetaDataImport::GetCustomAttributeProps) 
-    FCFuncElement("_GetFieldOffset", MetaDataImport::GetFieldOffset) 
-
-    FCFuncElement("_GetSigOfFieldDef", MetaDataImport::GetSigOfFieldDef) 
-    FCFuncElement("_GetSigOfMethodDef", MetaDataImport::GetSigOfMethodDef) 
-    FCFuncElement("_GetFieldMarshal", MetaDataImport::GetFieldMarshal) 
-    FCFuncElement("_GetPInvokeMap", MetaDataImport::GetPinvokeMap) 
-    FCFuncElement("_IsValidToken", MetaDataImport::IsValidToken) 
-    FCFuncElement("_GetMarshalAs", MetaDataImport::GetMarshalAs)  
+    FCFuncElement("_GetPropertyProps", MetaDataImport::GetPropertyProps)
+    FCFuncElement("_GetParentToken", MetaDataImport::GetParentToken)
+    FCFuncElement("_GetParamDefProps", MetaDataImport::GetParamDefProps)
+    FCFuncElement("_GetGenericParamProps", MetaDataImport::GetGenericParamProps)
+
+    FCFuncElement("_Enum", MetaDataImport::Enum)
+    FCFuncElement("_GetMemberRefProps", MetaDataImport::GetMemberRefProps)
+    FCFuncElement("_GetCustomAttributeProps", MetaDataImport::GetCustomAttributeProps)
+    FCFuncElement("_GetFieldOffset", MetaDataImport::GetFieldOffset)
+
+    FCFuncElement("_GetSigOfFieldDef", MetaDataImport::GetSigOfFieldDef)
+    FCFuncElement("_GetSigOfMethodDef", MetaDataImport::GetSigOfMethodDef)
+    FCFuncElement("_GetFieldMarshal", MetaDataImport::GetFieldMarshal)
+    FCFuncElement("_GetPInvokeMap", MetaDataImport::GetPinvokeMap)
+    FCFuncElement("_IsValidToken", MetaDataImport::IsValidToken)
+    FCFuncElement("_GetMarshalAs", MetaDataImport::GetMarshalAs)
 FCFuncEnd()
 
 FCFuncStart(gSignatureNative)
@@ -336,9 +342,9 @@ FCFuncStart(gRuntimeMethodHandle)
     FCFuncElement("GetStubIfNeeded", RuntimeMethodHandle::GetStubIfNeeded)
     FCFuncElement("GetMethodFromCanonical", RuntimeMethodHandle::GetMethodFromCanonical)
     FCFuncElement("IsDynamicMethod", RuntimeMethodHandle::IsDynamicMethod)
-    FCFuncElement("GetMethodBody", RuntimeMethodHandle::GetMethodBody)    
+    FCFuncElement("GetMethodBody", RuntimeMethodHandle::GetMethodBody)
     QCFuncElement("IsCAVisibleFromDecoratedType", RuntimeMethodHandle::IsCAVisibleFromDecoratedType)
-    FCFuncElement("IsConstructor", RuntimeMethodHandle::IsConstructor)    
+    FCFuncElement("IsConstructor", RuntimeMethodHandle::IsConstructor)
     QCFuncElement("Destroy", RuntimeMethodHandle::Destroy)
     FCFuncElement("GetResolver", RuntimeMethodHandle::GetResolver)
     FCFuncElement("GetLoaderAllocator", RuntimeMethodHandle::GetLoaderAllocator)
@@ -372,7 +378,7 @@ FCFuncStart(gCOMModuleFuncs)
     FCFuncElement("GetTypes", COMModule::GetTypes)
     QCFuncElement("GetFullyQualifiedName", COMModule::GetFullyQualifiedName)
     QCFuncElement("nIsTransientInternal", COMModule::IsTransient)
-    FCFuncElement("IsResource", COMModule::IsResource)    
+    FCFuncElement("IsResource", COMModule::IsResource)
 FCFuncEnd()
 
 FCFuncStart(gCOMModuleBuilderFuncs)
@@ -551,7 +557,7 @@ FCFuncStart(gAssemblyBuilderFuncs)
     FCFuncElement("GetInMemoryAssemblyModule", AssemblyNative::GetInMemoryAssemblyModule)
 FCFuncEnd()
 
-#ifdef MDA_SUPPORTED 
+#ifdef MDA_SUPPORTED
 FCFuncStart(gMda)
     FCFuncElement("MemberInfoCacheCreation", MdaManagedSupport::MemberInfoCacheCreation)
     FCFuncElement("DateTimeInvalidLocalFormat", MdaManagedSupport::DateTimeInvalidLocalFormat)
@@ -701,7 +707,7 @@ FCFuncStart(gThreadPoolFuncs)
     FCFuncElement("NotifyWorkItemComplete", ThreadPoolNative::NotifyRequestComplete)
     FCFuncElement("NotifyWorkItemProgressNative", ThreadPoolNative::NotifyRequestProgress)
     QCFuncElement("InitializeVMTp", ThreadPoolNative::InitializeVMTp)
-    FCFuncElement("ReportThreadStatus", ThreadPoolNative::ReportThreadStatus)   
+    FCFuncElement("ReportThreadStatus", ThreadPoolNative::ReportThreadStatus)
     QCFuncElement("RequestWorkerThread", ThreadPoolNative::RequestWorkerThread)
 FCFuncEnd()
 
@@ -811,7 +817,7 @@ FCFuncStart(gGCInterfaceFuncs)
 
     FCFuncElement("_SuppressFinalize", GCInterface::SuppressFinalize)
     FCFuncElement("_ReRegisterForFinalize", GCInterface::ReRegisterForFinalize)
-    
+
     FCFuncElement("_GetAllocatedBytesForCurrentThread", GCInterface::GetAllocatedBytesForCurrentThread)
 FCFuncEnd()
 
@@ -866,7 +872,7 @@ FCFuncStart(gInteropMarshalFuncs)
     FCFuncElement("GetObjectsForNativeVariants", MarshalNative::GetObjectsForNativeVariants)
     FCFuncElement("GetStartComSlot", MarshalNative::GetStartComSlot)
     FCFuncElement("GetEndComSlot", MarshalNative::GetEndComSlot)
-    
+
     FCFuncElement("InitializeManagedWinRTFactoryObject", MarshalNative::InitializeManagedWinRTFactoryObject)
 
     FCFuncElement("GetNativeActivationFactory", MarshalNative::GetNativeActivationFactory)
@@ -914,7 +920,7 @@ FCFuncEnd()
 
 FCFuncStart(gInterlockedFuncs)
     FCIntrinsicSig("Exchange", &gsig_SM_RefInt_Int_RetInt, COMInterlocked::Exchange, CORINFO_INTRINSIC_InterlockedXchg32)
-    FCIntrinsicSig("Exchange", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::Exchange64, CORINFO_INTRINSIC_InterlockedXchg64)    
+    FCIntrinsicSig("Exchange", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::Exchange64, CORINFO_INTRINSIC_InterlockedXchg64)
     FCFuncElementSig("Exchange", &gsig_SM_RefDbl_Dbl_RetDbl, COMInterlocked::ExchangeDouble)
     FCFuncElementSig("Exchange", &gsig_SM_RefFlt_Flt_RetFlt, COMInterlocked::ExchangeFloat)
     FCFuncElementSig("Exchange", &gsig_SM_RefObj_Obj_RetObj, COMInterlocked::ExchangeObject)
@@ -1039,7 +1045,7 @@ FCFuncStart(gMngdHiddenLengthArrayMarshalerFuncs)
     FCFuncElement("ConvertContentsToManaged", MngdHiddenLengthArrayMarshaler::ConvertContentsToManaged)
     FCFuncElement("ClearNativeContents", MngdHiddenLengthArrayMarshaler::ClearNativeContents)
 FCFuncEnd()
-    
+
 FCFuncStart(gWinRTTypeNameConverterFuncs)
     FCFuncElement("ConvertToWinRTTypeName", StubHelpers::WinRTTypeNameConverter__ConvertToWinRTTypeName)
     FCFuncElement("GetTypeFromWinRTTypeName", StubHelpers::WinRTTypeNameConverter__GetTypeFromWinRTTypeName)
@@ -1085,16 +1091,16 @@ FCFuncStart(gStubHelperFuncs)
 #ifdef MDA_SUPPORTED
     FCFuncElement("CheckCollectedDelegateMDA", StubHelpers::CheckCollectedDelegateMDA)
 #endif // MDA_SUPPORTED
-#ifdef PROFILING_SUPPORTED    
+#ifdef PROFILING_SUPPORTED
     FCFuncElement("ProfilerBeginTransitionCallback", StubHelpers::ProfilerBeginTransitionCallback)
     FCFuncElement("ProfilerEndTransitionCallback", StubHelpers::ProfilerEndTransitionCallback)
-#endif    
+#endif
     FCFuncElement("CreateCustomMarshalerHelper", StubHelpers::CreateCustomMarshalerHelper)
     FCFuncElement("FmtClassUpdateNativeInternal", StubHelpers::FmtClassUpdateNativeInternal)
     FCFuncElement("FmtClassUpdateCLRInternal", StubHelpers::FmtClassUpdateCLRInternal)
     FCFuncElement("LayoutDestroyNativeInternal", StubHelpers::LayoutDestroyNativeInternal)
     FCFuncElement("AllocateInternal", StubHelpers::AllocateInternal)
-    FCFuncElement("strlen", StubHelpers::AnsiStrlen)    
+    FCFuncElement("strlen", StubHelpers::AnsiStrlen)
     FCFuncElement("MarshalToUnmanagedVaListInternal", StubHelpers::MarshalToUnmanagedVaListInternal)
     FCFuncElement("MarshalToManagedVaListInternal", StubHelpers::MarshalToManagedVaListInternal)
     FCFuncElement("CalcVaListSize", StubHelpers::CalcVaListSize)
@@ -1274,7 +1280,7 @@ FCClassElement("ManifestBasedResourceGroveler", "System.Resources",  gManifestBa
 FCClassElement("Marshal", "System.Runtime.InteropServices", gInteropMarshalFuncs)
 FCClassElement("Math", "System", gMathFuncs)
 FCClassElement("MathF", "System", gMathFFuncs)
-#ifdef MDA_SUPPORTED 
+#ifdef MDA_SUPPORTED
 FCClassElement("Mda", "System", gMda)
 #endif
 FCClassElement("MdUtf8String", "System", gMdUtf8String)
@@ -1284,10 +1290,10 @@ FCClassElement("MissingMemberException", "System",  gMissingMemberExceptionFuncs
 #ifdef FEATURE_COMINTEROP
 FCClassElement("MngdHiddenLengthArrayMarshaler", "System.StubHelpers", gMngdHiddenLengthArrayMarshalerFuncs)
 #endif // FEATURE_COMINTEROP
-FCClassElement("MngdNativeArrayMarshaler", "System.StubHelpers", gMngdNativeArrayMarshalerFuncs)    
-FCClassElement("MngdRefCustomMarshaler", "System.StubHelpers", gMngdRefCustomMarshalerFuncs)    
+FCClassElement("MngdNativeArrayMarshaler", "System.StubHelpers", gMngdNativeArrayMarshalerFuncs)
+FCClassElement("MngdRefCustomMarshaler", "System.StubHelpers", gMngdRefCustomMarshalerFuncs)
 #ifdef FEATURE_COMINTEROP
-FCClassElement("MngdSafeArrayMarshaler", "System.StubHelpers", gMngdSafeArrayMarshalerFuncs)  
+FCClassElement("MngdSafeArrayMarshaler", "System.StubHelpers", gMngdSafeArrayMarshalerFuncs)
 #endif // FEATURE_COMINTEROP
 FCClassElement("ModuleBuilder", "System.Reflection.Emit", gCOMModuleBuilderFuncs)
 FCClassElement("ModuleHandle", "System", gCOMModuleHandleFuncs)
@@ -1311,9 +1317,9 @@ FCClassElement("RegistrationServices", "System.Runtime.InteropServices", gRegist
 #endif // FEATURE_COMINTEROP
 
 FCClassElement("RuntimeAssembly", "System.Reflection", gRuntimeAssemblyFuncs)
-#ifdef FEATURE_COMINTEROP    
+#ifdef FEATURE_COMINTEROP
 FCClassElement("RuntimeClass", "System.Runtime.InteropServices.WindowsRuntime", gRuntimeClassFuncs)
-#endif // FEATURE_COMINTEROP    
+#endif // FEATURE_COMINTEROP
 FCClassElement("RuntimeFieldHandle", "System", gCOMFieldHandleNewFuncs)
 FCClassElement("RuntimeHelpers", "System.Runtime.CompilerServices", gCompilerFuncs)
 FCClassElement("RuntimeImports", "System.Runtime", gRuntimeImportsFuncs)