Skip to content

Commit c277b32

Browse files
Drop size of hello world to 745 kB (#118718)
(With `StackTraceSupport=false`, `OptimizationPreference=Size`, `UseSystemResourceKeys=true`) The thing that makes the difference is that we are no longer boxing enums and we can get rid of the super expensive enum stringification logic. Not boxing enums also means that #118640 can fully kick in because enums are the last remaining place that looks at custom attributes (looking for `FlagsAttribute`). Co-authored-by: Jan Kotas <[email protected]>
1 parent 8d1ad7f commit c277b32

File tree

4 files changed

+79
-55
lines changed

4 files changed

+79
-55
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal bool IsEnum
3737

3838
// Generic type definitions that return true for IsPrimitive are type definitions of generic enums.
3939
// Otherwise check the base type.
40-
return IsPrimitive && (IsGenericTypeDefinition || NonArrayBaseType == MethodTable.Of<Enum>());
40+
return IsPrimitive && (IsGenericTypeDefinition || NonArrayBaseType != MethodTable.Of<ValueType>());
4141
}
4242
}
4343

src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ public static long GetTotalAllocatedBytes(bool precise = false)
764764

765765
/// <summary>Gets garbage collection memory information.</summary>
766766
/// <returns>An object that contains information about the garbage collector's memory usage.</returns>
767-
public static GCMemoryInfo GetGCMemoryInfo() => GetGCMemoryInfo(GCKind.Any);
767+
public static GCMemoryInfo GetGCMemoryInfo() => GetGCMemoryInfoUnchecked(GCKind.Any);
768768

769769
/// <summary>Gets garbage collection memory information.</summary>
770770
/// <param name="kind">The kind of collection for which to retrieve memory information.</param>
@@ -780,6 +780,11 @@ public static GCMemoryInfo GetGCMemoryInfo(GCKind kind)
780780
GCKind.Background));
781781
}
782782

783+
return GetGCMemoryInfoUnchecked(kind);
784+
}
785+
786+
private static GCMemoryInfo GetGCMemoryInfoUnchecked(GCKind kind)
787+
{
783788
var data = new GCMemoryInfoData();
784789
RuntimeImports.RhGetMemoryInfo(ref data.GetRawData(), kind);
785790
return new GCMemoryInfo(data);

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,14 @@ private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
289289
{
290290
if (throwOnError)
291291
{
292-
string msg = SR.Format(SR.Thread_ApartmentState_ChangeFailed, retState);
292+
// NOTE: We do the enum stringification manually to avoid introducing a dependency
293+
// on enum stringification in small apps. We set apartment state in the startup path.
294+
string msg = SR.Format(SR.Thread_ApartmentState_ChangeFailed, retState switch
295+
{
296+
ApartmentState.MTA => "MTA",
297+
ApartmentState.STA => "STA",
298+
_ => "Unknown"
299+
});
293300
throw new InvalidOperationException(msg);
294301
}
295302

src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -625,15 +625,11 @@ private static CultureData CreateCultureWithInvariantData()
625625
invariant._iFirstDayOfWeek = 0; // first day of week
626626
invariant._iFirstWeekOfYear = 0; // first week of year
627627

628-
// all available calendar type(s). The first one is the default calendar
629-
invariant._waCalendars = [CalendarId.GREGORIAN];
630-
631-
if (!GlobalizationMode.InvariantNoLoad)
632-
{
633-
// Store for specific data about each calendar
634-
invariant._calendars = new CalendarData[CalendarData.MAX_CALENDARS];
635-
invariant._calendars[0] = CalendarData.Invariant;
636-
}
628+
// Calendar information is expensive size-wise, especially for AOT.
629+
// CalendarData.Invariant is special cased in _waCalendars and _calendars
630+
// accessors and gets initialized lazily.
631+
// invariant._waCalendars
632+
// invariant._calendars
637633

638634
// Text information
639635
invariant._iReadingLayout = 0;
@@ -1647,61 +1643,68 @@ internal CalendarId[] CalendarIds
16471643
{
16481644
get
16491645
{
1650-
if (_waCalendars == null && !GlobalizationMode.Invariant)
1646+
if (_waCalendars == null)
16511647
{
1652-
// We pass in an array of ints, and native side fills it up with count calendars.
1653-
// We then have to copy that list to a new array of the right size.
1654-
// Default calendar should be first
1655-
CalendarId[] calendars = new CalendarId[23];
1656-
Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
1657-
1658-
int count = CalendarData.GetCalendarsCore(_sWindowsName, _bUseOverrides, calendars);
1659-
1660-
// See if we had a calendar to add.
1661-
if (count == 0)
1648+
if (GlobalizationMode.Invariant || IsInvariantCulture)
16621649
{
1663-
// Failed for some reason, just grab Gregorian from Invariant
1664-
_waCalendars = Invariant._waCalendars!;
1650+
// We do this lazily as opposed in CreateCultureWithInvariantData to avoid introducing
1651+
// enum arrays into apps that otherwise wouldn't have them. This helps with size in AOT.
1652+
_waCalendars = [CalendarId.GREGORIAN];
16651653
}
16661654
else
16671655
{
1668-
// The OS may not return calendar 4 for zh-TW, but we've always allowed it.
1669-
// TODO: Is this hack necessary long-term?
1670-
if (_sWindowsName == "zh-TW")
1671-
{
1672-
bool found = false;
1656+
// We pass in an array of ints, and native side fills it up with count calendars.
1657+
// We then have to copy that list to a new array of the right size.
1658+
// Default calendar should be first
1659+
CalendarId[] calendars = new CalendarId[23];
1660+
Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
1661+
1662+
int count = CalendarData.GetCalendarsCore(_sWindowsName, _bUseOverrides, calendars);
16731663

1674-
// Do we need to insert calendar 4?
1675-
for (int i = 0; i < count; i++)
1664+
// See if we had a calendar to add.
1665+
if (count == 0)
1666+
{
1667+
// Failed for some reason, just use Gregorian
1668+
_waCalendars = Invariant.CalendarIds;
1669+
}
1670+
else
1671+
{
1672+
// The OS may not return calendar 4 for zh-TW, but we've always allowed it.
1673+
// TODO: Is this hack necessary long-term?
1674+
if (_sWindowsName == "zh-TW")
16761675
{
1677-
// Stop if we found calendar four
1678-
if (calendars[i] == CalendarId.TAIWAN)
1676+
bool found = false;
1677+
1678+
// Do we need to insert calendar 4?
1679+
for (int i = 0; i < count; i++)
16791680
{
1680-
found = true;
1681-
break;
1681+
// Stop if we found calendar four
1682+
if (calendars[i] == CalendarId.TAIWAN)
1683+
{
1684+
found = true;
1685+
break;
1686+
}
16821687
}
1683-
}
16841688

1685-
// If not found then insert it
1686-
if (!found)
1687-
{
1688-
// Insert it as the 2nd calendar
1689-
count++;
1690-
// Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
1691-
Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1);
1692-
calendars[1] = CalendarId.TAIWAN;
1689+
// If not found then insert it
1690+
if (!found)
1691+
{
1692+
// Insert it as the 2nd calendar
1693+
count++;
1694+
// Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
1695+
Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1);
1696+
calendars[1] = CalendarId.TAIWAN;
1697+
}
16931698
}
1694-
}
1695-
1696-
// It worked, remember the list
1697-
CalendarId[] temp = new CalendarId[count];
1698-
Array.Copy(calendars, temp, count);
16991699

1700-
_waCalendars = temp;
1700+
// It worked, remember the list
1701+
CalendarId[] temp = new CalendarId[count];
1702+
Array.Copy(calendars, temp, count);
1703+
_waCalendars = temp;
1704+
}
17011705
}
17021706
}
1703-
1704-
return _waCalendars!;
1707+
return _waCalendars;
17051708
}
17061709
}
17071710

@@ -1737,8 +1740,17 @@ internal CalendarData GetCalendar(CalendarId calendarId)
17371740
// Make sure that calendar has data
17381741
if (calendarData == null)
17391742
{
1740-
Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already");
1741-
calendarData = new CalendarData(_sWindowsName, calendarId, _bUseOverrides);
1743+
if (calendarIndex == 0 && IsInvariantCulture)
1744+
{
1745+
// We do this lazily as opposed in CreateCultureWithInvariantData to avoid introducing
1746+
// invariant calendar data into apps that don't even need calendar.
1747+
calendarData = CalendarData.Invariant;
1748+
}
1749+
else
1750+
{
1751+
Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already");
1752+
calendarData = new CalendarData(_sWindowsName, calendarId, _bUseOverrides);
1753+
}
17421754
_calendars[calendarIndex] = calendarData;
17431755
}
17441756

0 commit comments

Comments
 (0)