-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
The JIT sometimes suppresses explicit zeroing for locals because it expects them to be zeroed by prolog:
runtime/src/coreclr/jit/importer.cpp
Lines 8890 to 8907 in e399e13
| bool bbInALoop = impBlockIsInALoop(block); | |
| bool bbIsReturn = block->KindIs(BBJ_RETURN) && | |
| (!compIsForInlining() || (impInlineInfo->iciBlock->KindIs(BBJ_RETURN))); | |
| LclVarDsc* const lclDsc = lvaGetDesc(lclNum); | |
| if (fgVarNeedsExplicitZeroInit(lclNum, bbInALoop, bbIsReturn)) | |
| { | |
| // Append a tree to zero-out the temp | |
| GenTree* newObjInit = | |
| gtNewZeroConNode(lclDsc->TypeIs(TYP_STRUCT) ? TYP_INT : lclDsc->TypeGet()); | |
| impStoreToTemp(lclNum, newObjInit, CHECK_SPILL_NONE); | |
| } | |
| else | |
| { | |
| JITDUMP("\nSuppressing zero-init for V%02u -- expect to zero in prolog\n", lclNum); | |
| lclDsc->lvSuppressedZeroInit = 1; | |
| compSuppressedZeroInit = true; | |
| } |
This can interact poorly with async. If we suppress the zeroing and the object was created after a suspension point, then wecan end up hoisting a default-valued local to the heap if we see what looks like a use (e.g. LCL_ADDR passed to a constructor).
We may consider turning off the suppressions in some cases, or perhaps we should have a fully-fledged "default value" analysis that the async transformation can use to determine if the something is default-valued at a suspension point.
A small repro looks like:
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
await FooAsync();
}
private static async Task FooAsync()
{
await Task.Yield();
Inline();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Inline()
{
S s = new S();
Console.WriteLine(s.A);
}
private struct S
{
public long A, B, C, D, E;
public object F;
[MethodImpl(MethodImplOptions.NoInlining)]
public S()
{
A = B = C = D = E = 10;
F = null;
}
}
}The JIT saves and restores the S that came from Inline at the suspension point in FooAsync.