[browser][coreCLR] no COM, no swift, no x86 intrinsics#125083
[browser][coreCLR] no COM, no swift, no x86 intrinsics#125083pavelsavara wants to merge 2 commits intodotnet:mainfrom
Conversation
|
Tagging subscribers to this area: @agocke |
There was a problem hiding this comment.
Pull request overview
This PR aims to reduce trimmed size for browser-WASM CoreCLR builds by removing/gating roots and native support code for features that aren’t supported in the browser (COM/interop-related pieces, DynamicInterfaceCastable, Swift interop, and intrinsics metadata rooting).
Changes:
- Filters reverse P/Invoke stub generation for types marked
[UnsupportedOSPlatform("browser")]and annotatesComActivatoraccordingly. - Gates ILLink rooting for
ComponentActivator.GetFunctionPointerbehind the existing native-hosting feature switch. - Adds
TARGET_WASMguards to exclude DynamicInterfaceCastable native support on WASM and trims related ILLink roots / metadata retention paths.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tasks/WasmAppBuilder/generate-coreclr-helpers.cmd | Updates helper generation script used for CoreCLR WASM callhelper regeneration. |
| src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs | Skips generating reverse P/Invoke callback stubs for types unsupported on browser. |
| src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompExactlyDependsOnAttribute.cs | Removes CompExactlyDependsOnAttribute metadata for browser/WASI builds to improve trimming. |
| src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml | Gates ComponentActivator.GetFunctionPointer rooting behind the native-hosting feature switch. |
| src/coreclr/vm/wasm/callhelpers-reverse.cpp | Regenerated reverse thunk table reflecting removed callbacks. |
| src/coreclr/vm/wasm/callhelpers-pinvoke.cpp | Regenerated P/Invoke table reflecting upstream removals. |
| src/coreclr/vm/virtualcallstub.cpp | Removes DynamicInterfaceCastable resolver path from WASM builds. |
| src/coreclr/vm/rexcep.h | Attempts to exclude interop exception types from WASM ILLink descriptor generation. |
| src/coreclr/vm/methodtable.cpp | Removes IDynamicInterfaceCastable special method resolution on WASM. |
| src/coreclr/vm/jithelpers.cpp | Removes IDynamicInterfaceCastable cast path on WASM. |
| src/coreclr/vm/dynamicinterfacecastable.h | Wraps DynamicInterfaceCastable API surface out of WASM builds. |
| src/coreclr/vm/dynamicinterfacecastable.cpp | Wraps DynamicInterfaceCastable implementation out of WASM builds. |
| src/coreclr/vm/corelib.h | Attempts to exclude Swift interop and ComVariant from WASM ILLink descriptor generation; removes DynamicInterfaceCastableHelpers from WASM. |
| src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.PlatformNotSupported.cs | Marks ComActivator as unsupported on browser to suppress reverse stub generation. |
c066985 to
77b2da7
Compare
77b2da7 to
cb5be74
Compare
maraf
left a comment
There was a problem hiding this comment.
The generator code looks good to me module the copilot caching comment
| #if MONO | ||
| [Conditional("unnecessary")] // Mono doesn't use Ready2Run so we can remove this attribute to reduce size | ||
| #if MONO || TARGET_BROWSER || TARGET_WASI | ||
| [Conditional("unnecessary")] // These platforms don't use Ready2Run so we can remove this attribute to reduce size |
There was a problem hiding this comment.
Please add WASM-TODO comment for future when we enable R2R
There was a problem hiding this comment.
What is the WASM-TODO comment going to say? Add the attribute back?
I do not think we should be stripping it now if we will need to add it back soon.
| int32_t SystemNative_FSync (void *); | ||
| int32_t SystemNative_FTruncate (void *, int64_t); | ||
| int32_t SystemNative_FUTimens (void *, void *); | ||
| int32_t SystemNative_FcntlGetIsNonBlocking (void *, void *); |
There was a problem hiding this comment.
I guess we need to regenerate the helpers.
radekdoulik
left a comment
There was a problem hiding this comment.
Beside the 2 comments it LGTM, thank you!
| DEFINE_CLASS(CALLCONV_MEMBERFUNCTION, CompilerServices, CallConvMemberFunction) | ||
| DEFINE_CLASS(CALLCONV_SWIFT, CompilerServices, CallConvSwift) | ||
|
|
||
| #if !defined(TARGET_WASM) || !defined(FOR_ILLINK) |
There was a problem hiding this comment.
Can this be ifdefed out for Apple instead of this? We support swift interop on Apple OSes only.
| DEFINE_METHOD(HANDLE_MARSHALER, THROW_SAFEHANDLE_FIELD_CHANGED, ThrowSafeHandleFieldChanged, SM_RetVoid) | ||
| DEFINE_METHOD(HANDLE_MARSHALER, THROW_CRITICALHANDLE_FIELD_CHANGED, ThrowCriticalHandleFieldChanged, SM_RetVoid) | ||
|
|
||
| #if !defined(TARGET_WASM) || !defined(FOR_ILLINK) |
There was a problem hiding this comment.
Can this be ifdefed out for FEATURE_COMINTEROP instead of this?
| DEFINE_EXCEPTION(g_IONS, IOException, false, COR_E_IO, CTL_E_DEVICEIOERROR, STD_CTL_SCODE(31036), STD_CTL_SCODE(31037)) | ||
|
|
||
| #if !defined(TARGET_WASM) || !defined(FOR_ILLINK) | ||
| DEFINE_EXCEPTION(g_InteropNS, MarshalDirectiveException, false, COR_E_MARSHALDIRECTIVE) |
There was a problem hiding this comment.
I would expect that MarshalDirectiveException can be thrown even when we run on Wasm. What is the experience going to be on wasm when the IL linker trims it out? Is it going to be inscrutable crash?
| </assembly> | ||
|
|
||
| <assembly fullname="System.Private.CoreLib"> | ||
| <assembly fullname="System.Private.CoreLib" feature="System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting" featurevalue="true"> |
There was a problem hiding this comment.
Based on the comment, I think the whole point of this block is to keep ComponentActivator.GetFunctionPointer alive to get a reasonable experience when somebody tries to use this when EnableConsumingManagedCodeFromNativeHosting is disabled, and this change is going to break that.
Do you have any numbers for the size improvement? |
Trim dead interop/intrinsics code from browser-WASM CoreCLR builds
Summary
This PR reduces the trimmed size of browser-WASM CoreCLR apps by removing ILLinker roots and native code for features that cannot run in the browser: COM interop, Dynamic Interface Castable, Swift interop, and hardware intrinsics metadata.
Motivation
When building trimmed browser-WASM apps with CoreCLR, several managed types survive trimming despite being unreachable at runtime. These types are kept alive by:
corelib.handrexcep.h— the descriptor generator processesDEFINE_CLASS/DEFINE_EXCEPTIONentries and creates root entries that tell the linker to preserve types and methods.PInvokeCollector.csfor[UnmanagedCallersOnly]methods on types that are unsupported on browser.[CompExactlyDependsOn(typeof(...))]attribute metadata — this R2R-only attribute creates hard metadata type references (viatypeof()) that the linker follows, keeping entire intrinsics type hierarchies alive.Changes
1. Exclude COM/Interop exception types from WASM ILLink descriptors
Files:
src/coreclr/vm/rexcep.hGuard
InvalidOleVariantTypeException,MarshalDirectiveException,COMException,ExternalException, andSEHExceptionwith#if !defined(TARGET_WASM) || !defined(FOR_ILLINK). This excludes them from the generated ILLink descriptor on WASM while keeping them available for the C++ compiler (which never definesFOR_ILLINK).3. Exclude ComVariant from WASM ILLink descriptors
File:
src/coreclr/vm/corelib.hGuard
COMVARIANTDEFINE_CLASS with#if !defined(TARGET_WASM) || !defined(FOR_ILLINK)to prevent rootingSystem.Runtime.InteropServices.Marshalling.ComVarianton WASM.4. Exclude Swift interop types from WASM ILLink descriptors
File:
src/coreclr/vm/corelib.hGuard
SwiftSelf,SwiftSelf<T>,SwiftError, andSwiftIndirectResultDEFINE_CLASS entries with#if !defined(TARGET_WASM) || !defined(FOR_ILLINK). Swift interop is not supported on WASM. The C++ code incallstubgenerator.cppandstubgen.cppstill has access toCLASS__SWIFT_*constants during native compilation (sinceFOR_ILLINKis never defined for the C++ compiler).5. Gate ComponentActivator ILLink root behind feature switch
File:
src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xmlThe
GetFunctionPointermethod onComponentActivatorwas unconditionally rooted. Now gated behind theSystem.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHostingfeature switch, matching the otherComponentActivatormethods in the same file.6. Filter
[UnsupportedOSPlatform("browser")]types from reverse P/Invoke stubsFiles:
src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs,src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.PlatformNotSupported.csIsUnsupportedOnBrowser()helper toPInvokeCollector.DoesMethodHaveCallbacks()— skips generating reverse P/Invoke callback stubs for methods on types annotated with[UnsupportedOSPlatform("browser")].[UnsupportedOSPlatform("browser")]toComActivator.PlatformNotSupported.csso its[UnmanagedCallersOnly]methods (GetClassFactoryForTypeInternal,RegisterClassForTypeInternal,UnregisterClassForTypeInternal) are excluded from the generated stubs.7. Strip
[CompExactlyDependsOn]attribute on browser/WASI buildsFile:
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompExactlyDependsOnAttribute.csExpand the existing
[Conditional("unnecessary")]guard from#if MONOto#if MONO || TARGET_BROWSER || TARGET_WASI. This attribute is only needed for Ready2Run compilation, which browser and WASI targets do not use. Thetypeof(AdvSimd.Arm64)etc. arguments in 40+ methods across SPCL create hard metadata references that prevent the linker from trimmingSystem.Runtime.Intrinsics.Arm(andX86) type hierarchies. Stripping the attribute at compile time removes these metadata references.8. Regenerated callhelpers files
Files:
src/coreclr/vm/wasm/callhelpers-pinvoke.cpp,src/coreclr/vm/wasm/callhelpers-reverse.cppRegenerated to reflect the ComActivator exclusion (3 stubs removed from reverse callbacks) and removal of
System.Net.Primitivessocket address P/Invokes that were removed upstream.Design: The
FOR_ILLINKguard patternThe pattern
#if !defined(TARGET_WASM) || !defined(FOR_ILLINK)is used for entries that must remain in native C++ code (for the enum/constant generator) but should be excluded from the ILLink root descriptor on WASM.FOR_ILLINKis never defined → condition is always true → entries are includedCreateRuntimeRootILLinkDescriptorFile): passesDefineConstants=$(DefineConstants);FOR_ILLINKwith a simple#ifparser that treats unknown expressions (likedefined()with&&/||) as false → entries are excluded on WASMTARGET_WASMis not defined → condition is true → entries are includedTesting
The build was verified with
.\build.cmd -os browser -subset clr -c Debug /p:RuntimeFlavor=CoreCLR.