summaryrefslogtreecommitdiff
path: root/src/mscorlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib')
-rw-r--r--src/mscorlib/src/System/String.cs81
-rw-r--r--src/mscorlib/src/System/TimeZoneInfo.cs61
2 files changed, 114 insertions, 28 deletions
diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs
index 24795050ef..7939fdefcf 100644
--- a/src/mscorlib/src/System/String.cs
+++ b/src/mscorlib/src/System/String.cs
@@ -372,19 +372,23 @@ namespace System {
char* a = ap;
char* b = bp;
- // unroll the loop
-#if AMD64
+#if WIN64
+ // Single int read aligns pointers for the following long reads
+ // PERF: No length check needed as there is always an int32 worth of string allocated
+ // This read can also include the null terminator which both strings will have
+ if (*(int*)a != *(int*)b) return false;
+ length -= 2; a += 2; b += 2;
+
// for AMD64 bit platform we unroll by 12 and
// check 3 qword at a time. This is less code
// than the 32 bit case and is a shorter path length.
- // Reads are unaligned
while (length >= 12)
{
if (*(long*)a != *(long*)b) return false;
if (*(long*)(a+4) != *(long*)(b+4)) return false;
if (*(long*)(a+8) != *(long*)(b+8)) return false;
- a += 12; b += 12; length -= 12;
+ length -= 12; a += 12; b += 12;
}
#else
while (length >= 10)
@@ -394,7 +398,7 @@ namespace System {
if (*(int*)(a+4) != *(int*)(b+4)) return false;
if (*(int*)(a+6) != *(int*)(b+6)) return false;
if (*(int*)(a+8) != *(int*)(b+8)) return false;
- a += 10; b += 10; length -= 10;
+ length -= 10; a += 10; b += 10;
}
#endif
@@ -405,13 +409,70 @@ namespace System {
while (length > 0)
{
if (*(int*)a != *(int*)b) break;
- a += 2; b += 2; length -= 2;
+ length -= 2; a += 2; b += 2;
}
return (length <= 0);
}
}
-
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ private unsafe static bool StartsWithOrdinalHelper(String str, String startsWith)
+ {
+ Contract.Requires(str != null);
+ Contract.Requires(startsWith != null);
+ Contract.Requires(str.Length >= startsWith.Length);
+
+ int length = startsWith.Length;
+
+ fixed (char* ap = &str.m_firstChar) fixed (char* bp = &startsWith.m_firstChar)
+ {
+ char* a = ap;
+ char* b = bp;
+
+#if WIN64
+ // Single int read aligns pointers for the following long reads
+ // No length check needed as this method is called when length >= 2
+ Contract.Assert(length >= 2);
+ if (*(int*)a != *(int*)b) goto ReturnFalse;
+ length -= 2; a += 2; b += 2;
+
+ while (length >= 12)
+ {
+ if (*(long*)a != *(long*)b) goto ReturnFalse;
+ if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
+ if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
+ length -= 12; a += 12; b += 12;
+ }
+#else
+ while (length >= 10)
+ {
+ if (*(int*)a != *(int*)b) goto ReturnFalse;
+ if (*(int*)(a+2) != *(int*)(b+2)) goto ReturnFalse;
+ if (*(int*)(a+4) != *(int*)(b+4)) goto ReturnFalse;
+ if (*(int*)(a+6) != *(int*)(b+6)) goto ReturnFalse;
+ if (*(int*)(a+8) != *(int*)(b+8)) goto ReturnFalse;
+ length -= 10; a += 10; b += 10;
+ }
+#endif
+
+ while (length >= 2)
+ {
+ if (*(int*)a != *(int*)b) goto ReturnFalse;
+ length -= 2; a += 2; b += 2;
+ }
+
+ // PERF: This depends on the fact that the String objects are always zero terminated
+ // and that the terminating zero is not included in the length. For even string sizes
+ // this compare can include the zero terminator. Bitwise OR avoids a branch.
+ return length == 0 | *a == *b;
+
+ ReturnFalse:
+ return false;
+ }
+ }
+
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe static int CompareOrdinalHelper(String strA, String strB)
{
@@ -453,9 +514,9 @@ namespace System {
diffOffset = 8;
break;
}
+ length -= 10;
a += 10;
b += 10;
- length -= 10;
}
if( diffOffset != -1) {
@@ -479,9 +540,9 @@ namespace System {
if (*(int*)a != *(int*)b) {
break;
}
+ length -= 2;
a += 2;
b += 2;
- length -= 2;
}
if( length > 0) {
@@ -2559,7 +2620,7 @@ namespace System {
}
return (value.Length == 1) ?
true : // First char is the same and thats all there is to compare
- (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0);
+ StartsWithOrdinalHelper(this, value);
case StringComparison.OrdinalIgnoreCase:
if( this.Length < value.Length) {
diff --git a/src/mscorlib/src/System/TimeZoneInfo.cs b/src/mscorlib/src/System/TimeZoneInfo.cs
index c4548f3747..26cdfe16d9 100644
--- a/src/mscorlib/src/System/TimeZoneInfo.cs
+++ b/src/mscorlib/src/System/TimeZoneInfo.cs
@@ -3471,33 +3471,58 @@ namespace System {
// fall back to reading from the local machine
// when the cache is not fully populated
if (!cachedData.m_allSystemTimeZonesRead) {
+ result = TryGetTimeZoneFromLocalMachine(id, dstDisabled, out value, out e, cachedData);
+ }
+#if PLATFORM_UNIX
+ // On UNIX, there may be some tzfiles that aren't in the zones.tab file, and thus aren't returned from GetSystemTimeZones().
+ // If a caller asks for one of these zones before calling GetSystemTimeZones(), the time zone is returned successfully. But if
+ // GetSystemTimeZones() is called first, FindSystemTimeZoneById will throw TimeZoneNotFoundException, which is inconsistent.
+ // To fix this, even if m_allSystemTimeZonesRead is true, try reading the tzfile from disk, but don't add the time zone to the
+ // list returned from GetSystemTimeZones(). These time zones will only be available if asked for directly.
+ else {
+ result = TryGetTimeZoneFromLocalMachine(id, dstDisabled, out value, out e, cachedData);
+ }
+#else
+ else {
+ result = TimeZoneInfoResult.TimeZoneNotFoundException;
+ value = null;
+ }
+#endif // PLATFORM_UNIX
+
+ return result;
+ }
+
+ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData)
+ {
+ TimeZoneInfoResult result;
+ TimeZoneInfo match;
+
#if FEATURE_WIN32_REGISTRY
- result = TryGetTimeZoneByRegistryKey(id, out match, out e);
+ result = TryGetTimeZoneByRegistryKey(id, out match, out e);
#elif PLATFORM_UNIX
- result = TryGetTimeZoneByFile(id, out match, out e);
+ result = TryGetTimeZoneByFile(id, out match, out e);
#endif // FEATURE_WIN32_REGISTRY
- if (result == TimeZoneInfoResult.Success) {
- if (cachedData.m_systemTimeZones == null)
- cachedData.m_systemTimeZones = new Dictionary<string, TimeZoneInfo>();
+ if (result == TimeZoneInfoResult.Success)
+ {
+ if (cachedData.m_systemTimeZones == null)
+ cachedData.m_systemTimeZones = new Dictionary<string, TimeZoneInfo>();
- cachedData.m_systemTimeZones.Add(id, match);
+ cachedData.m_systemTimeZones.Add(id, match);
- if (dstDisabled && match.m_supportsDaylightSavingTime) {
- // we found a cache hit but we want a time zone without DST and this one has DST data
- value = CreateCustomTimeZone(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName);
- }
- else {
- value = new TimeZoneInfo(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName,
- match.m_daylightDisplayName, match.m_adjustmentRules, false);
- }
+ if (dstDisabled && match.m_supportsDaylightSavingTime)
+ {
+ // we found a cache hit but we want a time zone without DST and this one has DST data
+ value = CreateCustomTimeZone(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName);
}
- else {
- value = null;
+ else
+ {
+ value = new TimeZoneInfo(match.m_id, match.m_baseUtcOffset, match.m_displayName, match.m_standardDisplayName,
+ match.m_daylightDisplayName, match.m_adjustmentRules, false);
}
}
- else {
- result = TimeZoneInfoResult.TimeZoneNotFoundException;
+ else
+ {
value = null;
}