You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Explore internal accessor with compile checks https://github.com/aelij/IgnoresAccessChecksToGenerator #560
Investigated this against current master 734314ed. I opened draft #567 to add runtime-contract checks now, while keeping the generator/performance ideas separate: #567
Findings
IgnoresAccessChecksToGenerator currently publicizes internal members (and the corresponding combined accessibilities), but not private fields/methods or private nested types. That is an implementation choice, not a fundamental barrier: an opt-in extension could expose those too in generated build-time references, with IgnoresAccessChecksTo permitting access at runtime. It would not require replacing the installed CoreLib.
FEC uses both internal members (m_localSignature, m_localCount, UpdateStackSize, DynamicScope.m_tokens) and private fields (m_length, m_ILStream). There are two further obstacles in the stock-package 0.8.0 probe on Windows ARM64/.NET 10.0.9:
Normal framework reference assemblies omit RuntimeILGenerator, so C# still cannot resolve the type.
Explicitly adding the installed System.Private.CoreLib implementation makes the generator fail with Writing mixed-mode assemblies is not supported.
A possible extension would generate a metadata-only reference facade from the relevant runtime implementation, exposing selected private members/types rather than rewriting its executable image. The exact runtime assembly identity and member signatures would need to be preserved. Compiler checks against that facade would check the chosen build-time runtime version; they would not guarantee compatibility with every consumer runtime update.
Performance opportunities
Direct typed helpers could potentially replace reflection/generated DynamicMethod setup during initialization and remove delegate dispatch in the IL-generator reuse/local-allocation paths. Specialized/batched emission could provide additional opportunities, but is a separate change. Replacing an existing UnsafeAccessor field access alone is not an established improvement. These possibilities need cold-start, warmed compilation and allocation measurements; no speedup is claimed by #567, and compiled application runtime performance would only change if emitted code changes.
.NET 10: validate all six production UnsafeAccessor declarations against the executing runtime's exact declaring type and field/method signatures; bind and exercise the actual accessors to emit and run a method.
.NET 8/10: fail if local allocation or IL-generator reuse silently falls back; verify actual reuse across changed signatures, locals, tokens and exception regions while the original delegate remains valid.
Both Standard and LightExpression, automatically in the existing Windows/Linux CI runner. An isolated --runtime-accessor-contracts option returns a nonzero exit for assertion failures too.
The isolated checks pass on .NET 10.0.9 (6 total) and .NET 8.0.28 (2 total), and a negative probe with reuse deliberately disabled fails as intended. Release runner builds pass, including Framework 4.7.2 (where this CoreCLR-specific fixture is excluded). The full ARM64 suites also exhibit a LightExpression nullable MultiplyChecked mismatch on .NET 10 and the Issue346 by-ref float crash on .NET 8; both reproduce without invoking the new fixture and are documented in the PR, not skipped here.
I tried the follow-up prototype and opened a separate experimental draft: #568. The earlier runtime-contract test PR #567 remains separate and unchanged.
The private-access approach works in the tested setup. The local source/backend fork replaces Cecil with System.Reflection.Metadata / System.Reflection.PortableExecutable, optionally exposes private fields/methods/nested types in build-time references, and includes an MSBuild task. Upstream MIT licensing and the reviewed source revision are retained. This is not yet a drop-in replacement for the entire upstream NuGet package.
Findings:
SDK reference assemblies omit implementation types such as RuntimeILGenerator. The stock publicizer cannot expose something absent from its input.
The original stock-package failure occurred in a net10.0 project when rewriting the installed .NET 10 CoreLib: Cecil reports Writing mixed-mode assemblies is not supported for the non-IL-only image. No .NET Core DLL was added to a .NET Framework project.
Generating a fresh IL-only reference image from implementation metadata avoids that writer limitation. The installed runtime stays unchanged; IgnoresAccessChecksTo authorizes the consumer's actual private access.
A full CoreLib facade cannot simply be added alongside SDK references: duplicate core-type definitions conflict. This prototype uses the managed implementation references from one explicitly selected runtime, substituting the generated CoreLib reference for compilation. This introduces runtime-version/OS-specific build inputs and platform annotations; it is not a portable targeting pack or a guarantee for every consumer runtime version.
A private nested-type probe (Array.ArrayAssignType) compiled on .NET 10 but failed on .NET 8 because the type is absent there. The retained cross-version probe uses GC.StartNoGCRegionStatus, confirmed genuinely private on both. This illustrates the versioning issue rather than hiding it.
Validation: 25/25 replay checks passed on Windows ARM64, SDK 10.0.301, .NET 8.0.28 and 10.0.9. Direct private-field/private-method/private-nested-type access and MSBuild integration execute successfully. Both Standard and LightExpression pass the isolated FEC smoke configurations (400 repeated local/try-finally expression compilations across four configurations, nested captures, and eight runtime-contract cases). Negative checks detect disabled private exposure, missing access permission (TypeAccessException), a nonexistent member (CS1061) and wrong field type (CS0029). These are 25 replay steps, not 25 independent unit tests. Runtime versions are pinned; installed CoreLib hashes remain unchanged, and no facade is copied to consumer output.
Recommendation: do not merge this follow-up into master in its current form; keep it as a draft. It proves feasibility, not a performance improvement. There are no before/after startup, compilation, allocation, execution or build-cost measurements yet. Direct typed helpers might reduce initialization work/delegate dispatch; replacing an existing UnsafeAccessor field access alone is not an established speedup. Application runtime benefits would need changed emitted code and measurement.
Before production integration, decide the runtime-version/reference strategy, narrow the exposure where possible, measure against existing helpers, and add broader OS/architecture and regression coverage. The task currently supports CoreLib and .NET 10 MSBuild only; it does not yet implement upstream option parity, general-package handling, packaging or incremental-generation caching. The focused metadata verifier is not general rewriter certification. Review #567's smaller runtime-contract tests independently. The draft contains the full findings, commands, input hashes and replay instructions; it does not claim to close #560.
Activity
jogibear9988 commentedon Oct 26, 2026
Investigated this against current master
734314ed. I opened draft #567 to add runtime-contract checks now, while keeping the generator/performance ideas separate: #567Findings
IgnoresAccessChecksToGenerator currently publicizes internal members (and the corresponding combined accessibilities), but not private fields/methods or private nested types. That is an implementation choice, not a fundamental barrier: an opt-in extension could expose those too in generated build-time references, with IgnoresAccessChecksTo permitting access at runtime. It would not require replacing the installed CoreLib.
FEC uses both internal members (
m_localSignature,m_localCount,UpdateStackSize,DynamicScope.m_tokens) and private fields (m_length,m_ILStream). There are two further obstacles in the stock-package 0.8.0 probe on Windows ARM64/.NET 10.0.9:RuntimeILGenerator, so C# still cannot resolve the type.System.Private.CoreLibimplementation makes the generator fail withWriting mixed-mode assemblies is not supported.A possible extension would generate a metadata-only reference facade from the relevant runtime implementation, exposing selected private members/types rather than rewriting its executable image. The exact runtime assembly identity and member signatures would need to be preserved. Compiler checks against that facade would check the chosen build-time runtime version; they would not guarantee compatibility with every consumer runtime update.
Performance opportunities
Direct typed helpers could potentially replace reflection/generated DynamicMethod setup during initialization and remove delegate dispatch in the IL-generator reuse/local-allocation paths. Specialized/batched emission could provide additional opportunities, but is a separate change. Replacing an existing UnsafeAccessor field access alone is not an established improvement. These possibilities need cold-start, warmed compilation and allocation measurements; no speedup is claimed by #567, and compiled application runtime performance would only change if emitted code changes.
What #567 adds
--runtime-accessor-contractsoption returns a nonzero exit for assertion failures too.The isolated checks pass on .NET 10.0.9 (6 total) and .NET 8.0.28 (2 total), and a negative probe with reuse deliberately disabled fails as intended. Release runner builds pass, including Framework 4.7.2 (where this CoreCLR-specific fixture is excluded). The full ARM64 suites also exhibit a LightExpression nullable MultiplyChecked mismatch on .NET 10 and the Issue346 by-ref float crash on .NET 8; both reproduce without invoking the new fixture and are documented in the PR, not skipped here.
Generator implementation reviewed: https://github.com/aelij/IgnoresAccessChecksToGenerator/blob/main/src/IgnoresAccessChecksToGenerator.Tasks/PublicizeInternals.cs
jogibear9988 commentedon Oct 26, 2026
I tried the follow-up prototype and opened a separate experimental draft: #568. The earlier runtime-contract test PR #567 remains separate and unchanged.
The private-access approach works in the tested setup. The local source/backend fork replaces Cecil with
System.Reflection.Metadata/System.Reflection.PortableExecutable, optionally exposes private fields/methods/nested types in build-time references, and includes an MSBuild task. Upstream MIT licensing and the reviewed source revision are retained. This is not yet a drop-in replacement for the entire upstream NuGet package.Findings:
RuntimeILGenerator. The stock publicizer cannot expose something absent from its input.Writing mixed-mode assemblies is not supportedfor the non-IL-only image. No .NET Core DLL was added to a .NET Framework project.IgnoresAccessChecksToauthorizes the consumer's actual private access.Array.ArrayAssignType) compiled on .NET 10 but failed on .NET 8 because the type is absent there. The retained cross-version probe usesGC.StartNoGCRegionStatus, confirmed genuinely private on both. This illustrates the versioning issue rather than hiding it.Validation: 25/25 replay checks passed on Windows ARM64, SDK 10.0.301, .NET 8.0.28 and 10.0.9. Direct private-field/private-method/private-nested-type access and MSBuild integration execute successfully. Both Standard and LightExpression pass the isolated FEC smoke configurations (400 repeated local/try-finally expression compilations across four configurations, nested captures, and eight runtime-contract cases). Negative checks detect disabled private exposure, missing access permission (
TypeAccessException), a nonexistent member (CS1061) and wrong field type (CS0029). These are 25 replay steps, not 25 independent unit tests. Runtime versions are pinned; installed CoreLib hashes remain unchanged, and no facade is copied to consumer output.Recommendation: do not merge this follow-up into master in its current form; keep it as a draft. It proves feasibility, not a performance improvement. There are no before/after startup, compilation, allocation, execution or build-cost measurements yet. Direct typed helpers might reduce initialization work/delegate dispatch; replacing an existing UnsafeAccessor field access alone is not an established speedup. Application runtime benefits would need changed emitted code and measurement.
Before production integration, decide the runtime-version/reference strategy, narrow the exposure where possible, measure against existing helpers, and add broader OS/architecture and regression coverage. The task currently supports CoreLib and .NET 10 MSBuild only; it does not yet implement upstream option parity, general-package handling, packaging or incremental-generation caching. The focused metadata verifier is not general rewriter certification. Review #567's smaller runtime-contract tests independently. The draft contains the full findings, commands, input hashes and replay instructions; it does not claim to close #560.