Skip to content

Commit 79c861e

Browse files
[NativeAOT-LLVM] Exclude ExceptionHandling.cs from the WASM build and pass -O1 to emcc (#3133)
* Exclude ExceptionHandling.cs from the WASM build It roots quite a bit of stuff we don't use/need. * Sort base-only/diff-only methods in wasmjit-diff.ps1 by size * Pass -O1 to emcc This both avoids wasm-opt and makes emscripten link-in the optimized version of its standard library, saving ~1.5% in code size for WasmDebugging. * More EH cleanup
1 parent d12d282 commit 79c861e

File tree

6 files changed

+135
-59
lines changed

6 files changed

+135
-59
lines changed

src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -588,8 +588,6 @@ The .NET Foundation licenses this file to you under the MIT license.
588588
<CustomLinkerArg Condition="'$(NativeDebugSymbols)' != 'true'" Include="-Wl,--strip-all" />
589589
<!-- TODO-LLVM: https://github.com/dotnet/runtimelab/issues/2752. -->
590590
<!--<CustomLinkerArg Condition="'$(NativeDebugSymbols)' != 'true'" Include="-Wl,compress-relocations" />-->
591-
<!-- see https://github.com/emscripten-core/emscripten/issues/16836 for the issue that means we have to force the linker to include these symbols before LTO -->
592-
<!--<CustomLinkerArg Condition="'$(Optimize)' != 'true'" Include="$(WasmOptimizationSetting) -flto" /> -->
593591
<CustomLinkerArg Condition="'$(IlcLlvmTarget)' != ''" Include="-target $(IlcLlvmTarget)" />
594592
</ItemGroup>
595593

@@ -601,13 +599,15 @@ The .NET Foundation licenses this file to you under the MIT license.
601599
<CustomLinkerArg Include="-s GLOBAL_BASE=$(IlcWasmGlobalBase)" />
602600
<CustomLinkerArg Include="-s TOTAL_STACK=$(IlcWasmStackSize)" />
603601
<CustomLinkerArg Include="-s ERROR_ON_UNDEFINED_SYMBOLS=0" Condition="'$(IlcTreatWarningsAsErrors)' != 'true'" />
604-
<CustomLinkerArg Condition="'$(WasmEnableJSBigIntIntegration)' == 'true'" Include="-s WASM_BIGINT=1" />
605-
<CustomLinkerArg Condition="'$(IlcLlvmExceptionHandlingModel)' == 'cpp'" Include="-s DISABLE_EXCEPTION_CATCHING=0" />
606-
607-
<CustomLinkerArg Include="$(EmccFlags)" />
602+
<CustomLinkerArg Include="-s WASM_BIGINT=1" Condition="'$(WasmEnableJSBigIntIntegration)' == 'true'" />
603+
<CustomLinkerArg Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(IlcLlvmExceptionHandlingModel)' == 'cpp'" />
608604
<CustomLinkerArg Include="-s MAXIMUM_MEMORY=$(EmccMaximumHeapSize)" Condition="'$(EmccMaximumHeapSize)' != ''" />
609605
<CustomLinkerArg Include="-s INITIAL_MEMORY=$(EmccInitialHeapSize)" Condition="'$(EmccInitialHeapSize)' != ''" />
610-
<CustomLinkerArg Condition="'$(EmccEnableAssertions)' == 'true'" Include="-s ASSERTIONS=1" />
606+
<CustomLinkerArg Include="-s ASSERTIONS=1" Condition="'$(EmccEnableAssertions)' == 'true'" />
607+
608+
<!-- See https://github.com/dotnet/runtimelab/issues/2357 for why we don't run wasm-opt (it would mangle our strack trace info). -->
609+
<CustomLinkerArg Condition="'$(Optimize)' == 'true'" Include="-O1" />
610+
<CustomLinkerArg Include="$(EmccFlags)" />
611611
</ItemGroup>
612612

613613
<!-- wasm-ld only supports listing exports on the command line -->

src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.wasm.cs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private static void DispatchException(object exception, RhEHFrameType flags)
9696
}
9797
else
9898
{
99-
if (ShouldTypedClauseCatchThisException(exception, clause.ClauseType, false /* tryUnwrapException, not used for NATIVEAOT */))
99+
if (ShouldTypedClauseCatchThisException(exception, clause.ClauseType))
100100
{
101101
goto FoundHandler;
102102
}
@@ -869,4 +869,98 @@ public static int Parse(byte* pUnwindInfo, uint* pShadowFrameSize = null, void**
869869
return (int)(pCurrent - pUnwindInfo);
870870
}
871871
}
872+
873+
// TODO-LLVM-Upstream: create ExceptionHandling.Common.cs and put the things below there.
874+
internal static unsafe partial class EH
875+
{
876+
private enum RhEHFrameType
877+
{
878+
RH_EH_FIRST_FRAME = 1,
879+
RH_EH_FIRST_RETHROW_FRAME = 2,
880+
}
881+
882+
private enum RhEHClauseKind
883+
{
884+
RH_EH_CLAUSE_TYPED = 0,
885+
RH_EH_CLAUSE_FAULT = 1,
886+
RH_EH_CLAUSE_FILTER = 2,
887+
RH_EH_CLAUSE_UNUSED = 3,
888+
}
889+
890+
internal struct MethodRegionInfo
891+
{
892+
}
893+
894+
internal struct ExInfo
895+
{
896+
}
897+
898+
internal struct PAL_LIMITED_CONTEXT
899+
{
900+
}
901+
902+
[StackTraceHidden]
903+
[RuntimeExport("RhExceptionHandling_FailedAllocation")]
904+
public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow)
905+
{
906+
ExceptionIDs exID = fIsOverflow ? ExceptionIDs.Overflow : ExceptionIDs.OutOfMemory;
907+
908+
// Throw the out of memory exception defined by the classlib, using the input MethodTable*
909+
// to find the correct classlib.
910+
911+
throw pEEType->GetClasslibException(exID);
912+
}
913+
914+
private static bool ShouldTypedClauseCatchThisException(object exception, MethodTable* pClauseType)
915+
{
916+
return TypeCast.IsInstanceOfException(pClauseType, exception);
917+
}
918+
919+
private static void OnFirstChanceExceptionViaClassLib(object exception)
920+
{
921+
IntPtr pOnFirstChanceFunction =
922+
(IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType(exception.GetMethodTable(), ClassLibFunctionId.OnFirstChance);
923+
924+
if (pOnFirstChanceFunction == IntPtr.Zero)
925+
{
926+
return;
927+
}
928+
929+
try
930+
{
931+
((delegate*<object, void>)pOnFirstChanceFunction)(exception);
932+
}
933+
catch when (true)
934+
{
935+
// disallow all exceptions leaking out of callbacks
936+
}
937+
}
938+
939+
private static void OnUnhandledExceptionViaClassLib(object exception)
940+
{
941+
IntPtr pOnUnhandledExceptionFunction =
942+
(IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType(exception.GetMethodTable(), ClassLibFunctionId.OnUnhandledException);
943+
944+
if (pOnUnhandledExceptionFunction == IntPtr.Zero)
945+
{
946+
return;
947+
}
948+
949+
try
950+
{
951+
((delegate*<object, void>)pOnUnhandledExceptionFunction)(exception);
952+
}
953+
catch when (true)
954+
{
955+
// disallow all exceptions leaking out of callbacks
956+
}
957+
}
958+
959+
#pragma warning disable IDE0060
960+
internal static void FallbackFailFast(RhFailFastReason reason, object? unhandledException)
961+
{
962+
InternalCalls.RhpFallbackFailFast();
963+
}
964+
#pragma warning restore IDE0060
965+
}
872966
}

src/coreclr/nativeaot/Runtime/wasm/ExceptionHandling/ExceptionHandling.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,3 @@ FCIMPL0(void*, RhpGetLastPreciseVirtualUnwindFrame)
4848
return static_cast<uint8_t*>(pShadowStack) - sizeof(void*);
4949
}
5050
FCIMPLEND
51-
52-
// We do not use these helpers. TODO-LLVM: exclude them from the WASM build.
53-
FCIMPL4(void*, RhpCallCatchFunclet, void*, void*, void*, void*) { abort(); } FCIMPLEND
54-
FCIMPL3(bool, RhpCallFilterFunclet, void*, void*, void*) { abort(); } FCIMPLEND
55-
FCIMPL2(void, RhpCallFinallyFunclet, void*, void*) { abort(); } FCIMPLEND

src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -588,9 +588,12 @@
588588
<Compile Include="$(RuntimeBasePath)System\Runtime\MethodTable.Runtime.cs">
589589
<Link>Runtime.Base\src\System\Runtime\MethodTable.Runtime.cs</Link>
590590
</Compile>
591-
<Compile Include="$(RuntimeBasePath)System\Runtime\ExceptionHandling.cs">
591+
<Compile Include="$(RuntimeBasePath)System\Runtime\ExceptionHandling.cs" Condition="'$(WasmAbi)' != 'true'">
592592
<Link>Runtime.Base\src\System\Runtime\ExceptionHandling.cs</Link>
593593
</Compile>
594+
<Compile Include="$(RuntimeBasePath)System\Runtime\ExceptionHandling.wasm.cs" Condition="'$(WasmAbi)' == 'true'">
595+
<Link>Runtime.Base\src\System\Runtime\ExceptionHandling.wasm.cs</Link>
596+
</Compile>
594597
<Compile Include="$(RuntimeBasePath)System\Runtime\InternalCalls.cs">
595598
<Link>Runtime.Base\src\System\Runtime\InternalCalls.cs</Link>
596599
</Compile>
@@ -612,9 +615,6 @@
612615
<Compile Include="$(AotCommonPath)\Internal\Runtime\TransitionBlock.cs">
613616
<Link>Common\TransitionBlock.cs</Link>
614617
</Compile>
615-
<Compile Include="$(RuntimeBasePath)System\Runtime\ExceptionHandling.wasm.cs" Condition="'$(WasmAbi)' == 'true'">
616-
<Link>Runtime.Base\src\System\Runtime\ExceptionHandling.wasm.cs</Link>
617-
</Compile>
618618
</ItemGroup>
619619
<ItemGroup Condition="'$(InPlaceRuntime)' == 'true'">
620620
<Compile Include="$(IntermediatesDir)\nativeaot\Runtime\Full\AsmOffsets.cs" Condition="'$(WasmAbi)' != 'true'" />

src/tests/nativeaot/Directory.Build.props

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@
1515
<DefineConstants Condition="'$(TargetsWasm)' == 'true'">$(DefineConstants);CODEGEN_WASM</DefineConstants>
1616
<DefineConstants Condition="$(TargetOS) == 'wasi'">$(DefineConstants);CODEGEN_WASI</DefineConstants>
1717
</PropertyGroup>
18+
19+
<ItemGroup>
20+
<!-- Our stack trace implementation is not compatible with post-link optimizations/changes. -->
21+
<!-- Exempt $(EmccExtraArgs) so that quick experimentation from the command line is still possible. -->
22+
<LinkerArg Include="-sERROR_ON_WASM_CHANGES_AFTER_LINK=1" Condition="'$(TargetsBrowser)' == 'true' and '$(EmccExtraArgs)' == ''" />
23+
</ItemGroup>
1824
</Project>

src/tests/nativeaot/SmokeTests/HelloWasm/wasmjit-diff.ps1

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -496,10 +496,6 @@ if ($Analyze -or $Summary)
496496

497497
$RegressionCount = 0
498498
$ImprovementCount = 0
499-
$HaveRegressionDiffs = $false
500-
$HaveImprovementDiffs = $false
501-
$HaveBaseOnlyMethods = $false
502-
$HaveDiffOnlyMethods = $false
503499
$AverageRelativeCodeSizeDelta = 0.0
504500
foreach ($Diff in $Diffs)
505501
{
@@ -517,24 +513,13 @@ if ($Analyze -or $Summary)
517513
# Just skip them for now.
518514
if ($Diff.Base.Size -eq 0)
519515
{
520-
$HaveDiffOnlyMethods = $true
521516
continue
522517
}
523518
if ($Diff.Diff.Size -eq 0)
524519
{
525-
$HaveBaseOnlyMethods = $true
526520
continue
527521
}
528522

529-
if ($IsRegression)
530-
{
531-
$HaveRegressionDiffs = $true
532-
}
533-
else
534-
{
535-
$HaveImprovementDiffs = $true
536-
}
537-
538523
$AverageRelativeCodeSizeDelta += $Diff.CodeSizeDelta / $Diff.Base.Size
539524
}
540525

@@ -558,8 +543,13 @@ if ($Analyze -or $Summary)
558543
Write-Host " average relative diff is $($AverageRelativeCodeSizeDelta -lt 0 ? 'an improvement' : 'a regression')"
559544
Write-Host ""
560545

561-
function ShowRelativeDiffs($DiffsToShow, $Message, $ShowBaseOnlyMethods = $false, $ShowDiffOnlyMethods = $false)
546+
function ShowRelativeDiffs($DiffsToShow, $Message)
562547
{
548+
if ($DiffsToShow.Length -eq 0)
549+
{
550+
return
551+
}
552+
563553
Write-Host $Message
564554

565555
$DiffsShown = 0
@@ -570,42 +560,33 @@ if ($Analyze -or $Summary)
570560
break
571561
}
572562

573-
$IsBaseOnlyMethod = $Diff.Diff.Size -eq 0
574-
$IsDiffOnlyMethod = $Diff.Base.Size -eq 0
575-
if (($ShowBaseOnlyMethods -eq $IsBaseOnlyMethod) -and ($ShowDiffOnlyMethods -eq $IsDiffOnlyMethod))
576-
{
577-
Write-Host (" {0,8} ({1,6:P} of base) : {2} - {3}" -f
578-
$Diff.CodeSizeDelta, ($Diff.CodeSizeDelta / $Diff.Base.Size), $Diff.DiffFileName, $Diff.Name)
579-
$DiffsShown++
580-
}
563+
Write-Host(" {0,8} ({1,6:P} of base) : {2} - {3}" -f
564+
$Diff.CodeSizeDelta, ($Diff.CodeSizeDelta / $Diff.Base.Size), $Diff.DiffFileName, $Diff.Name)
565+
$DiffsShown++
581566
}
582567
Write-Host ""
583568
}
584569

585570
if ($RegressionCount -ne 0)
586571
{
587-
$RegressionDiffs = $Diffs | sort { $_.CodeSizeDelta / $_.Base.Size } -Descending | where CodeSizeDelta -gt 0
588-
if ($HaveRegressionDiffs)
589-
{
590-
ShowRelativeDiffs $RegressionDiffs "Top method regressions (percentages):"
591-
}
592-
if ($HaveDiffOnlyMethods)
593-
{
594-
ShowRelativeDiffs $RegressionDiffs "Top methods only present in diff:" -ShowDiffOnlyMethods $true
595-
}
572+
$RegressionDiffs = $Diffs | where CodeSizeDelta -gt 0
573+
574+
$ActualRegressionDiffs = $RegressionDiffs | where { $_.Base.Size -ne 0 } | sort { $_.CodeSizeDelta / $_.Base.Size } -Descending
575+
ShowRelativeDiffs $ActualRegressionDiffs "Top method regressions (percentages):"
576+
577+
$DiffOnlyDiffs = $RegressionDiffs | where { $_.Base.Size -eq 0 } | sort CodeSizeDelta -Descending
578+
ShowRelativeDiffs $DiffOnlyDiffs "Top methods only present in diff:"
596579
}
597580

598581
if ($ImprovementCount -ne 0)
599582
{
600-
$ImprovementDiffs = $Diffs | sort { $_.CodeSizeDelta / $_.Base.Size } | where CodeSizeDelta -lt 0
601-
if ($HaveImprovementDiffs)
602-
{
603-
ShowRelativeDiffs $ImprovementDiffs "Top method improvements (percentages):"
604-
}
605-
if ($HaveBaseOnlyMethods)
606-
{
607-
ShowRelativeDiffs $ImprovementDiffs "Top methods only present in base:" -ShowBaseOnlyMethods $true
608-
}
583+
$ImprovementDiffs = $Diffs | where CodeSizeDelta -lt 0
584+
585+
$ActualImprovementDiffs = $ImprovementDiffs | where { $_.Diff.Size -ne 0 } | sort { $_.CodeSizeDelta / $_.Base.Size }
586+
ShowRelativeDiffs $ActualImprovementDiffs "Top method improvements (percentages):"
587+
588+
$BaseOnlyDiffs = $ImprovementDiffs | where { $_.Diff.Size -eq 0 } | sort CodeSizeDelta
589+
ShowRelativeDiffs $BaseOnlyDiffs "Top methods only present in base:"
609590
}
610591

611592
Write-Host "$($Diffs.Count) total methods with Code Size differences ($ImprovementCount improved, $RegressionCount regressed)"

0 commit comments

Comments
 (0)