Skip to content

Allow some Globalization code to be dynamically removed.#596

Merged
marek-safar merged 1 commit intodotnet:masterfrom
baulig:work-globalization-gate
Jun 6, 2019
Merged

Allow some Globalization code to be dynamically removed.#596
marek-safar merged 1 commit intodotnet:masterfrom
baulig:work-globalization-gate

Conversation

@baulig
Copy link

@baulig baulig commented May 30, 2019

Rationale: allow dynamic removal (as it without rebuilding corlib) of some of the globalization code when --exclude-feature globalization is provided.

Currently removes the Japanese, Taiwan and Hebrew calendars as well as Hebrew numbers.

This requires mono/corefx#298 and mono/mono#14825.

We are using the same techinique as previously employed in #590 to dynamically remove the System.Reflection.Emit code.

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.

After this has been done in the BCL, we need to explicitly tell the linker to turn those method bodies into stubs when --exclude-feature globalization.

Ideally, we would want to use MethodAction.ConvertToStub instead of ConvertToThrow here, but we'd have to extend the code rewriter first to support methods with arbitrary return types and parameters.

if (FeatureGlobalization)
ExcludeGlobalization (type);

if (RemoveCustomAttributes (type)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block has already been merged, ignore.

public bool FeatureCOM { get; set; }
public bool FeatureETW { get; set; }
public bool FeatureSRE { get; set; }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block has already been merged, ignore.

FeatureCOM = excluded_features.Contains ("com"),
FeatureETW = excluded_features.Contains ("etw"),
FeatureSRE = excluded_features.Contains ("sre"),
FeatureGlobalization = excluded_features.Contains ("globalization")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block has already been merged, ignore.

@baulig
Copy link
Author

baulig commented May 30, 2019

Please disregard the SRE changes; I intentionally made this draft against an older version of the linker as I'm having some difficulties with the SDK-style projects in VSMac. I got them to build, but Intellisense is completely messed up, thus making it very hard to edit / debug.

@baulig
Copy link
Author

baulig commented May 31, 2019

All sizes are from the wasm profile.

  • Unlinked size: 3917312.

  • Linked size with this PR and without --exclude-feature globalization (ie. globalization enabled): 697856.

  • Linked size with this PR and --exclude-feature globalization: 686592.

  • Running with my Linker Optimizer: 675328. You won't get this without my tool, just including here as reference. I'm still investigating what the difference is and will post some more details about that shortly.

@baulig
Copy link
Author

baulig commented May 31, 2019

Trying to analyzing the difference between the linker and my tool ...

  • There is -System.Security.Policy.Evidence, System.Globalization.DateTimeFormatInfoScanner/FoundDatePattern and System.Globalization.GlobalizationMode that my tool removes, but that won't account for the 11.2k difference.

still investigating ....

@baulig
Copy link
Author

baulig commented May 31, 2019

With my tool, but without touching GlobalizationMode.Invariant, the size is 686592.

Now when looking at individual classes / method - but tool does not account for metadata size, so these numbers are a bit off on the lower side.

The entire DateTimeFormatInfoScanner class is 2957 bytes, the other two are too small to even look at.

However, I can also do a diff between individual classes.

  • All of corlib: 434232 / 443459.
  • DateTimeParse: 13745 - 14628; changes in Lex, TryParse, ProcessHebrewTerminalState, GetHebrewDayOfNM.
  • System.RuntimeType: 10877 / 11001 - for completely unknown reasons.
  • DateTimeFormat: 6903 / 7301.
  • lots of smaller changes in a bunch of system and reflection types, some just a couple of bytes in difference.
  • all of System.Globalization: 42651 / 49284 -> good, so we don't have to look at all that small stuff.
  • DateTimeFormatInfo: 10414 / 13810 -> that's huge! Added CreateTokenHashTable, Tokenize, GetAllDateTimePatterns, set_Calendar, YearMonthAdjustment, GetMergedPatterns, GetCombinedPatterns and some small stuff. The first three are most significant.
  • CultureData: 4114 / 4427.
  • DateTimeFormatInfoScanner: 1026 / 2957.
  • GlobalizationGate (that I added here): 347

Okay, I think that gave me a few methods to look at and apply the same technique.

@baulig
Copy link
Author

baulig commented May 31, 2019

Disregard this (generated output from my tool), it's just for my own reference later on.

	<action-list>
		<namespace name="System.Globalization">
			<type name="GlobalizationMode">
				<method name="get_Invariant" action="return-true" />
			</type>
			<type name="CompareInfo">
				<method name=".ctor" action="scan" />
				<method name="CompareOrdinalIgnoreCase(System.ReadOnlySpan`1&lt;System.Char&gt;,System.ReadOnlySpan`1&lt;System.Char&gt;)" action="scan" dead-code="blocks,jumps" />
			</type>
			<type name="CultureInfo">
				<method name="get_DateTimeFormat" action="scan" dead-code="blocks,jumps" />
			</type>
			<type name="DateTimeFormatInfo">
				<method name="set_Calendar" action="scan" dead-code="blocks,variables" />
				<method name="Tokenize" action="scan" dead-code="blocks,jumps,variables" />
				<method name="CreateTokenHashTable" action="scan" dead-code="blocks,jumps,constant-jumps,variables" />
			</type>
			<type name="CalendarData">
				<method name=".ctor(System.String,System.Int32,System.Boolean)" action="scan" dead-code="blocks,jumps" />
				<method name="InitializeAbbreviatedEraNames" action="scan" dead-code="blocks" />
			</type>
			<type name="CharUnicodeInfo">
				<method name="EndianSwap(System.UInt16)" dead-code="variables" />
			</type>
		</namespace>
		<namespace name="Martin.LinkerTest">
			<type name="TestGlobalization">
				<method name="Test" action="scan" dead-code="blocks,jumps" />
			</type>
		</namespace>
		<namespace name="System">
			<type name="DateTimeParse">
				<method name="TryParse(System.ReadOnlySpan`1&lt;System.Char&gt;,System.Globalization.DateTimeFormatInfo,System.Globalization.DateTimeStyles,System.DateTimeResult&amp;)" action="scan" dead-code="blocks" />
				<method name="Lex" action="scan" dead-code="blocks" />
			</type>
			<type name="DateTimeFormat">
				<method name="FormatCustomized" action="scan" dead-code="blocks,jumps,constant-jumps,variables" />
			</type>
			<type name="Array">
				<method name="CreateInstance(System.Type,System.Int32[])" dead-code="variables" />
			</type>
		</namespace>
		<namespace name="System.IO">
			<type name="Path">
				<method name="CanonicalizePath" dead-code="blocks,jumps,constant-jumps,variables" />
			</type>
		</namespace>
		<namespace name="System.Threading">
			<type name="SpinLock">
				<method name="ContinueTryEnterWithThreadTracking" dead-code="variables" />
			</type>
		</namespace>
		<namespace name="System.Reflection">
			<type name="SignatureType">
				<method name="get_TypeHandle" dead-code="variables" />
			</type>
		</namespace>
	</action-list>

@baulig
Copy link
Author

baulig commented May 31, 2019

Disregard as well; generated output.

		<assembly name="mscorlib" size="675328" code-size="434232">
			<namespace name="System" size="165129">
				<type name="Number" size="20115" />
				<type name="DateTimeParse" size="13745" />
				<type name="String" size="13415" />
				<type name="RuntimeType" size="10877" />
				<type name="DateTimeFormat" size="6903" />
				<type name="Type" size="6580" />
				<type name="TimeZoneInfo" size="5592" />
				<type name="DateTime" size="5359" />
				<type name="Array" size="4894" />
				<type name="DefaultBinder" size="3682" />
				<type name="Guid" size="3606" />
				<type name="ThrowHelper" size="3072" />
				<type name="MonoCustomAttrs" size="2902" />
				<type name="SpanHelpers" size="2585" />
				<type name="__DTString" size="2452" />
				<type name="Delegate" size="2313" />
				<type name="Enum" size="2251" />
				<type name="Exception" size="2162" />
				<type name="Version" size="1793" />
				<type name="ExceptionResource" size="1706" />
				<type name="Buffer" size="1702" />
				<type name="TimeSpan" size="1503" />
				<type name="Attribute" size="1401" />
				<type name="Char" size="1346" />
				<type name="ValueTuple`2" size="1267" />
				<type name="AggregateException" size="1261" />
				<type name="Span`1" size="1261" />
				<type name="AppDomain" size="1252" />
				<type name="Convert" size="1234" />
				<type name="Tuple`3" size="1109" />
				<type name="Random" size="1089" />
				<type name="ReadOnlySpan`1" size="1022" />
				<type name="IntPtr" size="983" />
				<type name="RuntimeTypeHandle" size="965" />
				<type name="Environment" size="947" />
				<type name="Double" size="897" />
				<type name="MemoryExtensions" size="801" />
				<type name="Console" size="792" />
				<type name="Single" size="759" />
				<type name="Marvin" size="731" />
				<type name="TypeLoadException" size="681" />
				<type name="Int16" size="675" />
				<type name="MulticastDelegate" size="674" />
				<type name="SByte" size="671" />
				<type name="DateTimeResult" size="669" />
				<type name="Int64" size="661" />
				<type name="UInt64" size="661" />
				<type name="ValueTuple" size="628" />
				<type name="Int32" size="625" />
				<type name="AppDomainSetup" size="620" />
				<type name="BadImageFormatException" size="617" />
				<type name="ExceptionArgument" size="602" />
				<type name="ParamsArray" size="594" />
				<type name="Byte" size="594" />
				<type name="UInt32" size="577" />
				<type name="UInt16" size="548" />
				<type name="Nullable`1" size="505" />
				<type name="TokenType" size="496" />
				<type name="RuntimeMethodHandle" size="496" />
				<type name="Boolean" size="490" />
				<type name="UIntPtr" size="490" />
				<type name="ArgumentOutOfRangeException" size="433" />
				<type name="MissingMemberException" size="406" />
				<type name="ObjectDisposedException" size="382" />
				<type name="GC" size="347" />
				<type name="ValueType" size="347" />
				<type name="AttributeUsageAttribute" size="346" />
				<type name="RuntimeFieldHandle" size="339" />
				<type name="ArgumentException" size="329" />
				<type name="CharEnumerator" size="325" />
				<type name="OperationCanceledException" size="323" />
				<type name="MissingMethodException" size="320" />
				<type name="DateTimeRawInfo" size="312" />
				<type name="DBNull" size="295" />
				<type name="TypeInitializationException" size="282" />
				<type name="Gen2GcCallback" size="277" />
				<type name="MissingFieldException" size="253" />
				<type name="Object" size="250" />
				<type name="Math" size="244" />
				<type name="Variant" size="241" />
				<type name="ParseFlags" size="229" />
				<type name="TypeNameFormatFlags" size="205" />
				<type name="ArgumentNullException" size="205" />
				<type name="ApplicationException" size="203" />
				<type name="SystemException" size="203" />
				<type name="ExecutionEngineException" size="203" />
				<type name="InvalidOperationException" size="203" />
				<type name="FormatException" size="203" />
				<type name="ParseFailureKind" size="198" />
				<type name="AttributeTargets" size="195" />
				<type name="TypeCode" size="186" />
				<type name="ConsoleColor" size="179" />
				<type name="ResolveEventArgs" size="174" />
				<type name="ObsoleteAttribute" size="170" />
				<type name="BitConverter" size="154" />
				<type name="StringComparison" size="139" />
				<type name="IndexOutOfRangeException" size="135" />
				<type name="NotImplementedException" size="135" />
				<type name="MethodAccessException" size="135" />
				<type name="OutOfMemoryException" size="135" />
				<type name="OverflowException" size="135" />
				<type name="CannotUnloadAppDomainException" size="135" />
				<type name="ArithmeticException" size="135" />
				<type name="MulticastNotSupportedException" size="135" />
				<type name="NotSupportedException" size="135" />
				<type name="NullReferenceException" size="135" />
				<type name="InvalidProgramException" size="135" />
				<type name="RankException" size="135" />
				<type name="UnauthorizedAccessException" size="135" />
				<type name="DllNotFoundException" size="135" />
				<type name="EntryPointNotFoundException" size="135" />
				<type name="StackOverflowException" size="135" />
				<type name="InvalidCastException" size="135" />
				<type name="FieldAccessException" size="135" />
				<type name="MemberAccessException" size="135" />
				<type name="TypedReference" size="127" />
				<type name="Tuple" size="113" />
				<type name="ArgIterator" size="109" />
				<type name="InvalidTimeZoneException" size="108" />
				<type name="DTSubString" size="108" />
				<type name="UnhandledExceptionEventArgs" size="102" />
				<type name="DayOfWeek" size="89" />
				<type name="Activator" size="88" />
				<type name="ArrayTypeMismatchException" size="87" />
				<type name="AppDomainUnloadedException" size="87" />
				<type name="PlatformNotSupportedException" size="87" />
				<type name="DivideByZeroException" size="87" />
				<type name="AssemblyLoadEventArgs" size="85" />
				<type name="MonoAsyncCall" size="85" />
				<type name="ReflectionOnlyType" size="80" />
				<type name="ByReference`1" size="79" />
				<type name="DelegateData" size="75" />
				<type name="TimeZoneNotFoundException" size="71" />
				<type name="TypeNameKind" size="64" />
				<type name="CLSCompliantAttribute" size="61" />
				<type name="DTSubStringType" size="59" />
				<type name="MonoTODOAttribute" size="54" />
				<type name="MonoTypeInfo" size="53" />
				<type name="TimeZoneInfoOptions" size="43" />
				<type name="DateTimeKind" size="42" />
				<type name="NotImplemented" size="42" />
				<type name="StringSplitOptions" size="41" />
				<type name="EmptyArray`1" size="39" />
				<type name="MarshalByRefObject" size="37" />
				<type name="AppContextSwitches" size="36" />
				<type name="CompatibilitySwitches" size="33" />
				<type name="__ComObject" size="29" />
				<type name="NonSerializedAttribute" size="24" />
				<type name="ContextStaticAttribute" size="24" />
				<type name="DateTimeToken" size="24" />
				<type name="ParamArrayAttribute" size="24" />
				<type name="SerializableAttribute" size="24" />
				<type name="EventArgs" size="24" />
				<type name="FlagsAttribute" size="24" />
				<type name="ThreadStaticAttribute" size="24" />
				<type name="BRECORD" size="24" />
				<type name="STAThreadAttribute" size="24" />
				<type name="MonoListItem" size="16" />
				<type name="RuntimeArgumentHandle" size="8" />
			</namespace>
			<namespace name="System.Globalization" size="42651">
				<type name="DateTimeFormatInfo" size="10414" />
				<type name="CultureData" size="4114" />
				<type name="CompareInfo" size="3748" />
				<type name="NumberFormatInfo" size="3668" />
				<type name="CultureInfo" size="3532" />
				<type name="CalendarData" size="3139" />
				<type name="TextInfo" size="2863" />
				<type name="TimeSpanFormat" size="2206" />
				<type name="GregorianCalendar" size="1999" />
				<type name="Calendar" size="1156" />
				<type name="DateTimeFormatInfoScanner" size="1026" />
				<type name="CharUnicodeInfo" size="795" />
				<type name="CultureNotFoundException" size="649" />
				<type name="UnicodeCategory" size="557" />
				<type name="TextInfoToLowerData" size="406" />
				<type name="CalendarId" size="404" />
				<type name="TextInfoToUpperData" size="364" />
				<type name="NumberStyles" size="285" />
				<type name="DateTimeStyles" size="197" />
				<type name="RegionInfo" size="178" />
				<type name="DateTimeFormatFlags" size="168" />
				<type name="FORMATFLAGS" size="153" />
				<type name="CompareOptions" size="147" />
				<type name="TimeSpanParse" size="129" />
				<type name="GregorianCalendarTypes" size="116" />
				<type name="GlobalizationAssembly" size="114" />
				<type name="MonthNameStyles" size="46" />
				<type name="GlobalizationGate" size="42" />
				<type name="SortKey" size="36" />
			</namespace>
			<namespace name="System.Text" size="33225">
				<type name="UTF8Encoding" size="8854" />
				<type name="StringBuilder" size="6950" />
				<type name="Encoding" size="3011" />
				<type name="ValueStringBuilder" size="1188" />
				<type name="DecoderNLS" size="1185" />
				<type name="EncoderNLS" size="1057" />
				<type name="InternalEncoderBestFitFallbackBuffer" size="1028" />
				<type name="Decoder" size="888" />
				<type name="InternalDecoderBestFitFallbackBuffer" size="835" />
				<type name="EncoderReplacementFallbackBuffer" size="799" />
				<type name="EncoderFallbackBuffer" size="793" />
				<type name="Encoder" size="759" />
				<type name="DecoderFallbackBuffer" size="738" />
				<type name="DecoderReplacementFallback" size="524" />
				<type name="EncoderReplacementFallback" size="524" />
				<type name="EncoderFallbackException" size="457" />
				<type name="DecoderReplacementFallbackBuffer" size="421" />
				<type name="EncoderExceptionFallbackBuffer" size="401" />
				<type name="EncodingHelper" size="372" />
				<type name="ValueUtf8Converter" size="314" />
				<type name="InternalDecoderBestFitFallback" size="288" />
				<type name="DecoderExceptionFallbackBuffer" size="277" />
				<type name="DecoderFallback" size="270" />
				<type name="InternalEncoderBestFitFallback" size="263" />
				<type name="EncoderFallback" size="260" />
				<type name="DecoderFallbackException" size="214" />
				<type name="StringBuilderCache" size="201" />
				<type name="DecoderExceptionFallback" size="177" />
				<type name="EncoderExceptionFallback" size="177" />
			</namespace>
			<namespace name="System.Reflection" size="32496">
				<type name="SignatureType" size="2508" />
				<type name="RuntimeMethodInfo" size="1685" />
				<type name="RuntimePropertyInfo" size="1622" />
				<type name="AssemblyName" size="1436" />
				<type name="SignatureConstructedGenericType" size="1293" />
				<type name="SignatureTypeExtensions" size="1265" />
				<type name="MethodBase" size="1184" />
				<type name="CorElementType" size="1103" />
				<type name="RuntimeConstructorInfo" size="1061" />
				<type name="RuntimeEventInfo" size="1057" />
				<type name="RuntimeAssembly" size="1016" />
				<type name="RuntimeFieldInfo" size="957" />
				<type name="RuntimeParameterInfo" size="952" />
				<type name="SignatureHasElementType" size="862" />
				<type name="Module" size="856" />
				<type name="FieldInfo" size="837" />
				<type name="ParameterInfo" size="698" />
				<type name="Assembly" size="574" />
				<type name="MemberInfo" size="571" />
				<type name="EventInfo" size="526" />
				<type name="MethodInfo" size="522" />
				<type name="ReflectionTypeLoadException" size="521" />
				<type name="TypeAttributes" size="521" />
				<type name="PInvokeAttributes" size="445" />
				<type name="SignatureArrayType" size="418" />
				<type name="MonoMethodInfo" size="417" />
				<type name="RuntimeModule" size="393" />
				<type name="ManifestResourceInfo" size="382" />
				<type name="MethodAttributes" size="360" />
				<type name="BindingFlags" size="347" />
				<type name="ConstructorInfo" size="330" />
				<type name="ExceptionHandlingClause" size="305" />
				<type name="SignaturePointerType" size="293" />
				<type name="SignatureByRefType" size="293" />
				<type name="FieldAttributes" size="279" />
				<type name="PropertyInfo" size="266" />
				<type name="MethodImplAttributes" size="237" />
				<type name="StrongNameKeyPair" size="215" />
				<type name="CustomAttributeExtensions" size="193" />
				<type name="Pointer" size="186" />
				<type name="GenericParameterAttributes" size="183" />
				<type name="CustomAttributeFormatException" size="173" />
				<type name="InvalidFilterCriteriaException" size="173" />
				<type name="TargetException" size="169" />
				<type name="LocalVariableInfo" size="141" />
				<type name="ParameterAttributes" size="137" />
				<type name="AmbiguousMatchException" size="135" />
				<type name="TargetParameterCountException" size="135" />
				<type name="PropertyAttributes" size="120" />
				<type name="MonoEventInfo" size="117" />
				<type name="PortableExecutableKinds" size="117" />
				<type name="MemberTypes" size="109" />
				<type name="AssemblyNameFlags" size="105" />
				<type name="TargetInvocationException" size="98" />
				<type name="AssemblyInformationalVersionAttribute" size="97" />
				<type name="PInfo" size="93" />
				<type name="AssemblyFileVersionAttribute" size="85" />
				<type name="AssemblyDefaultAliasAttribute" size="81" />
				<type name="ResourceLocation" size="80" />
				<type name="AssemblyDescriptionAttribute" size="79" />
				<type name="DefaultMemberAttribute" size="77" />
				<type name="AssemblyDelaySignAttribute" size="75" />
				<type name="AssemblyCopyrightAttribute" size="75" />
				<type name="MonoPropertyInfo" size="73" />
				<type name="AssemblyKeyFileAttribute" size="71" />
				<type name="AssemblyCompanyAttribute" size="71" />
				<type name="AssemblyProductAttribute" size="71" />
				<type name="CallingConventions" size="68" />
				<type name="AssemblyTitleAttribute" size="67" />
				<type name="EventAttributes" size="67" />
				<type name="Missing" size="62" />
				<type name="ProcessorArchitecture" size="58" />
				<type name="ExceptionHandlingClauseOptions" size="51" />
				<type name="ImageFileMachine" size="43" />
				<type name="AssemblyContentType" size="40" />
				<type name="ResourceAttributes" size="32" />
				<type name="Binder" size="24" />
				<type name="TypeInfo" size="24" />
				<type name="RtFieldInfo" size="24" />
				<type name="ParameterModifier" size="10" />
			</namespace>
			<namespace name="System.Threading" size="25204">
				<type name="SemaphoreSlim" size="2597" />
				<type name="ExecutionContext" size="2576" />
				<type name="CancellationTokenSource" size="2549" />
				<type name="ManualResetEventSlim" size="1998" />
				<type name="SpinLock" size="1738" />
				<type name="Thread" size="1302" />
				<type name="ThreadPoolWorkQueue" size="1146" />
				<type name="CancellationToken" size="903" />
				<type name="Monitor" size="739" />
				<type name="InternalThread" size="670" />
				<type name="Timer" size="657" />
				<type name="ThreadPool" size="637" />
				<type name="WaitHandle" size="632" />
				<type name="CancellationTokenRegistration" size="576" />
				<type name="SpinWait" size="544" />
				<type name="SparselyPopulatedArray`1" size="539" />
				<type name="QueueUserWorkItemCallback" size="455" />
				<type name="CancellationCallbackInfo" size="418" />
				<type name="SparselyPopulatedArrayFragment`1" size="402" />
				<type name="EventWaitHandle" size="382" />
				<type name="LazyInitializer" size="351" />
				<type name="SynchronizationContext" size="320" />
				<type name="ThreadPoolWorkQueueThreadLocals" size="308" />
				<type name="NativeEventCalls" size="276" />
				<type name="PlatformHelper" size="222" />
				<type name="WasmRuntime" size="192" />
				<type name="ExecutionContextSwitcher" size="189" />
				<type name="ThreadState" size="156" />
				<type name="SparselyPopulatedArrayAddInfo`1" size="150" />
				<type name="ThreadPoolGlobals" size="139" />
				<type name="TimeoutHelper" size="138" />
				<type name="SynchronizationLockException" size="135" />
				<type name="WaitHandleCannotBeOpenedException" size="135" />
				<type name="ThreadStateException" size="135" />
				<type name="CancellationCallbackCoreWorkArguments" size="114" />
				<type name="LockRecursionException" size="108" />
				<type name="Lock" size="106" />
				<type name="ThreadAbortException" size="88" />
				<type name="ThreadInterruptedException" size="88" />
				<type name="StackCrawlMark" size="86" />
				<type name="LockHolder" size="82" />
				<type name="SemaphoreFullException" size="76" />
				<type name="ManualResetEvent" size="43" />
				<type name="EventResetMode" size="39" />
				<type name="_ThreadPoolWaitCallback" size="37" />
				<type name="Interlocked" size="31" />
			</namespace>
			<namespace name="System.IO" size="21604">
				<type name="FileStream" size="4426" />
				<type name="Path" size="3026" />
				<type name="StreamWriter" size="2115" />
				<type name="UnmanagedMemoryStream" size="1728" />
				<type name="MonoIO" size="1504" />
				<type name="Stream" size="1386" />
				<type name="StreamReader" size="1042" />
				<type name="TextWriter" size="992" />
				<type name="__Error" size="759" />
				<type name="FileNotFoundException" size="745" />
				<type name="FileLoadException" size="642" />
				<type name="MonoIOError" size="616" />
				<type name="FileSystem" size="258" />
				<type name="UnexceptionalStreamWriter" size="239" />
				<type name="FileAttributes" size="223" />
				<type name="FileStreamAsyncResult" size="214" />
				<type name="IOException" size="191" />
				<type name="Directory" size="180" />
				<type name="TextReader" size="157" />
				<type name="UnexceptionalStreamReader" size="146" />
				<type name="DirectoryNotFoundException" size="135" />
				<type name="DriveNotFoundException" size="135" />
				<type name="PathTooLongException" size="135" />
				<type name="FileOptions" size="115" />
				<type name="Error" size="84" />
				<type name="FileMode" size="80" />
				<type name="MonoIOStat" size="79" />
				<type name="FileShare" size="74" />
				<type name="MonoFileType" size="56" />
				<type name="PathInternal" size="43" />
				<type name="FileAccess" size="41" />
				<type name="SeekOrigin" size="38" />
			</namespace>
			<namespace name="System.Threading.Tasks" size="21453">
				<type name="Task" size="11877" />
				<type name="TaskExceptionHolder" size="1294" />
				<type name="AwaitTaskContinuation" size="1059" />
				<type name="TaskScheduler" size="858" />
				<type name="DebuggerSupport" size="821" />
				<type name="Task`1" size="807" />
				<type name="TaskFactory" size="689" />
				<type name="SynchronizationContextAwaitTaskContinuation" size="427" />
				<type name="ThreadPoolTaskScheduler" size="421" />
				<type name="StandardTaskContinuation" size="385" />
				<type name="AsyncCausalityTracer" size="352" />
				<type name="TaskContinuationOptions" size="303" />
				<type name="TaskSchedulerAwaitTaskContinuation" size="282" />
				<type name="ContinuationTaskFromTask" size="259" />
				<type name="CompletionActionInvoker" size="212" />
				<type name="TaskContinuation" size="183" />
				<type name="StackGuard" size="170" />
				<type name="TaskCanceledException" size="162" />
				<type name="TaskStatus" size="147" />
				<type name="TaskCreationOptions" size="142" />
				<type name="InternalTaskOptions" size="132" />
				<type name="TaskSchedulerException" size="125" />
				<type name="UnobservedTaskExceptionEventArgs" size="74" />
				<type name="CausalitySynchronousWork" size="74" />
				<type name="CausalityRelation" size="66" />
				<type name="AsyncCausalityStatus" size="56" />
				<type name="CausalityTraceLevel" size="47" />
				<type name="ITaskCompletionAction" size="29" />
			</namespace>
			<namespace name="System.Collections.Generic" size="18540">
				<type name="Dictionary`2" size="4056" />
				<type name="List`1" size="2318" />
				<type name="LowLevelList`1" size="2002" />
				<type name="ArraySortHelper`2" size="1765" />
				<type name="ArraySortHelper`1" size="1739" />
				<type name="LowLevelDictionary`2" size="951" />
				<type name="EqualityComparer`1" size="854" />
				<type name="Comparer`1" size="422" />
				<type name="NullableEqualityComparer`1" size="414" />
				<type name="ObjectEqualityComparer`1" size="412" />
				<type name="GenericEqualityComparer`1" size="402" />
				<type name="ValueListBuilder`1" size="384" />
				<type name="ByteEqualityComparer" size="375" />
				<type name="LowLevelListWithIList`1" size="267" />
				<type name="LongEnumEqualityComparer`1" size="253" />
				<type name="EnumEqualityComparer`1" size="253" />
				<type name="InternalStringComparer" size="227" />
				<type name="NullableComparer`1" size="189" />
				<type name="KeyValuePair`2" size="184" />
				<type name="GenericComparer`1" size="176" />
				<type name="ObjectComparer`1" size="154" />
				<type name="KeyNotFoundException" size="135" />
				<type name="SByteEnumEqualityComparer`1" size="127" />
				<type name="ShortEnumEqualityComparer`1" size="127" />
				<type name="IntrospectiveSortUtilities" size="123" />
				<type name="KeyValuePair" size="113" />
				<type name="InsertionBehavior" size="59" />
				<type name="ICollection`1" size="23" />
				<type name="IEnumerator`1" size="11" />
				<type name="IReadOnlyCollection`1" size="9" />
				<type name="IReadOnlyList`1" size="8" />
				<type name="IList`1" size="8" />
			</namespace>
			<namespace name="System.Numerics" size="17773">
				<type name="Vector`1" size="16380" />
				<type name="Register" size="742" />
				<type name="ConstantHelper" size="499" />
				<type name="Vector" size="152" />
			</namespace>
			<namespace name="System.Reflection.Emit" size="17503">
				<type name="TypeBuilderInstantiation" size="2517" />
				<type name="SymbolType" size="1845" />
				<type name="TypeBuilder" size="1725" />
				<type name="GenericTypeParameterBuilder" size="1314" />
				<type name="EnumBuilder" size="1302" />
				<type name="MethodBuilder" size="823" />
				<type name="AssemblyBuilder" size="688" />
				<type name="DynamicMethod" size="681" />
				<type name="PropertyBuilder" size="676" />
				<type name="ModuleBuilder" size="670" />
				<type name="ConstructorBuilder" size="646" />
				<type name="FieldBuilder" size="604" />
				<type name="MethodOnTypeBuilderInst" size="561" />
				<type name="ConstructorOnTypeBuilderInst" size="503" />
				<type name="FieldOnTypeBuilderInst" size="502" />
				<type name="ILGenerator" size="317" />
				<type name="ByRefType" size="276" />
				<type name="UnmanagedMarshal" size="274" />
				<type name="ArrayType" size="270" />
				<type name="Label" size="163" />
				<type name="PointerType" size="123" />
				<type name="EventBuilder" size="121" />
				<type name="ILExceptionBlock" size="106" />
				<type name="PackingSize" size="103" />
				<type name="SignatureHelper" size="100" />
				<type name="ParameterBuilder" size="92" />
				<type name="CustomAttributeBuilder" size="91" />
				<type name="AssemblyBuilderAccess" size="75" />
				<type name="PEFileKinds" size="61" />
				<type name="MonoResource" size="57" />
				<type name="NativeResourceType" size="56" />
				<type name="LocalBuilder" size="45" />
				<type name="MonoWin32Resource" size="41" />
				<type name="ILExceptionInfo" size="35" />
				<type name="ILTokenInfo" size="22" />
				<type name="RefEmitPermissionSet" size="18" />
			</namespace>
			<namespace name="System.Runtime.CompilerServices" size="7437">
				<type name="AsyncTaskMethodBuilder`1" size="1422" />
				<type name="ConditionalWeakTable`2" size="1419" />
				<type name="AsyncMethodBuilderCore" size="1014" />
				<type name="TaskAwaiter" size="665" />
				<type name="Unsafe" size="545" />
				<type name="RuntimeHelpers" size="323" />
				<type name="AsyncTaskCache" size="229" />
				<type name="InternalsVisibleToAttribute" size="172" />
				<type name="RuntimeWrappedException" size="159" />
				<type name="RuntimeCompatibilityAttribute" size="149" />
				<type name="TaskAwaiter`1" size="149" />
				<type name="StateMachineAttribute" size="148" />
				<type name="ConfiguredTaskAwaitable`1" size="126" />
				<type name="JitHelpers" size="121" />
				<type name="CompilationRelaxationsAttribute" size="111" />
				<type name="TypeForwardedFromAttribute" size="108" />
				<type name="TypeDependencyAttribute" size="70" />
				<type name="RuntimeFeature" size="66" />
				<type name="DefaultDependencyAttribute" size="64" />
				<type name="AsyncStateMachineAttribute" size="46" />
				<type name="IteratorStateMachineAttribute" size="46" />
				<type name="LoadHint" size="45" />
				<type name="CompilationRelaxations" size="32" />
				<type name="IsByRefLikeAttribute" size="24" />
				<type name="ExtensionAttribute" size="24" />
				<type name="FriendAccessAllowedAttribute" size="24" />
				<type name="IsReadOnlyAttribute" size="24" />
				<type name="ReflectionBlockedAttribute" size="24" />
				<type name="CompilerGeneratedAttribute" size="24" />
				<type name="IntrinsicAttribute" size="24" />
				<type name="StringFreezingAttribute" size="24" />
				<type name="Ephemeron" size="16" />
			</namespace>
			<namespace name="System.Collections.Concurrent" size="5638">
				<type name="ConcurrentDictionary`2" size="5491" />
				<type name="CDSCollectionETWBCLProvider" size="147" />
			</namespace>
			<namespace name="System.Runtime.InteropServices" size="5364">
				<type name="SafeHandle" size="1019" />
				<type name="DllImportAttribute" size="751" />
				<type name="Marshal" size="671" />
				<type name="VarEnum" size="551" />
				<type name="GCHandle" size="432" />
				<type name="UnmanagedType" size="402" />
				<type name="MemoryMarshal" size="335" />
				<type name="MarshalAsAttribute" size="205" />
				<type name="MarshalDirectiveException" size="135" />
				<type name="ComInterfaceType" size="104" />
				<type name="SafeBuffer" size="86" />
				<type name="CallingConvention" size="65" />
				<type name="GCHandleType" size="64" />
				<type name="ClassInterfaceAttribute" size="62" />
				<type name="ComDefaultInterfaceAttribute" size="60" />
				<type name="InterfaceTypeAttribute" size="57" />
				<type name="ComVisibleAttribute" size="54" />
				<type name="FieldOffsetAttribute" size="50" />
				<type name="GuidAttribute" size="48" />
				<type name="ClassInterfaceType" size="47" />
				<type name="CharSet" size="46" />
				<type name="OutAttribute" size="24" />
				<type name="PreserveSigAttribute" size="24" />
				<type name="ComImportAttribute" size="24" />
				<type name="OptionalAttribute" size="24" />
				<type name="InAttribute" size="24" />
			</namespace>
			<namespace name="System.Diagnostics" size="3567">
				<type name="StackTrace" size="2275" />
				<type name="StackFrame" size="912" />
				<type name="DebuggerDisplayAttribute" size="104" />
				<type name="DebuggerTypeProxyAttribute" size="77" />
				<type name="DebuggableAttribute" size="61" />
				<type name="Debugger" size="42" />
				<type name="StackTraceHiddenAttribute" size="24" />
				<type name="DebuggerStepThroughAttribute" size="24" />
				<type name="DebuggerHiddenAttribute" size="24" />
				<type name="DebuggerNonUserCodeAttribute" size="24" />
			</namespace>
			<namespace name="System.Buffers" size="2794">
				<type name="TlsOverPerCoreLockedStacksArrayPool`1" size="1505" />
				<type name="ArrayPoolEventSource" size="986" />
				<type name="Utilities" size="185" />
				<type name="ArrayPool`1" size="118" />
			</namespace>
			<namespace name="System.Runtime.Serialization" size="2390">
				<type name="SerializationEvents" size="699" />
				<type name="SafeSerializationManager" size="440" />
				<type name="SerializationInfo" size="304" />
				<type name="SerializationException" size="181" />
				<type name="StreamingContext" size="179" />
				<type name="SerializationEventsCache" size="130" />
				<type name="OptionalFieldAttribute" size="129" />
				<type name="StreamingContextStates" size="121" />
				<type name="SerializationInfoEnumerator" size="111" />
				<type name="OnSerializingAttribute" size="24" />
				<type name="OnSerializedAttribute" size="24" />
				<type name="OnDeserializingAttribute" size="24" />
				<type name="OnDeserializedAttribute" size="24" />
			</namespace>
			<namespace name="Mono" size="1820">
				<type name="RuntimeGenericParamInfoHandle" size="343" />
				<type name="RuntimeClassHandle" size="257" />
				<type name="RuntimeGPtrArrayHandle" size="251" />
				<type name="SafeStringMarshal" size="211" />
				<type name="RuntimeEventHandle" size="202" />
				<type name="RuntimePropertyHandle" size="202" />
				<type name="SafeGPtrArrayHandle" size="170" />
				<type name="ValueTuple`5" size="45" />
				<type name="RuntimeMarshal" size="40" />
				<type name="ValueTuple`4" size="36" />
				<type name="ValueTuple`3" size="27" />
				<type name="ValueTuple`2" size="18" />
				<type name="RuntimeRemoteClassHandle" size="9" />
				<type name="ValueTuple`1" size="9" />
			</namespace>
			<namespace name="System.Collections" size="1483">
				<type name="Hashtable" size="510" />
				<type name="HashHelpers" size="452" />
				<type name="Comparer" size="394" />
				<type name="Stack" size="82" />
				<type name="ArrayList" size="45" />
			</namespace>
			<namespace name="System.Diagnostics.Tracing" size="1368">
				<type name="EventSource" size="765" />
				<type name="EventAttribute" size="197" />
				<type name="EventSourceAttribute" size="166" />
				<type name="EventKeywords" size="156" />
				<type name="EventLevel" size="84" />
			</namespace>
			<namespace name="System.Runtime.Remoting.Messaging" size="1287">
				<type name="MonoMethodMessage" size="751" />
				<type name="AsyncResult" size="432" />
				<type name="CallType" size="57" />
				<type name="CallContext" size="47" />
			</namespace>
			<namespace name="System.Collections.ObjectModel" size="1034">
				<type name="ReadOnlyCollection`1" size="1034" />
			</namespace>
			<namespace name="Internal.Threading.Tasks.Tracing" size="597">
				<type name="TaskTrace" size="597" />
			</namespace>
			<namespace name="System.Runtime.Remoting.Proxies" size="453">
				<type name="RealProxy" size="261" />
				<type name="TransparentProxy" size="192" />
			</namespace>
			<namespace name="System.Buffers.Text" size="397">
				<type name="FormattingHelpers" size="397" />
			</namespace>
			<namespace name="System.Runtime.ExceptionServices" size="392">
				<type name="ExceptionDispatchInfo" size="368" />
				<type name="HandleProcessCorruptedStateExceptionsAttribute" size="24" />
			</namespace>
			<namespace name="Microsoft.Win32.SafeHandles" size="337">
				<type name="SafeFileHandle" size="117" />
				<type name="SafeHandleZeroOrMinusOneIsInvalid" size="116" />
				<type name="SafeWaitHandle" size="104" />
			</namespace>
			<namespace name="Internal.Runtime.Augments" size="333">
				<type name="RuntimeThread" size="214" />
				<type name="AsyncStatus" size="56" />
				<type name="RuntimeAugments" size="52" />
				<type name="TaskTraceCallbacks" size="11" />
			</namespace>
			<namespace name="System.Runtime.ConstrainedExecution" size="331">
				<type name="ReliabilityContractAttribute" size="136" />
				<type name="Consistency" size="100" />
				<type name="CriticalFinalizerObject" size="54" />
				<type name="Cer" size="41" />
			</namespace>
			<namespace name="System.Security" size="281">
				<type name="SecurityException" size="243" />
				<type name="SecurityManager" size="38" />
			</namespace>
			<namespace name="System.Resources" size="254">
				<type name="NeutralResourcesLanguageAttribute" size="129" />
				<type name="SatelliteContractVersionAttribute" size="85" />
				<type name="UltimateResourceFallbackLocation" size="40" />
			</namespace>
			<namespace name="System.Runtime.Remoting.Contexts" size="152">
				<type name="Context" size="152" />
			</namespace>
			<namespace name="System.Security.Permissions" size="142">
				<type name="SecurityAction" size="142" />
			</namespace>
			<namespace name="System.Diagnostics.Contracts" size="140">
				<type name="Contract" size="140" />
			</namespace>
			<namespace name="System.Runtime.Remoting" size="137">
				<type name="RemotingServices" size="137" />
			</namespace>
			<namespace name="System.Runtime" size="135">
				<type name="AmbiguousImplementationException" size="135" />
			</namespace>
			<namespace name="System.Configuration.Assemblies" size="119">
				<type name="AssemblyHashAlgorithm" size="64" />
				<type name="AssemblyVersionCompatibility" size="55" />
			</namespace>
			<namespace name="System.Numerics.Hashing" size="104">
				<type name="HashHelpers" size="104" />
			</namespace>
			<namespace name="Microsoft.Win32" size="99">
				<type name="Win32Native" size="99" />
			</namespace>
			<namespace name="System.Runtime.Remoting.Activation" size="45">
				<type name="ActivationServices" size="45" />
			</namespace>
			<namespace name="System.Runtime.Versioning" size="24">
				<type name="NonVersionableAttribute" size="24" />
			</namespace>
		</assembly>
		<assembly name="TestHelpers" size="3072" code-size="26">
			<namespace name="Martin.LinkerTest" size="26">
				<type name="AssertionException" size="26" />
			</namespace>
		</assembly>

@baulig
Copy link
Author

baulig commented May 31, 2019

Okay, looking at DateTimeFormatInfo.CreateTokenHashTable, quite a significant part of that method is conditional to GlobalizationMode.Invariant. My tool can remove all those parts, but the normal linker cannot.

However, we can try to split that method into two parts then use the trick showed in this draft to remove one of them - this should have about the same effect. And we can probably apply the same technique to some other functions as well.

But even without that, we still have 686592 bytes versus 697856.

@mrvoorhe
Copy link
Contributor

My tool can remove all those parts, but the normal linker cannot.

@baulig Out of curiosity, what tool are you referring to?

@baulig
Copy link
Author

baulig commented Jun 4, 2019

Latest commit brought us to 680448 versus 675328, slowly getting better ...

@baulig
Copy link
Author

baulig commented Jun 4, 2019

My tool can remove all those parts, but the normal linker cannot.

@baulig Out of curiosity, what tool are you referring to?

It's a research project that I've been working on recently. I created a tool called "Linker Optimizer" that does basic block scanning and dead code elimination.

@mrvoorhe
Copy link
Contributor

mrvoorhe commented Jun 5, 2019

Neat. We have things like that in our UnityLinker. I've mentioned it to @marek-safar a couple times in passing over the past year or so. The conclusion at the time has always been that it was best to keep the logic in our linker so that we could iterate faster. Maybe the time is near to bring our efforts upstream and combine forces? Or do you have a completely different approach you are looking to take (i.e. not inside monolinker)?

@baulig
Copy link
Author

baulig commented Jun 5, 2019

I would absolutely love to collaborate more on these issues instead of us duplicating work.

The reason why I put my tool into a separate module was simply because I needed something fast to use during my day-to-day work and it was easier and faster for me to have it in a place where I can easily modify it at any time without worrying about breaking or blocking somebody else's work.

However, long-term we should look into incorporating that into the linker in some way.

@baulig baulig mentioned this pull request Jun 5, 2019
@baulig
Copy link
Author

baulig commented Jun 5, 2019

BCL PR's are now up: mono/corefx#298 and mono/mono#14825. We need to bump CoreFX after landing that one.

@baulig baulig force-pushed the work-globalization-gate branch 2 times, most recently from f0978e6 to 0c3112a Compare June 5, 2019 21:20
This requires mono/corefx#298 and
mono/mono#14825.

We are using the same techinique as previously employed in
dotnet#590 to dynamically remove
the `System.Reflection.Emit` code.

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.

After this has been done in the BCL, we need to explicitly tell the linker
to turn those method bodies into stubs when `--exclude-feature globalization`.

Ideally, we would want to use `MethodAction.ConvertToStub` instead of `ConvertToThrow`
here, but we'd have to extend the code rewriter first to support methods with
arbitrary return types and parameters.
@baulig baulig force-pushed the work-globalization-gate branch from 0c3112a to 7f18668 Compare June 5, 2019 21:24
@baulig baulig changed the title [WIP]: Globalization Gate. Allow some Globalization code to be dynamically removed. Jun 5, 2019
@baulig baulig marked this pull request as ready for review June 5, 2019 21:27
@baulig baulig requested a review from marek-safar as a code owner June 5, 2019 21:27
@baulig baulig self-assigned this Jun 5, 2019
@baulig baulig requested review from lewing and steveisok June 5, 2019 21:30
@marek-safar
Copy link
Contributor

build

@marek-safar marek-safar closed this Jun 6, 2019
@marek-safar marek-safar reopened this Jun 6, 2019
@marek-safar marek-safar merged commit 3eca6ad into dotnet:master Jun 6, 2019
@baulig baulig deleted the work-globalization-gate branch June 6, 2019 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants