mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
A stackalloc initializer whose first element is written twice must not be
folded into a 'stackalloc int[] { ... }': doing so drops the earlier store,
which is observable when its value has side effects. HandleSequentialLocAllocInitializer
already rejects this (the extra store trips the LoadCount and elementCount
guards); the sequential-store offset matcher on its own would misclassify the
second offset-0 write. The IL is derived from a C# 'stackalloc int[] { a, b, c }'
disassembly with an extra offset-0 store injected, a shape no compiler emits.
Assisted-by: Claude:claude-fable-5:Claude Code
master
3 changed files with 94 additions and 0 deletions
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty |
||||
{ |
||||
public static class StackAllocDuplicateStore |
||||
{ |
||||
public unsafe static int Seq(int a, int b, int c) |
||||
{ |
||||
byte* num = stackalloc byte[12]; |
||||
*(int*)num = a; |
||||
*(int*)num = 99; |
||||
((int*)num)[1] = b; |
||||
((int*)num)[2] = c; |
||||
Span<int> span = new Span<int>(num, 3); |
||||
return span[0] + span[1] + span[2]; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
// Metadata version: v4.0.30319 |
||||
.assembly extern System.Runtime |
||||
{ |
||||
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: |
||||
.ver 9:0:0:0 |
||||
} |
||||
.assembly StackAllocDuplicateStore |
||||
{ |
||||
.ver 1:0:0:0 |
||||
} |
||||
.module StackAllocDuplicateStore.dll |
||||
.corflags 0x00000001 // ILONLY |
||||
|
||||
// A stackalloc initializer that writes the first element twice. The sequential-store |
||||
// initializer transform must not fold this into a 'stackalloc int[] { ... }': the earlier |
||||
// store would be dropped, which is observable when its value has side effects. |
||||
|
||||
.class public abstract auto ansi sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.StackAllocDuplicateStore |
||||
extends [System.Runtime]System.Object |
||||
{ |
||||
.method public hidebysig static int32 Seq(int32 a, |
||||
int32 b, |
||||
int32 c) cil managed |
||||
{ |
||||
.maxstack 4 |
||||
.locals init (valuetype [System.Runtime]System.Span`1<int32> V_0) |
||||
IL_0000: ldc.i4.s 12 |
||||
IL_0002: conv.u |
||||
IL_0003: localloc |
||||
IL_0005: dup |
||||
IL_0006: ldarg.0 |
||||
IL_0007: stind.i4 |
||||
IL_0008: dup |
||||
IL_0009: ldc.i4.s 99 |
||||
IL_000b: stind.i4 |
||||
IL_000c: dup |
||||
IL_000d: ldc.i4.4 |
||||
IL_000e: add |
||||
IL_000f: ldarg.1 |
||||
IL_0010: stind.i4 |
||||
IL_0011: dup |
||||
IL_0012: ldc.i4.2 |
||||
IL_0013: conv.i |
||||
IL_0014: ldc.i4.4 |
||||
IL_0015: mul |
||||
IL_0016: add |
||||
IL_0017: ldarg.2 |
||||
IL_0018: stind.i4 |
||||
IL_0019: ldc.i4.3 |
||||
IL_001a: newobj instance void valuetype [System.Runtime]System.Span`1<int32>::.ctor(void*, |
||||
int32) |
||||
IL_001f: stloc.0 |
||||
IL_0020: ldloca.s V_0 |
||||
IL_0022: ldc.i4.0 |
||||
IL_0023: call instance !0& valuetype [System.Runtime]System.Span`1<int32>::get_Item(int32) |
||||
IL_0028: ldind.i4 |
||||
IL_0029: ldloca.s V_0 |
||||
IL_002b: ldc.i4.1 |
||||
IL_002c: call instance !0& valuetype [System.Runtime]System.Span`1<int32>::get_Item(int32) |
||||
IL_0031: ldind.i4 |
||||
IL_0032: add |
||||
IL_0033: ldloca.s V_0 |
||||
IL_0035: ldc.i4.2 |
||||
IL_0036: call instance !0& valuetype [System.Runtime]System.Span`1<int32>::get_Item(int32) |
||||
IL_003b: ldind.i4 |
||||
IL_003c: add |
||||
IL_003d: ret |
||||
} // end of method StackAllocDuplicateStore::Seq |
||||
|
||||
} // end of class StackAllocDuplicateStore |
||||
Loading…
Reference in new issue