Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Baulig <mabaul@microsoft.com>2019-06-05 21:31:28 +0300
committerMarek Safar <marek.safar@gmail.com>2019-06-06 20:38:39 +0300
commitd8554258fa53bf7d00d301260719946dc2cb591d (patch)
treec5baa42c1aabed902794e649b4084110576122d8 /src
parent9bfc928c1c979aee7181e2be56ba39d01d0d444d (diff)
Make `DateTimeFormatInfo` and `DateTimeParse` more linker friendly.
The goal is to allow the linker to remove some of the globalization code that is conditional to `GlobalizationMode.Invariant`. Since the linker does not currently support dead code elimination, it cannot break down any conditionals inside method bodies. One trick that we use to work around this is to move those conditional pieces into separate methods; then we can give the linker a list of those methods and tell it to replace their bodies with exceptions. In this particular case, we do not want to access the `JapaneseCalendar` and `TaiwanCalendar` types from methods that could not (currently) be linked out. The `DateTimeFormatInfo.PopulateSpecialTokenHashTable()` method does not explicitly reference any of those, but it is quite big so we benefit from having the non-invariant pieces in a separate method which can then be removed.
Diffstat (limited to 'src')
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs263
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs18
2 files changed, 150 insertions, 131 deletions
diff --git a/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs b/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs
index 5393d6a37c..07a3c46e17 100644
--- a/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs
@@ -2320,46 +2320,14 @@ namespace System.Globalization
InsertHash(temp, this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
InsertHash(temp, this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
- // TODO: This ignores similar custom cultures
- if (!GlobalizationMode.Invariant && LanguageName.Equals("sq"))
- {
- // Albanian allows time formats like "12:00.PD"
- InsertHash(temp, IgnorablePeriod + this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
- InsertHash(temp, IgnorablePeriod + this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
- }
+ // For some cultures, the date separator works more like a comma, being allowed before or after any date part.
+ // In these cultures, we do not use normal date separator since we disallow date separator after a date terminal state.
+ // This is determined in DateTimeFormatInfoScanner. Use this flag to determine if we should treat date separator as ignorable symbol.
+ bool useDateSepAsIgnorableSymbol = false;
if (!GlobalizationMode.Invariant)
{
- // CJK suffix
- InsertHash(temp, CJKYearSuff, TokenType.SEP_YearSuff, 0);
- InsertHash(temp, KoreanYearSuff, TokenType.SEP_YearSuff, 0);
- InsertHash(temp, CJKMonthSuff, TokenType.SEP_MonthSuff, 0);
- InsertHash(temp, KoreanMonthSuff, TokenType.SEP_MonthSuff, 0);
- InsertHash(temp, CJKDaySuff, TokenType.SEP_DaySuff, 0);
- InsertHash(temp, KoreanDaySuff, TokenType.SEP_DaySuff, 0);
-
- InsertHash(temp, CJKHourSuff, TokenType.SEP_HourSuff, 0);
- InsertHash(temp, ChineseHourSuff, TokenType.SEP_HourSuff, 0);
- InsertHash(temp, CJKMinuteSuff, TokenType.SEP_MinuteSuff, 0);
- InsertHash(temp, CJKSecondSuff, TokenType.SEP_SecondSuff, 0);
-
- if (!AppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == (int)CalendarId.JAPAN)
- {
- // We need to support parsing the dates has the start of era symbol which means it is year 1 in the era.
- // The start of era symbol has to be followed by the year symbol suffix, otherwise it would be invalid date.
- InsertHash(temp, JapaneseEraStart, TokenType.YearNumberToken, 1);
- InsertHash(temp, "(", TokenType.IgnorableSymbol, 0);
- InsertHash(temp, ")", TokenType.IgnorableSymbol, 0);
- }
-
- // TODO: This ignores other custom cultures that might want to do something similar
- if (koreanLanguage)
- {
- // Korean suffix
- InsertHash(temp, KoreanHourSuff, TokenType.SEP_HourSuff, 0);
- InsertHash(temp, KoreanMinuteSuff, TokenType.SEP_MinuteSuff, 0);
- InsertHash(temp, KoreanSecondSuff, TokenType.SEP_SecondSuff, 0);
- }
+ PopulateSpecialTokenHashTable(temp, ref useDateSepAsIgnorableSymbol);
}
if (!GlobalizationMode.Invariant && LanguageName.Equals("ky"))
@@ -2372,62 +2340,6 @@ namespace System.Globalization
InsertHash(temp, dateSeparatorOrTimeZoneOffset, TokenType.SEP_DateOrOffset, 0);
}
- String[] dateWords = null;
- DateTimeFormatInfoScanner scanner = null;
-
- if (!GlobalizationMode.Invariant)
- {
- // We need to rescan the date words since we're always synthetic
- scanner = new DateTimeFormatInfoScanner();
- dateWords = scanner.GetDateWordsOfDTFI(this);
- }
-
- // Ensure the formatflags is initialized.
- DateTimeFormatFlags flag = FormatFlags;
-
- // For some cultures, the date separator works more like a comma, being allowed before or after any date part.
- // In these cultures, we do not use normal date separator since we disallow date separator after a date terminal state.
- // This is determined in DateTimeFormatInfoScanner. Use this flag to determine if we should treat date separator as ignorable symbol.
- bool useDateSepAsIgnorableSymbol = false;
-
- String monthPostfix = null;
- if (!GlobalizationMode.Invariant && dateWords != null)
- {
- // There are DateWords. It could be a real date word (such as "de"), or a monthPostfix.
- // The monthPostfix starts with '\xfffe' (MonthPostfixChar), followed by the real monthPostfix.
- for (int i = 0; i < dateWords.Length; i++)
- {
- switch (dateWords[i][0])
- {
- // This is a month postfix
- case DateTimeFormatInfoScanner.MonthPostfixChar:
- // Get the real month postfix.
- monthPostfix = dateWords[i].Substring(1);
- // Add the month name + postfix into the token.
- AddMonthNames(temp, monthPostfix);
- break;
- case DateTimeFormatInfoScanner.IgnorableSymbolChar:
- String symbol = dateWords[i].Substring(1);
- InsertHash(temp, symbol, TokenType.IgnorableSymbol, 0);
- if (this.DateSeparator.Trim(null).Equals(symbol))
- {
- // The date separator is the same as the ignorable symbol.
- useDateSepAsIgnorableSymbol = true;
- }
- break;
- default:
- InsertHash(temp, dateWords[i], TokenType.DateWordToken, 0);
- // TODO: This ignores similar custom cultures
- if (LanguageName.Equals("eu"))
- {
- // Basque has date words with leading dots
- InsertHash(temp, IgnorablePeriod + dateWords[i], TokenType.DateWordToken, 0);
- }
- break;
- }
- }
- }
-
if (!useDateSepAsIgnorableSymbol)
{
// Use the normal date separator.
@@ -2481,42 +2393,6 @@ namespace System.Globalization
InsertHash(temp, GetAbbreviatedEraName(i), TokenType.EraToken, i);
}
- // TODO: This ignores other cultures that might want to do something similar
- if (!GlobalizationMode.Invariant && LanguageName.Equals(JapaneseLangName))
- {
- // Japanese allows day of week forms like: "(Tue)"
- for (int i = 0; i < 7; i++)
- {
- String specialDayOfWeek = "(" + GetAbbreviatedDayName((DayOfWeek)i) + ")";
- InsertHash(temp, specialDayOfWeek, TokenType.DayOfWeekToken, i);
- }
- if (this.Calendar.GetType() != typeof(JapaneseCalendar))
- {
- // Special case for Japanese. If this is a Japanese DTFI, and the calendar is not Japanese calendar,
- // we will check Japanese Era name as well when the calendar is Gregorian.
- DateTimeFormatInfo jaDtfi = GetJapaneseCalendarDTFI();
- for (int i = 1; i <= jaDtfi.Calendar.Eras.Length; i++)
- {
- InsertHash(temp, jaDtfi.GetEraName(i), TokenType.JapaneseEraToken, i);
- InsertHash(temp, jaDtfi.GetAbbreviatedEraName(i), TokenType.JapaneseEraToken, i);
- // m_abbrevEnglishEraNames[0] contains the name for era 1, so the token value is i+1.
- InsertHash(temp, jaDtfi.AbbreviatedEnglishEraNames[i - 1], TokenType.JapaneseEraToken, i);
- }
- }
- }
- // TODO: This prohibits similar custom cultures, but we hard coded the name
- else if (!GlobalizationMode.Invariant && CultureName.Equals("zh-TW"))
- {
- DateTimeFormatInfo twDtfi = GetTaiwanCalendarDTFI();
- for (int i = 1; i <= twDtfi.Calendar.Eras.Length; i++)
- {
- if (twDtfi.GetEraName(i).Length > 0)
- {
- InsertHash(temp, twDtfi.GetEraName(i), TokenType.TEraToken, i);
- }
- }
- }
-
InsertHash(temp, InvariantInfo.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
InsertHash(temp, InvariantInfo.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
@@ -2561,6 +2437,135 @@ namespace System.Globalization
return (temp);
}
+ private void PopulateSpecialTokenHashTable(TokenHashValue[] temp, ref bool useDateSepAsIgnorableSymbol)
+ {
+ // TODO: This ignores similar custom cultures
+ if (LanguageName.Equals("sq"))
+ {
+ // Albanian allows time formats like "12:00.PD"
+ InsertHash(temp, IgnorablePeriod + this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
+ InsertHash(temp, IgnorablePeriod + this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
+ }
+
+ // CJK suffix
+ InsertHash(temp, CJKYearSuff, TokenType.SEP_YearSuff, 0);
+ InsertHash(temp, KoreanYearSuff, TokenType.SEP_YearSuff, 0);
+ InsertHash(temp, CJKMonthSuff, TokenType.SEP_MonthSuff, 0);
+ InsertHash(temp, KoreanMonthSuff, TokenType.SEP_MonthSuff, 0);
+ InsertHash(temp, CJKDaySuff, TokenType.SEP_DaySuff, 0);
+ InsertHash(temp, KoreanDaySuff, TokenType.SEP_DaySuff, 0);
+
+ InsertHash(temp, CJKHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, ChineseHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, CJKMinuteSuff, TokenType.SEP_MinuteSuff, 0);
+ InsertHash(temp, CJKSecondSuff, TokenType.SEP_SecondSuff, 0);
+
+ if (!AppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == (int)CalendarId.JAPAN)
+ {
+ // We need to support parsing the dates has the start of era symbol which means it is year 1 in the era.
+ // The start of era symbol has to be followed by the year symbol suffix, otherwise it would be invalid date.
+ InsertHash(temp, JapaneseEraStart, TokenType.YearNumberToken, 1);
+ InsertHash(temp, "(", TokenType.IgnorableSymbol, 0);
+ InsertHash(temp, ")", TokenType.IgnorableSymbol, 0);
+ }
+
+ // TODO: This ignores other custom cultures that might want to do something similar
+ if (LanguageName.Equals(KoreanLangName))
+ {
+ // Korean suffix
+ InsertHash(temp, KoreanHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, KoreanMinuteSuff, TokenType.SEP_MinuteSuff, 0);
+ InsertHash(temp, KoreanSecondSuff, TokenType.SEP_SecondSuff, 0);
+ }
+
+ DateTimeFormatInfoScanner scanner = new DateTimeFormatInfoScanner();
+ String[] dateWords = scanner.GetDateWordsOfDTFI(this);
+
+ // Ensure the formatflags is initialized.
+ DateTimeFormatFlags flag = FormatFlags;
+
+ String monthPostfix = null;
+ if (dateWords != null)
+ {
+ // There are DateWords. It could be a real date word (such as "de"), or a monthPostfix.
+ // The monthPostfix starts with '\xfffe' (MonthPostfixChar), followed by the real monthPostfix.
+ for (int i = 0; i < dateWords.Length; i++)
+ {
+ switch (dateWords[i][0])
+ {
+ // This is a month postfix
+ case DateTimeFormatInfoScanner.MonthPostfixChar:
+ // Get the real month postfix.
+ monthPostfix = dateWords[i].Substring(1);
+ // Add the month name + postfix into the token.
+ AddMonthNames(temp, monthPostfix);
+ break;
+ case DateTimeFormatInfoScanner.IgnorableSymbolChar:
+ String symbol = dateWords[i].Substring(1);
+ InsertHash(temp, symbol, TokenType.IgnorableSymbol, 0);
+ if (this.DateSeparator.Trim(null).Equals(symbol))
+ {
+ // The date separator is the same as the ignorable symbol.
+ useDateSepAsIgnorableSymbol = true;
+ }
+ break;
+ default:
+ InsertHash(temp, dateWords[i], TokenType.DateWordToken, 0);
+ // TODO: This ignores similar custom cultures
+ if (LanguageName.Equals("eu"))
+ {
+ // Basque has date words with leading dots
+ InsertHash(temp, IgnorablePeriod + dateWords[i], TokenType.DateWordToken, 0);
+ }
+ break;
+ }
+ }
+ }
+
+ // TODO: This ignores other cultures that might want to do something similar
+ if (LanguageName.Equals(JapaneseLangName))
+ {
+ // Japanese allows day of week forms like: "(Tue)"
+ for (int i = 0; i < 7; i++)
+ {
+ String specialDayOfWeek = "(" + GetAbbreviatedDayName((DayOfWeek)i) + ")";
+ InsertHash(temp, specialDayOfWeek, TokenType.DayOfWeekToken, i);
+ }
+ if (!IsJapaneseCalendar(this.Calendar))
+ {
+ // Special case for Japanese. If this is a Japanese DTFI, and the calendar is not Japanese calendar,
+ // we will check Japanese Era name as well when the calendar is Gregorian.
+ DateTimeFormatInfo jaDtfi = GetJapaneseCalendarDTFI();
+ for (int i = 1; i <= jaDtfi.Calendar.Eras.Length; i++)
+ {
+ InsertHash(temp, jaDtfi.GetEraName(i), TokenType.JapaneseEraToken, i);
+ InsertHash(temp, jaDtfi.GetAbbreviatedEraName(i), TokenType.JapaneseEraToken, i);
+ // m_abbrevEnglishEraNames[0] contains the name for era 1, so the token value is i+1.
+ InsertHash(temp, jaDtfi.AbbreviatedEnglishEraNames[i - 1], TokenType.JapaneseEraToken, i);
+ }
+ }
+ }
+ // TODO: This prohibits similar custom cultures, but we hard coded the name
+ else if (CultureName.Equals("zh-TW"))
+ {
+ DateTimeFormatInfo twDtfi = GetTaiwanCalendarDTFI();
+ for (int i = 1; i <= twDtfi.Calendar.Eras.Length; i++)
+ {
+ if (twDtfi.GetEraName(i).Length > 0)
+ {
+ InsertHash(temp, twDtfi.GetEraName(i), TokenType.TEraToken, i);
+ }
+ }
+ }
+ }
+
+ private static bool IsJapaneseCalendar(Calendar calendar)
+ {
+ if (GlobalizationMode.Invariant)
+ throw new PlatformNotSupportedException();
+ return calendar.GetType() == typeof(JapaneseCalendar);
+ }
+
private void AddMonthNames(TokenHashValue[] temp, String monthPostfix)
{
for (int i = 1; i <= 13; i++)
diff --git a/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs b/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs
index fcef1fa113..63f3e793e9 100644
--- a/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs
@@ -1056,7 +1056,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
throw new PlatformNotSupportedException();
}
- result.calendar = JapaneseCalendar.GetDefaultInstance();
+ result.calendar = GetJapaneseCalendarDefaultInstance();
dtfi = DateTimeFormatInfo.GetJapaneseCalendarDTFI();
if (result.era != -1)
{
@@ -1075,7 +1075,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
throw new PlatformNotSupportedException();
}
- result.calendar = TaiwanCalendar.GetDefaultInstance();
+ result.calendar = GetTaiwanCalendarDefaultInstance();
dtfi = DateTimeFormatInfo.GetTaiwanCalendarDTFI();
if (result.era != -1)
{
@@ -1169,6 +1169,20 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return true;
}
+ private static Calendar GetJapaneseCalendarDefaultInstance()
+ {
+ if (GlobalizationMode.Invariant)
+ throw new PlatformNotSupportedException();
+ return JapaneseCalendar.GetDefaultInstance();
+ }
+
+ internal static Calendar GetTaiwanCalendarDefaultInstance()
+ {
+ if (GlobalizationMode.Invariant)
+ throw new PlatformNotSupportedException();
+ return TaiwanCalendar.GetDefaultInstance();
+ }
+
private static Boolean VerifyValidPunctuation(ref __DTString str)
{
// Compatability Behavior. Allow trailing nulls and surrounding hashes