Repository navigation
fix(aot): preserve grain activation constructors - #11383
Conversation
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
NativeAOT linker behavior and externally owned smoke infrastructure warrant final human validation.
Review effort: Balanced
Findings: None
What changed in this PR
Preserves grain public constructors through generated metadata so default activation works under trimming and NativeAOT.
Changes:
- Propagates constructor-preservation annotations through registration, mapping, and activation.
- Adds managed and NativeAOT activation coverage.
- Documents constructor selection and scoped dependency behavior.
| File | Description |
|---|---|
test/Orleans.NativeAotSmoke/Orleans.NativeAotSmoke.csproj |
Configures NativeAOT scenarios. |
test/Orleans.NativeAotSmoke/NativeAotEnvironment.cs |
Validates native execution. |
test/Orleans.NativeAotSmoke/GrainActivation.smoke.json |
Defines diagnostic gates. |
test/Orleans.NativeAotSmoke/GrainActivation.cs |
Exercises native grain activation. |
test/Orleans.Core.Tests/Runtime/DefaultGrainActivatorTests.cs |
Tests constructor and DI behavior. |
src/Orleans.Serialization/Configuration/TypeManifestOptions.cs |
Preserves public constructors at registration. |
src/Orleans.Runtime/README.md |
Documents grain construction. |
src/Orleans.Runtime/Manifest/GrainClassMap.cs |
Propagates constructor metadata guarantees. |
src/Orleans.Runtime/Facet/GrainConstructorArgumentFactory.cs |
Annotates reflected grain types. |
src/Orleans.Runtime/Activation/DefaultGrainActivator.cs |
Annotates activation input types. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Code coverage
Report-only conclusion: current-main baseline stale. The newest successful coverage run tested 171c262, not current main cc1a9ff. Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities. The comparison remains report-only while normal line and branch variance is calibrated. Coverage details |
d06349a to
aae978c
Compare

Problem
NativeAOT can remove the public constructor metadata of a concrete grain registered by generated metadata. The grain class resolves successfully, but
DefaultGrainActivatorcannot find its implicit public parameterless constructor. Manual grain registration needs the same constructor-retention guarantee.Solution
Preserve public constructors alongside implemented interfaces in
TypeManifestOptions.AddInterfaceImplementation, the source-generated registration boundary. Carry the constructor requirement throughGrainClassMapand both default activation consumers.Add
GrainTypeOptions.AddClass(Type)as the annotated manual-registration path. Direct access to the legacyClassescollection and construction of aGrainClassMapfrom an arbitrary dictionary carry trimming warnings requiring separate constructor preservation. Production manifest construction consumes the registered options collection. Collection-boundary suppressions are confined to those established registration contracts.Constructor selection stays with
ActivatorUtilities, including preferred public constructors and activation-scoped dependency identity. Focused tests cover those outcomes in the existing test project and the sharedGrainActivationNativeAOT scenario. The expanded native scenario also activates a private grain registered exclusively throughAddClassand checks that generated metadata has not registered it. Removing constructor retention at either registration boundary reproduces the corresponding native activation failure; restoring it makes the same scenario pass.The branch is rebased onto
mainand reuses the shared smoke harness and common CI from merged #11367. This scenario keeps the wider runtime diagnostic backlog visible while rejecting constructor-path diagnostics; generic grain closure and runtime facet construction retain their existing diagnostics.The cumulative integration gate verified the original constructor-retention change alongside the existing series in a real Windows x64 NativeAOT executable with dynamic code disabled: ordinary
Host.StartAsync, applicationIAdditionGrain.Add(17, 25)returning42, and explicitStopAsyncwith graceful silo shutdown. It kept the original host configuration and deadline, the default-off generated-context setting, and source-generated grain registrations. This proof covers the exercised concrete, non-generic grain and local memory-storage host contract; the expanded focused native scenario verifies the manual-registration correction.Fixes #11381.
Microsoft Reviewers: Open in CodeFlow