Repository navigation
Conversation
…oval optRemoveRedundantZeroInits marks a GC local as explicitly initialized, so the prolog doesn't zero it, when no GC safe point precedes its first store. That's sound where tracked locals are only reported while live, but wasm reports every GC slot on the frame for the whole method, including aborted frames during exception dispatch. Wasm also has no hardware exceptions: a null check or other throwing tree becomes a call to a throw helper. So a GC ref local stored after a null check (e.g. Object.GetType's temps) was reported with whatever the stack held when the check threw, which failed pMT->Validate() in TypeIntrinsics_r on the browser-wasm R2R leg. On wasm, IsPotentialGCSafePoint now treats trees with GTF_EXCEPT as safe points. System.Private.CoreLib.wasm grows by 6,944 bytes (0.02%). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
|
The native whole appears to be real too. Will update after validating. |
I think then it shouldn't do it. We already suspect that |
…l targets Move the fix from IsPotentialGCSafePoint into optRemoveRedundantZeroInits and make it target-independent. A GC local reported as an untracked slot is reported whenever its frame is, including at a throw helper call that a tree before the local's first store may make. Natively, an address-exposed object local stored after a bounds check was reported uninitialized at the RNGCHKFAIL call, and the test now crashes without the fix on osx-arm64 even without GC stress. Wasm reports every GC local on the frame as untracked, so its codegen is unchanged from the previous commits. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
|
@EgorBo agreed. The latest push (e8083cd) still relies on that safe-point analysis, just with throwing trees added. That push also covers a native case of the same hole, for untracked locals; the repro and SuperPMI diffs are in the description. I'm switching to not marking untracked GC locals (all GC locals on wasm) as explicitly initialized at all, without relying on the safe-point scan. I'm implementing and testing that now, and will post SuperPMI and Note This comment was drafted with GitHub Copilot. |
Instead of extending the safe-point scan with throwing trees, don't mark GC locals reported as untracked slots as explicitly initialized at all. They are reported whenever their frame is, and optRemoveRedundantZeroInits runs before later phases (helper expansion, lowering) that can still introduce calls, so it can't rule out every gc-safe point before the store. Tracked GC locals are only reported where they're live and keep the optimization. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
|
@EgorBo updated in 8f3d1ef. Impact:
Details are in the description. Note This comment was drafted with GitHub Copilot. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
|
The wasm side of this is getting hit fairly frequently if would be good to get it a review. |
|
@EgorBo if you prefer, I can only modify wasm and add and activeissue to the test for the other platforms? |
|
@lewing I thought about this for a bit and realized that your initial fix was correct, you did if ((tree->gtFlags & GTF_EXCEPT) != 0)
{
return true;
}in |
|
This check is still potentially incorrect, but that needs a rewrite to do this analysis closer to codegen, because it's too early in the optimization pipeline to guess whether there will be gc safe points between two points or not. |
Per review, go back to counting trees with GTF_EXCEPT as potential GC safe points in IsPotentialGCSafePoint, without limiting it to wasm: a tree that may throw can call a throw helper, which is a GC safe point on every target. This replaces the untracked-local special case in optRemoveRedundantZeroInits. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45f42362-f012-4030-8643-26f4c1fbf2e1
|
Done in 0e216df, without the ifdef. Diffs are smaller than the untracked-only version: 70-99 contexts per target (+204 to +697 bytes), CoreLib.wasm +6,944 bytes. Note This comment was drafted with GitHub Copilot. |
optRemoveRedundantZeroInitsskips prolog zeroing for a GC local when no GC safe point precedes its first store.IsPotentialGCSafePointignored trees that may throw, but they can call a throw helper, which is a GC safe point. An uninitialized GC slot could then be reported:Object.GetType, the null check onthiscallsThrowNullReferenceExceptionbefore its GC temps are stored. A GC there reported stale stack contents andTypeIntrinsics_rasserted inpMT->Validate().IsPotentialGCSafePointnow returns true forGTF_EXCEPTtrees on all targets.The analysis still runs before helper expansion and lowering, so it can't see every safe point; doing it closer to codegen is separate work.
Diffs
SuperPMI (benchmarks, realworld, aspire):
System.Private.CoreLib.wasm: +6,944 bytes (0.02%).Validation
Runtime_135966, osx-arm64 Checked, GCStress=0/1/4JIT_r(browser-wasm R2R Checked, CI Helix payloads), GCStress=1pMT->Validate()assert, 3/3Runtime_135966, browser-wasm R2R, GCStress=0/1Resolves #135966
Note
This PR description was drafted with GitHub Copilot.