JIT: preserve side effect ordering when unrolling UTF16 comparisons - #134099
Conversation
impUtf16StringComparison and impUtf16SpanComparison append the temp stores for
the unrolled comparison with CHECK_SPILL_NONE, so expressions still sitting on
the importer's evaluation stack below the call arguments were evaluated after
them. For obj.Equals("cns") / StartsWith / EndsWith the unrolled expansion
dereferences the receiver directly, so its NullReferenceException was raised
ahead of earlier side effects.
Spill the side effects of the stack entries below the arguments before
appending. Only those entries are spilled, so the already-captured argument
trees stay valid.
Fixes dotnet#133966
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 5 pipeline(s). 11 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings require fixes and additional regression coverage.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Fixes JIT evaluation-order regressions when unrolling UTF-16 string and span comparisons.
Changes:
- Spills earlier side effects before appending unrolled comparison trees.
- Adds regression coverage for exception ordering and comparison behavior.
File summaries
| File | Summary |
|---|---|
src/tests/JIT/Regression_ro_2/Runtime_133966.cs |
Adds regression tests for string comparison ordering. |
src/coreclr/jit/importervectorization.cpp |
Critical (1 vote): Spill GTF_ORDER_SIDEEFF entries as well as regular side effects. Moderate (3 votes): Add span-comparison coverage for exception ordering. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
Pop captured arguments before spilling the remaining stack through the shared helper, including global reads and special catch-argument effects. Add span exception-ordering coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b4f59c04-0b50-4dcd-a98a-e07b9b349619
There was a problem hiding this comment.
🔵 Needs a closer look
String and span paths still fail to spill stack entries containing only GTF_ORDER_SIDEEFF.
Review details
Suppressed comments (2)
src/coreclr/jit/importervectorization.cpp:523
impSpillSideEffects(true, ...)still does not spill an evaluation-stack tree whose only ordering flag isGTF_ORDER_SIDEEFF:impSpillSideEffectselectsGTF_GLOB_EFFECTforspillGlobEffects=true, whileGTF_ORDER_SIDEEFFis excluded from that mask. Such a tree below the popped arguments remains on the stack, so the followingCHECK_SPILL_NONEstores can still move this comparison ahead of the required ordering dependency. Please extend or use a spill path that also handlesGTF_ORDER_SIDEEFF.
impSpillSideEffects(true, CHECK_SPILL_ALL DEBUGARG("unrolled UTF16 string comparison"));
src/coreclr/jit/importervectorization.cpp:695
- The analogous span path has the same gap:
impSpillSideEffects(true, ...)only selectsGTF_GLOB_EFFECT, so a stack entry carrying onlyGTF_ORDER_SIDEEFFis left in place. The subsequentCHECK_SPILL_NONEstores can therefore still overtake that ordering dependency during span comparison expansion. Please extend or use a spill path that also handlesGTF_ORDER_SIDEEFF.
impSpillSideEffects(true, CHECK_SPILL_ALL DEBUGARG("unrolled UTF16 span comparison"));
- Files reviewed: 2/2 changed files
- Comments generated: 0 new
- Review effort level: Lite
jakobbotsch
left a comment
There was a problem hiding this comment.
LGTM, but seems the existing impStoreToTemp could instead pass CHECK_SPILL_ALL to benefit from normal interference checks
|
/ba-g known mono failure |
impUtf16StringComparison and impUtf16SpanComparison append the temp stores for the unrolled comparison with CHECK_SPILL_NONE, so expressions still sitting on the importer's evaluation stack below the call arguments were evaluated after them. For obj.Equals("cns") / StartsWith / EndsWith the unrolled expansion dereferences the receiver directly, so its NullReferenceException was raised ahead of earlier side effects.
Spill the side effects of the stack entries below the arguments before appending. Only those entries are spilled, so the already-captured argument trees stay valid.
Fixes #133966