Browse Source

Merge pull request #924 from icsharpcode/unsafe

Improve decompilation of pointer arithmetic and other "unsafe" C# constructs
pull/940/merge
Daniel Grunwald 8 years ago committed by GitHub
parent
commit
00759d2691
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 46
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs
  4. 148
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/UnsafeCode.cs
  5. 1
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/.gitignore
  6. 1
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/.gitignore
  7. 288
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  8. 1149
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.il
  9. 904
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.il
  10. 910
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.roslyn.il
  11. 1155
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.roslyn.il
  12. 45
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  13. 420
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  14. 29
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  15. 9
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs
  16. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  17. 2
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  18. 2
      ICSharpCode.Decompiler/IL/Instructions.cs
  19. 3
      ICSharpCode.Decompiler/IL/Instructions.tt
  20. 13
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  21. 13
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  22. 23
      ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -76,6 +76,7 @@ @@ -76,6 +76,7 @@
<Compile Include="TestCases\Correctness\Using.cs" />
<Compile Include="TestCases\ILPretty\Issue379.cs" />
<Compile Include="TestCases\Pretty\FixProxyCalls.cs" />
<Compile Include="TestCases\Pretty\UnsafeCode.cs" />
<Compile Include="TestCases\Pretty\InitializerTests.cs" />
<None Include="TestCases\ILPretty\Issue646.cs" />
<Compile Include="TestCases\Pretty\Async.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -181,6 +181,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -181,6 +181,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
[Test]
public void UnsafeCode([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);
}
[Test]
public void PInvoke([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{

46
ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs

@ -25,6 +25,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -25,6 +25,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
static void Main()
{
InterestingConstants();
TruncatedComp();
}
static void Print<T>(T val)
@ -46,5 +47,50 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -46,5 +47,50 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Print(val2);
Print(2147483648u);
}
static void TruncatedComp()
{
Console.WriteLine("TruncatedComp1(1):");
TruncatedComp1(1);
Console.WriteLine("TruncatedComp1(-1):");
TruncatedComp1(-1);
Console.WriteLine("TruncatedComp1(0x100000001):");
TruncatedComp1(0x100000001);
Console.WriteLine("TruncatedComp1(long.MinValue):");
TruncatedComp1(long.MinValue);
Console.WriteLine("TruncatedComp2(1):");
TruncatedComp2(1, 1);
Console.WriteLine("TruncatedComp2(-1):");
TruncatedComp2(-1, -1);
Console.WriteLine("TruncatedComp2(0x100000001):");
TruncatedComp2(0x100000001, 1);
Console.WriteLine("TruncatedComp2(long.MinValue):");
TruncatedComp2(long.MinValue, int.MinValue);
}
static void TruncatedComp1(long val)
{
Print((int)val == val);
Print(val == (int)val);
Print(val < (int)val);
Print((int)val >= val);
}
static void TruncatedComp2(long val1, int val2)
{
Print(val1 == val2);
Print((int)val1 == val2);
Print(val1 < val2);
Print((int)val1 < val2);
Print(val1 <= val2);
Print((int)val1 <= val2);
}
}
}

148
ICSharpCode.Decompiler.Tests/TestCases/Correctness/UnsafeCode.cs

@ -22,7 +22,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -22,7 +22,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
public class UnsafeCode
{
struct SimpleStruct
private struct SimpleStruct
{
public int X;
public double Y;
@ -34,58 +34,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -34,58 +34,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
// (but for now, it's already valuable knowing whether the decompiled code can be re-compiled)
}
public unsafe int* NullPointer
{
get {
return null;
}
}
public unsafe int* PointerCast(long* p)
{
return (int*)p;
}
public unsafe long ConvertDoubleToLong(double d)
{
return *(long*)(&d);
}
public unsafe double ConvertLongToDouble(long d)
{
return *(double*)(&d);
}
public unsafe int ConvertFloatToInt(float d)
{
return *(int*)(&d);
}
public unsafe float ConvertIntToFloat(int d)
{
return *(float*)(&d);
}
public unsafe void PassRefParameterAsPointer(ref int p)
{
fixed (int* ptr = &p) {
this.PassPointerAsRefParameter(ptr);
}
}
public unsafe void PassPointerAsRefParameter(int* p)
{
this.PassRefParameterAsPointer(ref *p);
}
public unsafe void AddressInMultiDimensionalArray(double[,] matrix)
{
fixed (double* ptr = &matrix[1, 2]) {
this.PointerReferenceExpression(ptr);
this.PointerReferenceExpression(ptr);
}
}
public unsafe int MultipleExitsOutOfFixedBlock(int[] arr)
{
fixed (int* ptr = &arr[0]) {
@ -101,42 +49,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -101,42 +49,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine("outside");
return 2;
}
public unsafe void FixedStringAccess(string text)
{
fixed (char* ptr = text) {
char* ptr2 = ptr;
while (*ptr2 != '\0') {
*ptr2 = 'A';
ptr2++;
}
}
}
public unsafe void PutDoubleIntoLongArray1(long[] array, int index, double val)
{
fixed (long* ptr = array) {
((double*)ptr)[index] = val;
}
}
public unsafe void PutDoubleIntoLongArray2(long[] array, int index, double val)
{
fixed (long* ptr = &array[index]) {
*(double*)ptr = val;
}
}
public unsafe string PointerReferenceExpression(double* d)
{
return d->ToString();
}
public unsafe string PointerReferenceExpression2(long addr)
{
return ((int*)addr)->ToString();
}
public unsafe void FixMultipleStrings(string text)
{
fixed (char* ptr = text, userName = Environment.UserName, ptr2 = text) {
@ -146,66 +59,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -146,66 +59,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
}
}
public unsafe string StackAlloc(int count)
{
char* ptr = stackalloc char[count];
char* ptr2 = stackalloc char[100];
for (int i = 0; i < count; i++) {
ptr[i] = (char)i;
}
return this.PointerReferenceExpression((double*)ptr);
}
public unsafe string StackAllocStruct(int count)
{
SimpleStruct* s = stackalloc SimpleStruct[checked(count * 2)];
SimpleStruct* p = stackalloc SimpleStruct[10];
return this.PointerReferenceExpression(&s->Y);
}
public unsafe int* PointerArithmetic(int* p)
{
return p + 2;
}
public unsafe byte* PointerArithmetic2(long* p, int y, int x)
{
return (byte*)((short*)p + (y * x));
}
public unsafe long* PointerArithmetic3(long* p)
{
return (long*)((byte*)p + 3);
}
public unsafe long* PointerArithmetic4(void* p)
{
return (long*)((byte*)p + 3);
}
public unsafe int PointerArithmetic5(void* p, byte* q, int i)
{
return (int)(q[i] + *(byte*)p);
}
public unsafe int PointerSubtraction(long* p, long* q)
{
return (int)((long)(p - q));
}
public unsafe int PointerSubtraction2(long* p, short* q)
{
return (int)((long)((byte*)p - (byte*)q));
}
public unsafe int PointerSubtraction3(void* p, void* q)
{
return (int)((long)((byte*)p - (byte*)q));
}
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);
}
}
}

1
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
/*.dll

1
ICSharpCode.Decompiler.Tests/TestCases/Pretty/.gitignore vendored

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
/*.res
/*.dll
/*.exe
/*.pdb

288
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -0,0 +1,288 @@ @@ -0,0 +1,288 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class UnsafeCode
{
public struct SimpleStruct
{
public int X;
public double Y;
}
public struct StructWithFixedSizeMembers
{
public unsafe fixed int Integers[100];
public int NormalMember;
public unsafe fixed double Doubles[200];
[Obsolete("another attribute")]
public unsafe fixed byte Old[1];
}
public unsafe int* NullPointer {
get {
return null;
}
}
public unsafe int SizeOf()
{
return sizeof(SimpleStruct);
}
private static void UseBool(bool b)
{
}
public unsafe void PointerComparison(int* a, double* b)
{
UnsafeCode.UseBool(a == b);
UnsafeCode.UseBool(a != b);
UnsafeCode.UseBool(a < b);
UnsafeCode.UseBool(a > b);
UnsafeCode.UseBool(a <= b);
UnsafeCode.UseBool(a >= b);
}
public unsafe void PointerComparisonWithNull(int* a)
{
UnsafeCode.UseBool(a == null);
UnsafeCode.UseBool(a != null);
}
public unsafe int* PointerCast(long* p)
{
return (int*)p;
}
public unsafe long ConvertDoubleToLong(double d)
{
return *(long*)(&d);
}
public unsafe double ConvertLongToDouble(long d)
{
return *(double*)(&d);
}
public unsafe int ConvertFloatToInt(float d)
{
return *(int*)(&d);
}
public unsafe float ConvertIntToFloat(int d)
{
return *(float*)(&d);
}
public unsafe int PointerCasts()
{
int result = 0;
*(float*)(&result) = 0.5f;
((byte*)(&result))[3] = 3;
return result;
}
public unsafe void PassRefParameterAsPointer(ref int p)
{
fixed (int* p2 = &p) {
this.PassPointerAsRefParameter(p2);
}
}
public unsafe void PassPointerAsRefParameter(int* p)
{
this.PassRefParameterAsPointer(ref *p);
}
public unsafe void AddressInMultiDimensionalArray(double[,] matrix)
{
fixed (double* d = &matrix[1, 2]) {
this.PointerReferenceExpression(d);
this.PointerReferenceExpression(d);
}
}
public unsafe void FixedStringAccess(string text)
{
fixed (char* ptr = text) {
char* ptr2 = ptr;
while (*ptr2 == 'a') {
*ptr2 = 'A';
ptr2++;
}
}
}
public unsafe void PutDoubleIntoLongArray1(long[] array, int index, double val)
{
fixed (long* ptr = array) {
*(double*)(ptr + index) = val;
}
}
public unsafe void PutDoubleIntoLongArray2(long[] array, int index, double val)
{
fixed (long* ptr = &array[index]) {
*(double*)ptr = val;
}
}
public unsafe string PointerReferenceExpression(double* d)
{
return d->ToString();
}
public unsafe string PointerReferenceExpression2(long addr)
{
return ((int*)addr)->ToString();
}
public unsafe int* PointerArithmetic(int* p)
{
return p + 2;
}
public unsafe long* PointerArithmetic2(long* p)
{
return 3 + p;
}
public unsafe long* PointerArithmetic3(long* p)
{
return (long*)((byte*)p + 3);
}
public unsafe long* PointerArithmetic4(void* p)
{
return (long*)((byte*)p + 3);
}
public unsafe int PointerArithmetic5(void* p, byte* q, int i)
{
return q[i] + *(byte*)p;
}
public unsafe int PointerArithmetic6(SimpleStruct* p, int i)
{
return p[i].X;
}
public unsafe int* PointerArithmeticLong1(int* p, long offset)
{
return p + offset;
}
public unsafe int* PointerArithmeticLong2(int* p, long offset)
{
return offset + p;
}
public unsafe int* PointerArithmeticLong3(int* p, long offset)
{
return p - offset;
}
public unsafe SimpleStruct* PointerArithmeticLong1s(SimpleStruct* p, long offset)
{
return p + offset;
}
public unsafe SimpleStruct* PointerArithmeticLong2s(SimpleStruct* p, long offset)
{
return offset + p;
}
public unsafe SimpleStruct* PointerArithmeticLong3s(SimpleStruct* p, long offset)
{
return p - offset;
}
public unsafe int PointerSubtraction(long* p, long* q)
{
return (int)(p - q);
}
public unsafe long PointerSubtractionLong(long* p, long* q)
{
return p - q;
}
public unsafe int PointerSubtraction2(long* p, short* q)
{
return (int)((byte*)p - (byte*)q);
}
public unsafe int PointerSubtraction3(void* p, void* q)
{
return (int)((byte*)p - (byte*)q);
}
public unsafe long PointerSubtraction4(sbyte* p, sbyte* q)
{
return p - q;
}
public unsafe long PointerSubtraction5(SimpleStruct* p, SimpleStruct* q)
{
return p - q;
}
public unsafe double FixedMemberAccess(StructWithFixedSizeMembers* m, int i)
{
return (double)m->Integers[i] + m->Doubles[i];
}
public unsafe double* FixedMemberBasePointer(StructWithFixedSizeMembers* m)
{
return m->Doubles;
}
public unsafe string UsePointer(double* ptr)
{
return ptr->ToString();
}
public unsafe string StackAlloc(int count)
{
char* ptr = stackalloc char[count];
char* ptr2 = stackalloc char[100];
for (int i = 0; i < count; i++) {
ptr[i] = (char)i;
ptr2[i] = '\0';
}
return this.UsePointer((double*)ptr);
}
public unsafe string StackAllocStruct(int count)
{
SimpleStruct* ptr = stackalloc SimpleStruct[checked(count * 2)];
SimpleStruct* _ = stackalloc SimpleStruct[10];
return this.UsePointer(&ptr->Y);
}
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);
}
}
}

1149
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.il

File diff suppressed because it is too large Load Diff

904
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.il

@ -0,0 +1,904 @@ @@ -0,0 +1,904 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly zuwavv1x
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module zuwavv1x.dll
// MVID: {4CC9FC6C-21CA-408A-ABC9-544A07D1E512}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x01600000
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode
extends [mscorlib]System.Object
{
.class sequential ansi sealed nested public beforefieldinit SimpleStruct
extends [mscorlib]System.ValueType
{
.field public int32 X
.field public float64 Y
} // end of class SimpleStruct
.class sequential ansi sealed nested public beforefieldinit StructWithFixedSizeMembers
extends [mscorlib]System.ValueType
{
.class sequential ansi sealed nested public beforefieldinit '<Integers>e__FixedBuffer0'
extends [mscorlib]System.ValueType
{
.pack 0
.size 400
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.UnsafeValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field public int32 FixedElementField
} // end of class '<Integers>e__FixedBuffer0'
.class sequential ansi sealed nested public beforefieldinit '<Doubles>e__FixedBuffer1'
extends [mscorlib]System.ValueType
{
.pack 0
.size 1600
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.UnsafeValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field public float64 FixedElementField
} // end of class '<Doubles>e__FixedBuffer1'
.class sequential ansi sealed nested public beforefieldinit '<Old>e__FixedBuffer2'
extends [mscorlib]System.ValueType
{
.pack 0
.size 1
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.UnsafeValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field public uint8 FixedElementField
} // end of class '<Old>e__FixedBuffer2'
.field public valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Integers>e__FixedBuffer0' Integers
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type,
int32) = ( 01 00 59 53 79 73 74 65 6D 2E 49 6E 74 33 32 2C // ..YSystem.Int32,
20 6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 69 // mscorlib, Versi
6F 6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C 74 // on=4.0.0.0, Cult
75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 // ure=neutral, Pub
6C 69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 61 // licKeyToken=b77a
35 63 35 36 31 39 33 34 65 30 38 39 64 00 00 00 // 5c561934e089d...
00 00 )
.field public int32 NormalMember
.field public valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer1' Doubles
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type,
int32) = ( 01 00 5A 53 79 73 74 65 6D 2E 44 6F 75 62 6C 65 // ..ZSystem.Double
2C 20 6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 // , mscorlib, Vers
69 6F 6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C // ion=4.0.0.0, Cul
74 75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 // ture=neutral, Pu
62 6C 69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 // blicKeyToken=b77
61 35 63 35 36 31 39 33 34 65 30 38 39 C8 00 00 // a5c561934e089...
00 00 00 )
.field public valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Old>e__FixedBuffer2' Old
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type,
int32) = ( 01 00 58 53 79 73 74 65 6D 2E 42 79 74 65 2C 20 // ..XSystem.Byte,
6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 69 6F // mscorlib, Versio
6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C 74 75 // n=4.0.0.0, Cultu
72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 6C // re=neutral, Publ
69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 61 35 // icKeyToken=b77a5
63 35 36 31 39 33 34 65 30 38 39 01 00 00 00 00 // c561934e089.....
00 )
.custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string) = ( 01 00 11 61 6E 6F 74 68 65 72 20 61 74 74 72 69 // ...another attri
62 75 74 65 00 00 ) // bute..
} // end of class StructWithFixedSizeMembers
.method public hidebysig specialname instance int32*
get_NullPointer() cil managed
{
// Code size 3 (0x3)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: conv.u
IL_0002: ret
} // end of method UnsafeCode::get_NullPointer
.method public hidebysig instance int32
SizeOf() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0006: ret
} // end of method UnsafeCode::SizeOf
.method private hidebysig static void UseBool(bool b) cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method UnsafeCode::UseBool
.method public hidebysig instance void
PointerComparison(int32* a,
float64* b) cil managed
{
// Code size 64 (0x40)
.maxstack 2
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ceq
IL_0004: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0009: ldarg.1
IL_000a: ldarg.2
IL_000b: ceq
IL_000d: ldc.i4.0
IL_000e: ceq
IL_0010: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0015: ldarg.1
IL_0016: ldarg.2
IL_0017: clt.un
IL_0019: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_001e: ldarg.1
IL_001f: ldarg.2
IL_0020: cgt.un
IL_0022: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0027: ldarg.1
IL_0028: ldarg.2
IL_0029: cgt.un
IL_002b: ldc.i4.0
IL_002c: ceq
IL_002e: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0033: ldarg.1
IL_0034: ldarg.2
IL_0035: clt.un
IL_0037: ldc.i4.0
IL_0038: ceq
IL_003a: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_003f: ret
} // end of method UnsafeCode::PointerComparison
.method public hidebysig instance void
PointerComparisonWithNull(int32* a) cil managed
{
// Code size 24 (0x18)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: conv.u
IL_0003: ceq
IL_0005: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_000a: ldarg.1
IL_000b: ldc.i4.0
IL_000c: conv.u
IL_000d: ceq
IL_000f: ldc.i4.0
IL_0010: ceq
IL_0012: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0017: ret
} // end of method UnsafeCode::PointerComparisonWithNull
.method public hidebysig instance int32*
PointerCast(int64* p) cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ret
} // end of method UnsafeCode::PointerCast
.method public hidebysig instance int64
ConvertDoubleToLong(float64 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.i8
IL_0004: ret
} // end of method UnsafeCode::ConvertDoubleToLong
.method public hidebysig instance float64
ConvertLongToDouble(int64 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.r8
IL_0004: ret
} // end of method UnsafeCode::ConvertLongToDouble
.method public hidebysig instance int32
ConvertFloatToInt(float32 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.i4
IL_0004: ret
} // end of method UnsafeCode::ConvertFloatToInt
.method public hidebysig instance float32
ConvertIntToFloat(int32 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.r4
IL_0004: ret
} // end of method UnsafeCode::ConvertIntToFloat
.method public hidebysig instance int32
PointerCasts() cil managed
{
// Code size 21 (0x15)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: conv.u
IL_0005: ldc.r4 0.5
IL_000a: stind.r4
IL_000b: ldloca.s V_0
IL_000d: conv.u
IL_000e: ldc.i4.3
IL_000f: conv.i
IL_0010: add
IL_0011: ldc.i4.3
IL_0012: stind.i1
IL_0013: ldloc.0
IL_0014: ret
} // end of method UnsafeCode::PointerCasts
.method public hidebysig instance void
PassRefParameterAsPointer(int32& p) cil managed
{
// Code size 14 (0xe)
.maxstack 2
.locals init (int32& pinned V_0)
IL_0000: ldarg.1
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: ldloc.0
IL_0004: conv.i
IL_0005: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PassPointerAsRefParameter(int32*)
IL_000a: ldc.i4.0
IL_000b: conv.u
IL_000c: stloc.0
IL_000d: ret
} // end of method UnsafeCode::PassRefParameterAsPointer
.method public hidebysig instance void
PassPointerAsRefParameter(int32* p) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PassRefParameterAsPointer(int32&)
IL_0007: ret
} // end of method UnsafeCode::PassPointerAsRefParameter
.method public hidebysig instance void
AddressInMultiDimensionalArray(float64[0...,0...] matrix) cil managed
{
// Code size 31 (0x1f)
.maxstack 3
.locals init (float64& pinned V_0)
IL_0000: ldarg.1
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: call instance float64& float64[0...,0...]::Address(int32,
int32)
IL_0008: stloc.0
IL_0009: ldarg.0
IL_000a: ldloc.0
IL_000b: conv.i
IL_000c: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PointerReferenceExpression(float64*)
IL_0011: pop
IL_0012: ldarg.0
IL_0013: ldloc.0
IL_0014: conv.i
IL_0015: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PointerReferenceExpression(float64*)
IL_001a: pop
IL_001b: ldc.i4.0
IL_001c: conv.u
IL_001d: stloc.0
IL_001e: ret
} // end of method UnsafeCode::AddressInMultiDimensionalArray
.method public hidebysig instance void
FixedStringAccess(string text) cil managed
{
// Code size 36 (0x24)
.maxstack 2
.locals init (char* V_0,
char* V_1,
string pinned V_2)
IL_0000: ldarg.1
IL_0001: stloc.2
IL_0002: ldloc.2
IL_0003: conv.i
IL_0004: dup
IL_0005: brfalse.s IL_000d
IL_0007: call int32 [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_000c: add
IL_000d: stloc.0
IL_000e: ldloc.0
IL_000f: stloc.1
IL_0010: br.s IL_001b
IL_0012: ldloc.1
IL_0013: ldc.i4.s 65
IL_0015: stind.i2
IL_0016: ldloc.1
IL_0017: ldc.i4.2
IL_0018: conv.i
IL_0019: add
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: ldind.u2
IL_001d: ldc.i4.s 97
IL_001f: beq.s IL_0012
IL_0021: ldnull
IL_0022: stloc.2
IL_0023: ret
} // end of method UnsafeCode::FixedStringAccess
.method public hidebysig instance void
PutDoubleIntoLongArray1(int64[] 'array',
int32 index,
float64 val) cil managed
{
// Code size 36 (0x24)
.maxstack 3
.locals init (int64& pinned V_0,
int64[] V_1)
IL_0000: ldarg.1
IL_0001: dup
IL_0002: stloc.1
IL_0003: brfalse.s IL_000a
IL_0005: ldloc.1
IL_0006: ldlen
IL_0007: conv.i4
IL_0008: brtrue.s IL_000f
IL_000a: ldc.i4.0
IL_000b: conv.u
IL_000c: stloc.0
IL_000d: br.s IL_0017
IL_000f: ldloc.1
IL_0010: ldc.i4.0
IL_0011: ldelema [mscorlib]System.Int64
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: conv.i
IL_0019: ldarg.2
IL_001a: conv.i
IL_001b: ldc.i4.8
IL_001c: mul
IL_001d: add
IL_001e: ldarg.3
IL_001f: stind.r8
IL_0020: ldc.i4.0
IL_0021: conv.u
IL_0022: stloc.0
IL_0023: ret
} // end of method UnsafeCode::PutDoubleIntoLongArray1
.method public hidebysig instance void
PutDoubleIntoLongArray2(int64[] 'array',
int32 index,
float64 val) cil managed
{
// Code size 16 (0x10)
.maxstack 2
.locals init (int64& pinned V_0)
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ldelema [mscorlib]System.Int64
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: conv.i
IL_000a: ldarg.3
IL_000b: stind.r8
IL_000c: ldc.i4.0
IL_000d: conv.u
IL_000e: stloc.0
IL_000f: ret
} // end of method UnsafeCode::PutDoubleIntoLongArray2
.method public hidebysig instance string
PointerReferenceExpression(float64* d) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call instance string [mscorlib]System.Double::ToString()
IL_0006: ret
} // end of method UnsafeCode::PointerReferenceExpression
.method public hidebysig instance string
PointerReferenceExpression2(int64 addr) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: conv.u
IL_0002: call instance string [mscorlib]System.Int32::ToString()
IL_0007: ret
} // end of method UnsafeCode::PointerReferenceExpression2
.method public hidebysig instance int32*
PointerArithmetic(int32* p) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.8
IL_0002: conv.i
IL_0003: add
IL_0004: ret
} // end of method UnsafeCode::PointerArithmetic
.method public hidebysig instance int64*
PointerArithmetic2(int64* p) cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: ldc.i4.s 24
IL_0002: conv.i
IL_0003: ldarg.1
IL_0004: add
IL_0005: ret
} // end of method UnsafeCode::PointerArithmetic2
.method public hidebysig instance int64*
PointerArithmetic3(int64* p) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.3
IL_0002: conv.i
IL_0003: add
IL_0004: ret
} // end of method UnsafeCode::PointerArithmetic3
.method public hidebysig instance int64*
PointerArithmetic4(void* p) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.3
IL_0002: conv.i
IL_0003: add
IL_0004: ret
} // end of method UnsafeCode::PointerArithmetic4
.method public hidebysig instance int32
PointerArithmetic5(void* p,
uint8* q,
int32 i) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.2
IL_0001: ldarg.3
IL_0002: add
IL_0003: ldind.u1
IL_0004: ldarg.1
IL_0005: ldind.u1
IL_0006: add
IL_0007: ret
} // end of method UnsafeCode::PointerArithmetic5
.method public hidebysig instance int32
PointerArithmetic6(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int32 i) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: conv.i
IL_0003: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0009: mul
IL_000a: add
IL_000b: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct::X
IL_0010: ret
} // end of method UnsafeCode::PointerArithmetic6
.method public hidebysig instance int32*
PointerArithmeticLong1(int32* p,
int64 offset) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ldc.i4.4
IL_0003: conv.i8
IL_0004: mul
IL_0005: conv.i
IL_0006: add
IL_0007: ret
} // end of method UnsafeCode::PointerArithmeticLong1
.method public hidebysig instance int32*
PointerArithmeticLong2(int32* p,
int64 offset) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.2
IL_0001: ldc.i4.4
IL_0002: conv.i8
IL_0003: mul
IL_0004: conv.i
IL_0005: ldarg.1
IL_0006: add
IL_0007: ret
} // end of method UnsafeCode::PointerArithmeticLong2
.method public hidebysig instance int32*
PointerArithmeticLong3(int32* p,
int64 offset) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ldc.i4.4
IL_0003: conv.i8
IL_0004: mul
IL_0005: conv.i
IL_0006: sub
IL_0007: ret
} // end of method UnsafeCode::PointerArithmeticLong3
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct*
PointerArithmeticLong1s(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int64 offset) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0008: conv.i8
IL_0009: mul
IL_000a: conv.i
IL_000b: add
IL_000c: ret
} // end of method UnsafeCode::PointerArithmeticLong1s
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct*
PointerArithmeticLong2s(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int64 offset) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.2
IL_0001: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0007: conv.i8
IL_0008: mul
IL_0009: conv.i
IL_000a: ldarg.1
IL_000b: add
IL_000c: ret
} // end of method UnsafeCode::PointerArithmeticLong2s
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct*
PointerArithmeticLong3s(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int64 offset) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0008: conv.i8
IL_0009: mul
IL_000a: conv.i
IL_000b: sub
IL_000c: ret
} // end of method UnsafeCode::PointerArithmeticLong3s
.method public hidebysig instance int32
PointerSubtraction(int64* p,
int64* q) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.8
IL_0004: div
IL_0005: conv.i8
IL_0006: conv.i4
IL_0007: ret
} // end of method UnsafeCode::PointerSubtraction
.method public hidebysig instance int64
PointerSubtractionLong(int64* p,
int64* q) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.8
IL_0004: div
IL_0005: conv.i8
IL_0006: ret
} // end of method UnsafeCode::PointerSubtractionLong
.method public hidebysig instance int32
PointerSubtraction2(int64* p,
int16* q) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.1
IL_0004: div
IL_0005: conv.i8
IL_0006: conv.i4
IL_0007: ret
} // end of method UnsafeCode::PointerSubtraction2
.method public hidebysig instance int32
PointerSubtraction3(void* p,
void* q) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.1
IL_0004: div
IL_0005: conv.i8
IL_0006: conv.i4
IL_0007: ret
} // end of method UnsafeCode::PointerSubtraction3
.method public hidebysig instance int64
PointerSubtraction4(int8* p,
int8* q) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.1
IL_0004: div
IL_0005: conv.i8
IL_0006: ret
} // end of method UnsafeCode::PointerSubtraction4
.method public hidebysig instance int64
PointerSubtraction5(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* q) cil managed
{
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0009: div
IL_000a: conv.i8
IL_000b: ret
} // end of method UnsafeCode::PointerSubtraction5
.method public hidebysig instance float64
FixedMemberAccess(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers* m,
int32 i) cil managed
{
// Code size 39 (0x27)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Integers>e__FixedBuffer0' ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers::Integers
IL_0006: ldflda int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Integers>e__FixedBuffer0'::FixedElementField
IL_000b: conv.u
IL_000c: ldarg.2
IL_000d: conv.i
IL_000e: ldc.i4.4
IL_000f: mul
IL_0010: add
IL_0011: ldind.i4
IL_0012: conv.r8
IL_0013: ldarg.1
IL_0014: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer1' ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers::Doubles
IL_0019: ldflda float64 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer1'::FixedElementField
IL_001e: conv.u
IL_001f: ldarg.2
IL_0020: conv.i
IL_0021: ldc.i4.8
IL_0022: mul
IL_0023: add
IL_0024: ldind.r8
IL_0025: add
IL_0026: ret
} // end of method UnsafeCode::FixedMemberAccess
.method public hidebysig instance float64*
FixedMemberBasePointer(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers* m) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer1' ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers::Doubles
IL_0006: ldflda float64 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer1'::FixedElementField
IL_000b: conv.u
IL_000c: ret
} // end of method UnsafeCode::FixedMemberBasePointer
.method public hidebysig instance string
UsePointer(float64* ptr) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call instance string [mscorlib]System.Double::ToString()
IL_0006: ret
} // end of method UnsafeCode::UsePointer
.method public hidebysig instance string
StackAlloc(int32 count) cil managed
{
// Code size 52 (0x34)
.maxstack 3
.locals init (char* V_0,
char* V_1,
int32 V_2)
IL_0000: ldarg.1
IL_0001: conv.u
IL_0002: ldc.i4.2
IL_0003: mul.ovf.un
IL_0004: localloc
IL_0006: stloc.0
IL_0007: ldc.i4.s 100
IL_0009: conv.u
IL_000a: ldc.i4.2
IL_000b: mul.ovf.un
IL_000c: localloc
IL_000e: stloc.1
IL_000f: ldc.i4.0
IL_0010: stloc.2
IL_0011: br.s IL_0028
IL_0013: ldloc.0
IL_0014: ldloc.2
IL_0015: conv.i
IL_0016: ldc.i4.2
IL_0017: mul
IL_0018: add
IL_0019: ldloc.2
IL_001a: conv.u2
IL_001b: stind.i2
IL_001c: ldloc.1
IL_001d: ldloc.2
IL_001e: conv.i
IL_001f: ldc.i4.2
IL_0020: mul
IL_0021: add
IL_0022: ldc.i4.0
IL_0023: stind.i2
IL_0024: ldloc.2
IL_0025: ldc.i4.1
IL_0026: add
IL_0027: stloc.2
IL_0028: ldloc.2
IL_0029: ldarg.1
IL_002a: blt.s IL_0013
IL_002c: ldarg.0
IL_002d: ldloc.0
IL_002e: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UsePointer(float64*)
IL_0033: ret
} // end of method UnsafeCode::StackAlloc
.method public hidebysig instance string
StackAllocStruct(int32 count) cil managed
{
// Code size 41 (0x29)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* V_0)
IL_0000: ldarg.1
IL_0001: ldc.i4.2
IL_0002: mul.ovf
IL_0003: conv.u
IL_0004: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_000a: mul.ovf.un
IL_000b: localloc
IL_000d: stloc.0
IL_000e: ldc.i4.s 10
IL_0010: conv.u
IL_0011: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0017: mul.ovf.un
IL_0018: localloc
IL_001a: pop
IL_001b: ldarg.0
IL_001c: ldloc.0
IL_001d: ldflda float64 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct::Y
IL_0022: conv.u
IL_0023: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UsePointer(float64*)
IL_0028: ret
} // end of method UnsafeCode::StackAllocStruct
.method family hidebysig virtual instance void
Finalize() cil managed
{
// Code size 22 (0x16)
.maxstack 2
.try
{
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: call instance int32* ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::get_NullPointer()
IL_0007: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PassPointerAsRefParameter(int32*)
IL_000c: leave.s IL_0015
} // end .try
finally
{
IL_000e: ldarg.0
IL_000f: call instance void [mscorlib]System.Object::Finalize()
IL_0014: endfinally
} // end handler
IL_0015: ret
} // end of method UnsafeCode::Finalize
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method UnsafeCode::.ctor
.property instance int32* NullPointer()
{
.get instance int32* ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::get_NullPointer()
} // end of property UnsafeCode::NullPointer
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file ../../../TestCases/Pretty\UnsafeCode.opt.res

910
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.opt.roslyn.il

@ -0,0 +1,910 @@ @@ -0,0 +1,910 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly UnsafeCode
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module UnsafeCode.dll
// MVID: {958D637E-F39D-447B-A248-B73AECEC847A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x007C0000
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode
extends [mscorlib]System.Object
{
.class sequential ansi sealed nested public beforefieldinit SimpleStruct
extends [mscorlib]System.ValueType
{
.field public int32 X
.field public float64 Y
} // end of class SimpleStruct
.class sequential ansi sealed nested public beforefieldinit StructWithFixedSizeMembers
extends [mscorlib]System.ValueType
{
.class sequential ansi sealed nested public beforefieldinit '<Integers>e__FixedBuffer'
extends [mscorlib]System.ValueType
{
.pack 0
.size 400
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.UnsafeValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field public int32 FixedElementField
} // end of class '<Integers>e__FixedBuffer'
.class sequential ansi sealed nested public beforefieldinit '<Doubles>e__FixedBuffer'
extends [mscorlib]System.ValueType
{
.pack 0
.size 1600
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.UnsafeValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field public float64 FixedElementField
} // end of class '<Doubles>e__FixedBuffer'
.class sequential ansi sealed nested public beforefieldinit '<Old>e__FixedBuffer'
extends [mscorlib]System.ValueType
{
.pack 0
.size 1
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.UnsafeValueTypeAttribute::.ctor() = ( 01 00 00 00 )
.field public uint8 FixedElementField
} // end of class '<Old>e__FixedBuffer'
.field public valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Integers>e__FixedBuffer' Integers
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type,
int32) = ( 01 00 59 53 79 73 74 65 6D 2E 49 6E 74 33 32 2C // ..YSystem.Int32,
20 6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 69 // mscorlib, Versi
6F 6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C 74 // on=4.0.0.0, Cult
75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 // ure=neutral, Pub
6C 69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 61 // licKeyToken=b77a
35 63 35 36 31 39 33 34 65 30 38 39 64 00 00 00 // 5c561934e089d...
00 00 )
.field public int32 NormalMember
.field public valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer' Doubles
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type,
int32) = ( 01 00 5A 53 79 73 74 65 6D 2E 44 6F 75 62 6C 65 // ..ZSystem.Double
2C 20 6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 // , mscorlib, Vers
69 6F 6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C // ion=4.0.0.0, Cul
74 75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 // ture=neutral, Pu
62 6C 69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 // blicKeyToken=b77
61 35 63 35 36 31 39 33 34 65 30 38 39 C8 00 00 // a5c561934e089...
00 00 00 )
.field public valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Old>e__FixedBuffer' Old
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type,
int32) = ( 01 00 58 53 79 73 74 65 6D 2E 42 79 74 65 2C 20 // ..XSystem.Byte,
6D 73 63 6F 72 6C 69 62 2C 20 56 65 72 73 69 6F // mscorlib, Versio
6E 3D 34 2E 30 2E 30 2E 30 2C 20 43 75 6C 74 75 // n=4.0.0.0, Cultu
72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 6C // re=neutral, Publ
69 63 4B 65 79 54 6F 6B 65 6E 3D 62 37 37 61 35 // icKeyToken=b77a5
63 35 36 31 39 33 34 65 30 38 39 01 00 00 00 00 // c561934e089.....
00 )
.custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string) = ( 01 00 11 61 6E 6F 74 68 65 72 20 61 74 74 72 69 // ...another attri
62 75 74 65 00 00 ) // bute..
} // end of class StructWithFixedSizeMembers
.method public hidebysig specialname instance int32*
get_NullPointer() cil managed
{
// Code size 3 (0x3)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: conv.u
IL_0002: ret
} // end of method UnsafeCode::get_NullPointer
.method public hidebysig instance int32
SizeOf() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0006: ret
} // end of method UnsafeCode::SizeOf
.method private hidebysig static void UseBool(bool b) cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method UnsafeCode::UseBool
.method public hidebysig instance void
PointerComparison(int32* a,
float64* b) cil managed
{
// Code size 64 (0x40)
.maxstack 2
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ceq
IL_0004: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0009: ldarg.1
IL_000a: ldarg.2
IL_000b: ceq
IL_000d: ldc.i4.0
IL_000e: ceq
IL_0010: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0015: ldarg.1
IL_0016: ldarg.2
IL_0017: clt.un
IL_0019: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_001e: ldarg.1
IL_001f: ldarg.2
IL_0020: cgt.un
IL_0022: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0027: ldarg.1
IL_0028: ldarg.2
IL_0029: cgt.un
IL_002b: ldc.i4.0
IL_002c: ceq
IL_002e: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0033: ldarg.1
IL_0034: ldarg.2
IL_0035: clt.un
IL_0037: ldc.i4.0
IL_0038: ceq
IL_003a: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_003f: ret
} // end of method UnsafeCode::PointerComparison
.method public hidebysig instance void
PointerComparisonWithNull(int32* a) cil managed
{
// Code size 24 (0x18)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: conv.u
IL_0003: ceq
IL_0005: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_000a: ldarg.1
IL_000b: ldc.i4.0
IL_000c: conv.u
IL_000d: ceq
IL_000f: ldc.i4.0
IL_0010: ceq
IL_0012: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UseBool(bool)
IL_0017: ret
} // end of method UnsafeCode::PointerComparisonWithNull
.method public hidebysig instance int32*
PointerCast(int64* p) cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ret
} // end of method UnsafeCode::PointerCast
.method public hidebysig instance int64
ConvertDoubleToLong(float64 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.i8
IL_0004: ret
} // end of method UnsafeCode::ConvertDoubleToLong
.method public hidebysig instance float64
ConvertLongToDouble(int64 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.r8
IL_0004: ret
} // end of method UnsafeCode::ConvertLongToDouble
.method public hidebysig instance int32
ConvertFloatToInt(float32 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.i4
IL_0004: ret
} // end of method UnsafeCode::ConvertFloatToInt
.method public hidebysig instance float32
ConvertIntToFloat(int32 d) cil managed
{
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarga.s d
IL_0002: conv.u
IL_0003: ldind.r4
IL_0004: ret
} // end of method UnsafeCode::ConvertIntToFloat
.method public hidebysig instance int32
PointerCasts() cil managed
{
// Code size 20 (0x14)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: conv.u
IL_0005: ldc.r4 0.5
IL_000a: stind.r4
IL_000b: ldloca.s V_0
IL_000d: conv.u
IL_000e: ldc.i4.3
IL_000f: add
IL_0010: ldc.i4.3
IL_0011: stind.i1
IL_0012: ldloc.0
IL_0013: ret
} // end of method UnsafeCode::PointerCasts
.method public hidebysig instance void
PassRefParameterAsPointer(int32& p) cil managed
{
// Code size 14 (0xe)
.maxstack 2
.locals init (int32& pinned V_0)
IL_0000: ldarg.1
IL_0001: stloc.0
IL_0002: ldarg.0
IL_0003: ldloc.0
IL_0004: conv.i
IL_0005: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PassPointerAsRefParameter(int32*)
IL_000a: ldc.i4.0
IL_000b: conv.u
IL_000c: stloc.0
IL_000d: ret
} // end of method UnsafeCode::PassRefParameterAsPointer
.method public hidebysig instance void
PassPointerAsRefParameter(int32* p) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PassRefParameterAsPointer(int32&)
IL_0007: ret
} // end of method UnsafeCode::PassPointerAsRefParameter
.method public hidebysig instance void
AddressInMultiDimensionalArray(float64[0...,0...] matrix) cil managed
{
// Code size 31 (0x1f)
.maxstack 3
.locals init (float64& pinned V_0)
IL_0000: ldarg.1
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: call instance float64& float64[0...,0...]::Address(int32,
int32)
IL_0008: stloc.0
IL_0009: ldarg.0
IL_000a: ldloc.0
IL_000b: conv.i
IL_000c: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PointerReferenceExpression(float64*)
IL_0011: pop
IL_0012: ldarg.0
IL_0013: ldloc.0
IL_0014: conv.i
IL_0015: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PointerReferenceExpression(float64*)
IL_001a: pop
IL_001b: ldc.i4.0
IL_001c: conv.u
IL_001d: stloc.0
IL_001e: ret
} // end of method UnsafeCode::AddressInMultiDimensionalArray
.method public hidebysig instance void
FixedStringAccess(string text) cil managed
{
// Code size 37 (0x25)
.maxstack 2
.locals init (char* V_0,
string pinned V_1,
char* V_2)
IL_0000: ldarg.1
IL_0001: stloc.1
IL_0002: ldloc.1
IL_0003: conv.i
IL_0004: stloc.0
IL_0005: ldloc.0
IL_0006: brfalse.s IL_0010
IL_0008: ldloc.0
IL_0009: call int32 [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_000e: add
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: stloc.2
IL_0012: br.s IL_001c
IL_0014: ldloc.2
IL_0015: ldc.i4.s 65
IL_0017: stind.i2
IL_0018: ldloc.2
IL_0019: ldc.i4.2
IL_001a: add
IL_001b: stloc.2
IL_001c: ldloc.2
IL_001d: ldind.u2
IL_001e: ldc.i4.s 97
IL_0020: beq.s IL_0014
IL_0022: ldnull
IL_0023: stloc.1
IL_0024: ret
} // end of method UnsafeCode::FixedStringAccess
.method public hidebysig instance void
PutDoubleIntoLongArray1(int64[] 'array',
int32 index,
float64 val) cil managed
{
// Code size 36 (0x24)
.maxstack 3
.locals init (int64& pinned V_0,
int64[] V_1)
IL_0000: ldarg.1
IL_0001: dup
IL_0002: stloc.1
IL_0003: brfalse.s IL_000a
IL_0005: ldloc.1
IL_0006: ldlen
IL_0007: conv.i4
IL_0008: brtrue.s IL_000f
IL_000a: ldc.i4.0
IL_000b: conv.u
IL_000c: stloc.0
IL_000d: br.s IL_0017
IL_000f: ldloc.1
IL_0010: ldc.i4.0
IL_0011: ldelema [mscorlib]System.Int64
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: conv.i
IL_0019: ldarg.2
IL_001a: conv.i
IL_001b: ldc.i4.8
IL_001c: mul
IL_001d: add
IL_001e: ldarg.3
IL_001f: stind.r8
IL_0020: ldc.i4.0
IL_0021: conv.u
IL_0022: stloc.0
IL_0023: ret
} // end of method UnsafeCode::PutDoubleIntoLongArray1
.method public hidebysig instance void
PutDoubleIntoLongArray2(int64[] 'array',
int32 index,
float64 val) cil managed
{
// Code size 16 (0x10)
.maxstack 2
.locals init (int64& pinned V_0)
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ldelema [mscorlib]System.Int64
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: conv.i
IL_000a: ldarg.3
IL_000b: stind.r8
IL_000c: ldc.i4.0
IL_000d: conv.u
IL_000e: stloc.0
IL_000f: ret
} // end of method UnsafeCode::PutDoubleIntoLongArray2
.method public hidebysig instance string
PointerReferenceExpression(float64* d) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call instance string [mscorlib]System.Double::ToString()
IL_0006: ret
} // end of method UnsafeCode::PointerReferenceExpression
.method public hidebysig instance string
PointerReferenceExpression2(int64 addr) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: conv.u
IL_0002: call instance string [mscorlib]System.Int32::ToString()
IL_0007: ret
} // end of method UnsafeCode::PointerReferenceExpression2
.method public hidebysig instance int32*
PointerArithmetic(int32* p) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.2
IL_0002: conv.i
IL_0003: ldc.i4.4
IL_0004: mul
IL_0005: add
IL_0006: ret
} // end of method UnsafeCode::PointerArithmetic
.method public hidebysig instance int64*
PointerArithmetic2(int64* p) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldc.i4.3
IL_0001: conv.i
IL_0002: ldc.i4.8
IL_0003: mul
IL_0004: ldarg.1
IL_0005: add
IL_0006: ret
} // end of method UnsafeCode::PointerArithmetic2
.method public hidebysig instance int64*
PointerArithmetic3(int64* p) cil managed
{
// Code size 4 (0x4)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.3
IL_0002: add
IL_0003: ret
} // end of method UnsafeCode::PointerArithmetic3
.method public hidebysig instance int64*
PointerArithmetic4(void* p) cil managed
{
// Code size 4 (0x4)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.3
IL_0002: add
IL_0003: ret
} // end of method UnsafeCode::PointerArithmetic4
.method public hidebysig instance int32
PointerArithmetic5(void* p,
uint8* q,
int32 i) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.2
IL_0001: ldarg.3
IL_0002: add
IL_0003: ldind.u1
IL_0004: ldarg.1
IL_0005: ldind.u1
IL_0006: add
IL_0007: ret
} // end of method UnsafeCode::PointerArithmetic5
.method public hidebysig instance int32
PointerArithmetic6(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int32 i) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: conv.i
IL_0003: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0009: mul
IL_000a: add
IL_000b: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct::X
IL_0010: ret
} // end of method UnsafeCode::PointerArithmetic6
.method public hidebysig instance int32*
PointerArithmeticLong1(int32* p,
int64 offset) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ldc.i4.4
IL_0003: conv.i8
IL_0004: mul
IL_0005: conv.i
IL_0006: add
IL_0007: ret
} // end of method UnsafeCode::PointerArithmeticLong1
.method public hidebysig instance int32*
PointerArithmeticLong2(int32* p,
int64 offset) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.2
IL_0001: ldc.i4.4
IL_0002: conv.i8
IL_0003: mul
IL_0004: conv.i
IL_0005: ldarg.1
IL_0006: add
IL_0007: ret
} // end of method UnsafeCode::PointerArithmeticLong2
.method public hidebysig instance int32*
PointerArithmeticLong3(int32* p,
int64 offset) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: ldc.i4.4
IL_0003: conv.i8
IL_0004: mul
IL_0005: conv.i
IL_0006: sub
IL_0007: ret
} // end of method UnsafeCode::PointerArithmeticLong3
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct*
PointerArithmeticLong1s(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int64 offset) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0008: conv.i8
IL_0009: mul
IL_000a: conv.i
IL_000b: add
IL_000c: ret
} // end of method UnsafeCode::PointerArithmeticLong1s
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct*
PointerArithmeticLong2s(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int64 offset) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.2
IL_0001: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0007: conv.i8
IL_0008: mul
IL_0009: conv.i
IL_000a: ldarg.1
IL_000b: add
IL_000c: ret
} // end of method UnsafeCode::PointerArithmeticLong2s
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct*
PointerArithmeticLong3s(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
int64 offset) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0008: conv.i8
IL_0009: mul
IL_000a: conv.i
IL_000b: sub
IL_000c: ret
} // end of method UnsafeCode::PointerArithmeticLong3s
.method public hidebysig instance int32
PointerSubtraction(int64* p,
int64* q) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.8
IL_0004: div
IL_0005: conv.i8
IL_0006: conv.i4
IL_0007: ret
} // end of method UnsafeCode::PointerSubtraction
.method public hidebysig instance int64
PointerSubtractionLong(int64* p,
int64* q) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.8
IL_0004: div
IL_0005: conv.i8
IL_0006: ret
} // end of method UnsafeCode::PointerSubtractionLong
.method public hidebysig instance int32
PointerSubtraction2(int64* p,
int16* q) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.1
IL_0004: div
IL_0005: conv.i8
IL_0006: conv.i4
IL_0007: ret
} // end of method UnsafeCode::PointerSubtraction2
.method public hidebysig instance int32
PointerSubtraction3(void* p,
void* q) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.1
IL_0004: div
IL_0005: conv.i8
IL_0006: conv.i4
IL_0007: ret
} // end of method UnsafeCode::PointerSubtraction3
.method public hidebysig instance int64
PointerSubtraction4(int8* p,
int8* q) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: ldc.i4.1
IL_0004: div
IL_0005: conv.i8
IL_0006: ret
} // end of method UnsafeCode::PointerSubtraction4
.method public hidebysig instance int64
PointerSubtraction5(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* p,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* q) cil managed
{
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: sub
IL_0003: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0009: div
IL_000a: conv.i8
IL_000b: ret
} // end of method UnsafeCode::PointerSubtraction5
.method public hidebysig instance float64
FixedMemberAccess(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers* m,
int32 i) cil managed
{
// Code size 39 (0x27)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Integers>e__FixedBuffer' ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers::Integers
IL_0006: ldflda int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Integers>e__FixedBuffer'::FixedElementField
IL_000b: conv.u
IL_000c: ldarg.2
IL_000d: conv.i
IL_000e: ldc.i4.4
IL_000f: mul
IL_0010: add
IL_0011: ldind.i4
IL_0012: conv.r8
IL_0013: ldarg.1
IL_0014: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer' ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers::Doubles
IL_0019: ldflda float64 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer'::FixedElementField
IL_001e: conv.u
IL_001f: ldarg.2
IL_0020: conv.i
IL_0021: ldc.i4.8
IL_0022: mul
IL_0023: add
IL_0024: ldind.r8
IL_0025: add
IL_0026: ret
} // end of method UnsafeCode::FixedMemberAccess
.method public hidebysig instance float64*
FixedMemberBasePointer(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers* m) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer' ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers::Doubles
IL_0006: ldflda float64 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/StructWithFixedSizeMembers/'<Doubles>e__FixedBuffer'::FixedElementField
IL_000b: conv.u
IL_000c: ret
} // end of method UnsafeCode::FixedMemberBasePointer
.method public hidebysig instance string
UsePointer(float64* ptr) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call instance string [mscorlib]System.Double::ToString()
IL_0006: ret
} // end of method UnsafeCode::UsePointer
.method public hidebysig instance string
StackAlloc(int32 count) cil managed
{
// Code size 52 (0x34)
.maxstack 3
.locals init (char* V_0,
char* V_1,
int32 V_2)
IL_0000: ldarg.1
IL_0001: conv.u
IL_0002: ldc.i4.2
IL_0003: mul.ovf.un
IL_0004: localloc
IL_0006: stloc.0
IL_0007: ldc.i4.s 100
IL_0009: conv.u
IL_000a: ldc.i4.2
IL_000b: mul.ovf.un
IL_000c: localloc
IL_000e: stloc.1
IL_000f: ldc.i4.0
IL_0010: stloc.2
IL_0011: br.s IL_0028
IL_0013: ldloc.0
IL_0014: ldloc.2
IL_0015: conv.i
IL_0016: ldc.i4.2
IL_0017: mul
IL_0018: add
IL_0019: ldloc.2
IL_001a: conv.u2
IL_001b: stind.i2
IL_001c: ldloc.1
IL_001d: ldloc.2
IL_001e: conv.i
IL_001f: ldc.i4.2
IL_0020: mul
IL_0021: add
IL_0022: ldc.i4.0
IL_0023: stind.i2
IL_0024: ldloc.2
IL_0025: ldc.i4.1
IL_0026: add
IL_0027: stloc.2
IL_0028: ldloc.2
IL_0029: ldarg.1
IL_002a: blt.s IL_0013
IL_002c: ldarg.0
IL_002d: ldloc.0
IL_002e: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UsePointer(float64*)
IL_0033: ret
} // end of method UnsafeCode::StackAlloc
.method public hidebysig instance string
StackAllocStruct(int32 count) cil managed
{
// Code size 41 (0x29)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct* V_0)
IL_0000: ldarg.1
IL_0001: ldc.i4.2
IL_0002: mul.ovf
IL_0003: conv.u
IL_0004: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_000a: mul.ovf.un
IL_000b: localloc
IL_000d: stloc.0
IL_000e: ldc.i4.s 10
IL_0010: conv.u
IL_0011: sizeof ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct
IL_0017: mul.ovf.un
IL_0018: localloc
IL_001a: pop
IL_001b: ldarg.0
IL_001c: ldloc.0
IL_001d: ldflda float64 ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode/SimpleStruct::Y
IL_0022: conv.u
IL_0023: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::UsePointer(float64*)
IL_0028: ret
} // end of method UnsafeCode::StackAllocStruct
.method family hidebysig virtual instance void
Finalize() cil managed
{
.override [mscorlib]System.Object::Finalize
// Code size 22 (0x16)
.maxstack 2
.try
{
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: call instance int32* ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::get_NullPointer()
IL_0007: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::PassPointerAsRefParameter(int32*)
IL_000c: leave.s IL_0015
} // end .try
finally
{
IL_000e: ldarg.0
IL_000f: call instance void [mscorlib]System.Object::Finalize()
IL_0014: endfinally
} // end handler
IL_0015: ret
} // end of method UnsafeCode::Finalize
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method UnsafeCode::.ctor
.property instance int32* NullPointer()
{
.get instance int32* ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode::get_NullPointer()
} // end of property UnsafeCode::NullPointer
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.UnsafeCode
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

1155
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.roslyn.il

File diff suppressed because it is too large Load Diff

45
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -30,6 +30,7 @@ using ICSharpCode.Decompiler.IL; @@ -30,6 +30,7 @@ using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.ControlFlow;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.Util;
using System.IO;
@ -207,6 +208,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -207,6 +208,8 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
if (settings.AsyncAwait && AsyncAwaitDecompiler.IsCompilerGeneratedStateMachine(type))
return true;
if (settings.FixedBuffers && type.Name.StartsWith("<", StringComparison.Ordinal) && type.Name.Contains("__FixedBuffer"))
return true;
} else if (type.IsCompilerGenerated()) {
if (type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
return true;
@ -822,9 +825,37 @@ namespace ICSharpCode.Decompiler.CSharp @@ -822,9 +825,37 @@ namespace ICSharpCode.Decompiler.CSharp
}
var fieldDecl = typeSystemAstBuilder.ConvertEntity(field);
SetNewModifier(fieldDecl);
if (settings.FixedBuffers && IsFixedField(field, out var elementType, out var elementCount)) {
var fixedFieldDecl = new FixedFieldDeclaration();
fieldDecl.Attributes.MoveTo(fixedFieldDecl.Attributes);
fixedFieldDecl.Modifiers = fieldDecl.Modifiers;
fixedFieldDecl.ReturnType = typeSystemAstBuilder.ConvertType(elementType);
fixedFieldDecl.Variables.Add(new FixedVariableInitializer(field.Name, new PrimitiveExpression(elementCount)));
fixedFieldDecl.Variables.Single().CopyAnnotationsFrom(((FieldDeclaration)fieldDecl).Variables.Single());
fixedFieldDecl.CopyAnnotationsFrom(fieldDecl);
RemoveAttribute(fixedFieldDecl, fixedBufferAttributeTypeName);
return fixedFieldDecl;
}
return fieldDecl;
}
static readonly FullTypeName fixedBufferAttributeTypeName = new TopLevelTypeName("System.Runtime.CompilerServices", "FixedBufferAttribute");
internal static bool IsFixedField(IField field, out IType type, out int elementCount)
{
type = null;
elementCount = 0;
IAttribute attr = field.GetAttribute(fixedBufferAttributeTypeName, inherit: false);
if (attr != null && attr.PositionalArguments.Count == 2) {
if (attr.PositionalArguments[0] is TypeOfResolveResult trr && attr.PositionalArguments[1].ConstantValue is int length) {
type = trr.ReferencedType;
elementCount = length;
return true;
}
}
return false;
}
EntityDeclaration DoDecompile(PropertyDefinition propertyDefinition, IProperty property, ITypeResolveContext decompilationContext)
{
Debug.Assert(decompilationContext.CurrentMember == property);
@ -937,11 +968,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -937,11 +968,11 @@ namespace ICSharpCode.Decompiler.CSharp
string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
AstType memberType;
if ((options & (ConvertTypeOptions.IncludeOuterTypeName | ConvertTypeOptions.IncludeNamespace)) != 0) {
AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
memberType = new MemberType { Target = typeRef, MemberName = namepart };
if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
AddTypeParameterDefininitionsTo(type, memberType);
}
if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
AddTypeParameterDefininitionsTo(type, memberType);
}
} else {
memberType = new SimpleType(namepart);
if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
@ -1054,9 +1085,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1054,9 +1085,9 @@ namespace ICSharpCode.Decompiler.CSharp
typeParameterCount = typeArguments.Count;
st.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount));
} else {
st.TypeArguments.AddRange(typeArguments);
st.TypeArguments.AddRange(typeArguments);
}
}
}
MemberType mt = baseType as MemberType;
if (mt != null) {
@ -1106,7 +1137,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1106,7 +1137,7 @@ namespace ICSharpCode.Decompiler.CSharp
SequencePointBuilder spb = new SequencePointBuilder();
syntaxTree.AcceptVisitor(spb);
return spb.GetSequencePoints();
}
}
#endregion
}

420
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -229,55 +229,38 @@ namespace ICSharpCode.Decompiler.CSharp @@ -229,55 +229,38 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLocAlloc(LocAlloc inst, TranslationContext context)
{
IType elementType;
TranslatedExpression countExpression = TranslatePointerArgument(inst.Argument, context, out elementType);
TranslatedExpression countExpression;
PointerType pointerType;
if (inst.Argument.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out var left, out var right)
&& right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchSizeOf(out var elementType))
{
// Determine the element type from the sizeof
countExpression = Translate(left.UnwrapConv(ConversionKind.ZeroExtend));
pointerType = new PointerType(elementType);
} else {
// Determine the element type from the expected pointer type in this context
pointerType = context.TypeHint as PointerType;
if (pointerType != null && GetPointerArithmeticOffset(
inst.Argument, Translate(inst.Argument),
pointerType, checkForOverflow: true,
unwrapZeroExtension: true
) is TranslatedExpression offset)
{
countExpression = offset;
elementType = pointerType.ElementType;
} else {
elementType = compilation.FindType(KnownTypeCode.Byte);
pointerType = new PointerType(elementType);
countExpression = Translate(inst.Argument);
}
}
countExpression = countExpression.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
if (elementType == null)
elementType = compilation.FindType(KnownTypeCode.Byte);
return new StackAllocExpression {
Type = ConvertType(elementType),
CountExpression = countExpression
}.WithILInstruction(inst).WithRR(new ResolveResult(new PointerType(elementType)));
}
/// <summary>
/// Translate the argument of an operation that deals with pointers:
/// * undoes the implicit multiplication with `sizeof(elementType)` and returns `elementType`
/// * on failure, translates the whole expression and returns `elementType = null`.
/// </summary>
TranslatedExpression TranslatePointerArgument(ILInstruction countExpr, TranslationContext context, out IType elementType)
{
ILInstruction left;
ILInstruction right;
if (countExpr.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out left, out right)
&& right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchSizeOf(out elementType))
{
return Translate(left);
}
var pointerTypeHint = context.TypeHint as PointerType;
if (pointerTypeHint == null) {
elementType = null;
return Translate(countExpr);
}
ResolveResult sizeofRR = resolver.ResolveSizeOf(pointerTypeHint.ElementType);
if (!(sizeofRR.IsCompileTimeConstant && sizeofRR.ConstantValue is int)) {
elementType = null;
return Translate(countExpr);
}
int typeSize = (int)sizeofRR.ConstantValue;
if (countExpr.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out left, out right)
&& right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchLdcI4(typeSize))
{
elementType = pointerTypeHint.ElementType;
return Translate(left);
}
elementType = null;
return Translate(countExpr);
}
protected internal override TranslatedExpression VisitLdcI4(LdcI4 inst, TranslationContext context)
{
return new PrimitiveExpression(inst.Value)
@ -494,6 +477,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -494,6 +477,20 @@ namespace ICSharpCode.Decompiler.CSharp
return right;
}
}
// Handle comparisons between unsafe pointers and null:
if (left.Type.Kind == TypeKind.Pointer && inst.Right.MatchLdcI(0)) {
negateOutput = false;
right = new NullReferenceExpression().WithRR(new ConstantResolveResult(SpecialType.NullType, null))
.WithILInstruction(inst.Right);
return CreateBuiltinBinaryOperator(left, inst.Kind.ToBinaryOperatorType(), right)
.WithILInstruction(inst);
} else if (right.Type.Kind == TypeKind.Pointer && inst.Left.MatchLdcI(0)) {
negateOutput = false;
left = new NullReferenceExpression().WithRR(new ConstantResolveResult(SpecialType.NullType, null))
.WithILInstruction(inst.Left);
return CreateBuiltinBinaryOperator(left, inst.Kind.ToBinaryOperatorType(), right)
.WithILInstruction(inst);
}
// Special case comparisons with enum and char literals
left = AdjustConstantExpressionToType(left, right.Type);
@ -504,12 +501,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -504,12 +501,8 @@ namespace ICSharpCode.Decompiler.CSharp
{
// When comparing a delegate with null, the C# compiler generates a reference comparison.
negateOutput = false;
return new BinaryOperatorExpression(left.Expression, inst.Kind.ToBinaryOperatorType(), right.Expression)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(
compilation.FindType(KnownTypeCode.Boolean),
inst.Kind == ComparisonKind.Equality ? ExpressionType.Equal : ExpressionType.NotEqual,
left.ResolveResult, right.ResolveResult));
return CreateBuiltinBinaryOperator(left, inst.Kind.ToBinaryOperatorType(), right)
.WithILInstruction(inst);
}
var rr = resolver.ResolveBinaryOperator(inst.Kind.ToBinaryOperatorType(), left.ResolveResult, right.ResolveResult)
@ -521,7 +514,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -521,7 +514,15 @@ namespace ICSharpCode.Decompiler.CSharp
if (inst.InputType == StackType.O) {
targetType = compilation.FindType(KnownTypeCode.Object);
} else {
targetType = TypeUtils.GetLargerType(NullableType.GetUnderlyingType(left.Type), NullableType.GetUnderlyingType(right.Type));
var leftUType = NullableType.GetUnderlyingType(left.Type);
var rightUType = NullableType.GetUnderlyingType(right.Type);
if (leftUType.GetStackType() == inst.InputType && !leftUType.IsSmallIntegerType()) {
targetType = leftUType;
} else if (rightUType.GetStackType() == inst.InputType && !rightUType.IsSmallIntegerType()) {
targetType = rightUType;
} else {
targetType = compilation.FindType(inst.InputType.ToKnownTypeCode(leftUType.GetSign()));
}
}
if (inst.IsLifted) {
targetType = NullableType.Create(compilation, targetType);
@ -539,9 +540,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -539,9 +540,10 @@ namespace ICSharpCode.Decompiler.CSharp
// If converting one input wasn't sufficient, convert both:
left = left.ConvertTo(targetType, this);
right = right.ConvertTo(targetType, this);
rr = new OperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean),
BinaryOperatorExpression.GetLinqNodeType(BinaryOperatorType.Equality, false),
left.ResolveResult, right.ResolveResult);
rr = new OperatorResolveResult(
compilation.FindType(KnownTypeCode.Boolean),
BinaryOperatorExpression.GetLinqNodeType(inst.Kind.ToBinaryOperatorType(), false),
left.ResolveResult, right.ResolveResult);
}
}
negateOutput = false;
@ -549,6 +551,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -549,6 +551,17 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(inst)
.WithRR(rr);
}
ExpressionWithResolveResult CreateBuiltinBinaryOperator(
TranslatedExpression left, BinaryOperatorType type, TranslatedExpression right,
bool checkForOverflow = false)
{
return new BinaryOperatorExpression(left.Expression, type, right.Expression)
.WithRR(new OperatorResolveResult(
compilation.FindType(KnownTypeCode.Boolean),
BinaryOperatorExpression.GetLinqNodeType(type, checkForOverflow),
left.ResolveResult, right.ResolveResult));
}
/// <summary>
/// Handle Comp instruction, operators other than equality/inequality.
@ -558,6 +571,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -558,6 +571,12 @@ namespace ICSharpCode.Decompiler.CSharp
var op = inst.Kind.ToBinaryOperatorType();
var left = Translate(inst.Left);
var right = Translate(inst.Right);
if (left.Type.Kind == TypeKind.Pointer && right.Type.Kind == TypeKind.Pointer) {
return CreateBuiltinBinaryOperator(left, op, right)
.WithILInstruction(inst);
}
left = PrepareArithmeticArgument(left, inst.InputType, inst.Sign, inst.IsLifted);
right = PrepareArithmeticArgument(right, inst.InputType, inst.Sign, inst.IsLifted);
@ -652,7 +671,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -652,7 +671,8 @@ namespace ICSharpCode.Decompiler.CSharp
case BinaryNumericOperator.Mul:
return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply);
case BinaryNumericOperator.Div:
return HandleBinaryNumeric(inst, BinaryOperatorType.Divide);
return HandlePointerSubtraction(inst)
?? HandleBinaryNumeric(inst, BinaryOperatorType.Divide);
case BinaryNumericOperator.Rem:
return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus);
case BinaryNumericOperator.BitAnd:
@ -669,15 +689,202 @@ namespace ICSharpCode.Decompiler.CSharp @@ -669,15 +689,202 @@ namespace ICSharpCode.Decompiler.CSharp
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// Translates pointer arithmetic:
/// ptr + int
/// int + ptr
/// ptr - int
/// Returns null if 'inst' is not performing pointer arithmetic.
/// This function not handle 'ptr - ptr'!
/// </summary>
TranslatedExpression? HandlePointerArithmetic(BinaryNumericInstruction inst, TranslatedExpression left, TranslatedExpression right)
{
if (!(inst.Operator == BinaryNumericOperator.Add || inst.Operator == BinaryNumericOperator.Sub))
return null;
if (inst.CheckForOverflow || inst.IsLifted)
return null;
if (!(inst.LeftInputType == StackType.I && inst.RightInputType == StackType.I))
return null;
PointerType pointerType;
ILInstruction byteOffsetInst;
TranslatedExpression byteOffsetExpr;
if (left.Type.Kind == TypeKind.Pointer) {
byteOffsetInst = inst.Right;
byteOffsetExpr = right;
pointerType = (PointerType)left.Type;
} else if (right.Type.Kind == TypeKind.Pointer) {
if (inst.Operator != BinaryNumericOperator.Add)
return null;
byteOffsetInst = inst.Left;
byteOffsetExpr = left;
pointerType = (PointerType)right.Type;
} else {
return null;
}
TranslatedExpression offsetExpr = GetPointerArithmeticOffset(byteOffsetInst, byteOffsetExpr, pointerType, inst.CheckForOverflow)
?? FallBackToBytePointer();
if (!offsetExpr.Type.IsCSharpPrimitiveIntegerType()) {
// pointer arithmetic accepts all primitive integer types, but no enums etc.
StackType targetType = offsetExpr.Type.GetStackType() == StackType.I4 ? StackType.I4 : StackType.I8;
offsetExpr = offsetExpr.ConvertTo(
compilation.FindType(targetType.ToKnownTypeCode(offsetExpr.Type.GetSign())),
this);
}
if (left.Type.Kind == TypeKind.Pointer) {
Debug.Assert(inst.Operator == BinaryNumericOperator.Add || inst.Operator == BinaryNumericOperator.Sub);
left = left.ConvertTo(pointerType, this);
right = offsetExpr;
} else {
Debug.Assert(inst.Operator == BinaryNumericOperator.Add);
Debug.Assert(right.Type.Kind == TypeKind.Pointer);
left = offsetExpr;
right = right.ConvertTo(pointerType, this);
}
var operatorType = inst.Operator == BinaryNumericOperator.Add ? BinaryOperatorType.Add : BinaryOperatorType.Subtract;
return new BinaryOperatorExpression(left, operatorType, right)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(
pointerType, BinaryOperatorExpression.GetLinqNodeType(operatorType, inst.CheckForOverflow),
left.ResolveResult, right.ResolveResult));
TranslatedExpression FallBackToBytePointer()
{
pointerType = new PointerType(compilation.FindType(KnownTypeCode.Byte));
return byteOffsetExpr;
}
}
TranslatedExpression? GetPointerArithmeticOffset(ILInstruction byteOffsetInst, TranslatedExpression byteOffsetExpr,
PointerType pointerType, bool checkForOverflow, bool unwrapZeroExtension = false)
{
if (byteOffsetInst is Conv conv && conv.InputType == StackType.I8 && conv.ResultType == StackType.I) {
byteOffsetInst = conv.Argument;
}
int? elementSize = ComputeSizeOf(pointerType.ElementType);
if (elementSize == 1) {
return byteOffsetExpr;
} else if (byteOffsetInst is BinaryNumericInstruction mul && mul.Operator == BinaryNumericOperator.Mul) {
if (mul.CheckForOverflow != checkForOverflow)
return null;
if (mul.IsLifted)
return null;
if (elementSize > 0 && mul.Right.MatchLdcI(elementSize.Value)
|| mul.Right.UnwrapConv(ConversionKind.SignExtend) is SizeOf sizeOf && sizeOf.Type.Equals(pointerType.ElementType))
{
var countOffsetInst = mul.Left;
if (unwrapZeroExtension) {
countOffsetInst = countOffsetInst.UnwrapConv(ConversionKind.ZeroExtend);
}
return Translate(countOffsetInst);
}
} else if (byteOffsetInst.MatchLdcI(out long val)) {
// If the offset is a constant, it's possible that the compiler
// constant-folded the multiplication.
if (elementSize > 0 && (val % elementSize == 0) && val > 0) {
val /= elementSize.Value;
if (val <= int.MaxValue) {
return new PrimitiveExpression((int)val)
.WithILInstruction(byteOffsetInst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), val));
}
}
}
return null;
}
/// <summary>
/// Called for divisions, detect and handles the code pattern:
/// div(sub(a, b), sizeof(T))
/// when a,b are of type T*.
/// This is what the C# compiler generates for pointer subtraction.
/// </summary>
TranslatedExpression? HandlePointerSubtraction(BinaryNumericInstruction inst)
{
Debug.Assert(inst.Operator == BinaryNumericOperator.Div);
if (inst.CheckForOverflow || inst.LeftInputType != StackType.I)
return null;
if (!(inst.Left is BinaryNumericInstruction sub && sub.Operator == BinaryNumericOperator.Sub))
return null;
if (sub.CheckForOverflow)
return null;
// First, attempt to parse the 'sizeof' on the RHS
IType elementType;
if (inst.Right.MatchLdcI(out long elementSize)) {
elementType = null;
// OK, might be pointer subtraction if the element size matches
} else if (inst.Right.UnwrapConv(ConversionKind.SignExtend).MatchSizeOf(out elementType)) {
// OK, might be pointer subtraction if the element type matches
} else {
return null;
}
var left = Translate(sub.Left);
var right = Translate(sub.Right);
IType pointerType;
if (IsMatchingPointerType(left.Type)) {
pointerType = left.Type;
} else if (IsMatchingPointerType(right.Type)) {
pointerType = right.Type;
} else if (elementSize == 1 && left.Type.Kind == TypeKind.Pointer && right.Type.Kind == TypeKind.Pointer) {
// two pointers (neither matching), we're dividing by 1 (debug builds only),
// -> subtract two byte pointers
pointerType = new PointerType(compilation.FindType(KnownTypeCode.Byte));
} else {
// neither is a matching pointer type
// -> not a pointer subtraction after all
return null;
}
// We got a pointer subtraction.
left = left.ConvertTo(pointerType, this);
right = right.ConvertTo(pointerType, this);
var rr = new OperatorResolveResult(
compilation.FindType(KnownTypeCode.Int64),
ExpressionType.Subtract,
left.ResolveResult, right.ResolveResult
);
var result = new BinaryOperatorExpression(
left.Expression, BinaryOperatorType.Subtract, right.Expression
).WithILInstruction(new[] { inst, sub })
.WithRR(rr);
return result;
bool IsMatchingPointerType(IType type)
{
if (type is PointerType pt) {
if (elementType != null)
return elementType.Equals(pt.ElementType);
else if (elementSize > 0)
return ComputeSizeOf(pt.ElementType) == elementSize;
}
return false;
}
}
int? ComputeSizeOf(IType type)
{
var rr = resolver.ResolveSizeOf(type);
if (rr.IsCompileTimeConstant && rr.ConstantValue is int size)
return size;
else
return null;
}
TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op)
{
var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow);
var left = Translate(inst.Left);
var right = Translate(inst.Right);
if (left.Type.Kind == TypeKind.Pointer || right.Type.Kind == TypeKind.Pointer) {
var ptrResult = HandlePointerArithmetic(inst, left, right);
if (ptrResult != null)
return ptrResult.Value;
}
left = PrepareArithmeticArgument(left, inst.LeftInputType, inst.Sign, inst.IsLifted);
right = PrepareArithmeticArgument(right, inst.RightInputType, inst.Sign, inst.IsLifted);
if (op == BinaryOperatorType.Subtract && inst.Left.MatchLdcI(0)) {
IType rightUType = NullableType.GetUnderlyingType(right.Type);
if (rightUType.IsKnownType(KnownTypeCode.Int32) || rightUType.IsKnownType(KnownTypeCode.Int64) || rightUType.IsCSharpSmallIntegerType()) {
@ -731,6 +938,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -731,6 +938,7 @@ namespace ICSharpCode.Decompiler.CSharp
// If the argument is oversized (needs truncation to match stack size of its ILInstruction),
// perform the truncation now.
IType targetType = compilation.FindType(argStackType.ToKnownTypeCode(sign));
argUType = targetType;
if (isLifted)
targetType = NullableType.Create(compilation, targetType);
arg = arg.ConvertTo(targetType, this);
@ -979,7 +1187,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -979,7 +1187,7 @@ namespace ICSharpCode.Decompiler.CSharp
// We just need to ensure the input type before the conversion is signed.
// Also, if the argument was translated into an oversized C# type,
// we need to perform the truncatation to the input stack type.
if (inputType.GetSign() != Sign.Signed || inputType.GetSize() > inputStackType.GetSize()) {
if (inputType.GetSign() != Sign.Signed || ValueMightBeOversized(arg.ResolveResult, inputStackType)) {
// Note that an undersized C# type is handled just fine:
// If it is unsigned we'll zero-extend it to the width of the inputStackType here,
// and it is signed we just combine the two sign-extensions into a single sign-extending conversion.
@ -1035,12 +1243,48 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1035,12 +1243,48 @@ namespace ICSharpCode.Decompiler.CSharp
// Case 4 (left-over extension from implicit conversion) can also be handled by our caller.
return arg.WithILInstruction(inst);
}
default:
return arg.ConvertTo(GetType(inst.TargetType.ToKnownTypeCode()), this, inst.CheckForOverflow)
.WithILInstruction(inst);
default: {
// We need to convert to inst.TargetType, or to an equivalent type.
IType targetType;
if (inst.TargetType == NullableType.GetUnderlyingType(context.TypeHint).ToPrimitiveType()
&& NullableType.IsNullable(context.TypeHint) == inst.IsLifted)
{
targetType = context.TypeHint;
} else {
targetType = GetType(inst.TargetType.ToKnownTypeCode());
}
return arg.ConvertTo(targetType, this, inst.CheckForOverflow)
.WithILInstruction(inst);
}
}
}
/// <summary>
/// Gets whether the ResolveResult computes a value that might be oversized for the specified stack type.
/// </summary>
bool ValueMightBeOversized(ResolveResult rr, StackType stackType)
{
IType inputType = NullableType.GetUnderlyingType(rr.Type);
if (inputType.GetSize() <= stackType.GetSize()) {
// The input type is smaller or equal to the stack type,
// it can't be an oversized value.
return false;
}
if (rr is OperatorResolveResult orr) {
if (stackType == StackType.I && orr.OperatorType == ExpressionType.Subtract
&& orr.Operands.Count == 2
&& orr.Operands[0].Type.Kind == TypeKind.Pointer
&& orr.Operands[1].Type.Kind == TypeKind.Pointer)
{
// Even though a pointer subtraction produces a value of type long in C#,
// the value will always fit in a native int.
return false;
}
}
// We don't have any information about the value, so it might be oversized.
return true;
}
protected internal override TranslatedExpression VisitCall(Call inst, TranslationContext context)
{
return new CallBuilder(this, typeSystem, settings).Build(inst);
@ -1211,19 +1455,41 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1211,19 +1455,41 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdObj(LdObj inst, TranslationContext context)
{
var target = Translate(inst.Target);
if (target.Expression is DirectionExpression && TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can dereference the managed reference by stripping away the 'ref'
var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
if (TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
TranslatedExpression result;
if (target.Expression is DirectionExpression dirExpr) {
// we can dereference the managed reference by stripping away the 'ref'
result = target.UnwrapChild(dirExpr.Expression);
result.Expression.AddAnnotation(inst); // add LdObj in addition to the existing ILInstruction annotation
} else if (target.Type is PointerType pointerType) {
if (target.Expression is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.AddressOf) {
// We can dereference the pointer by stripping away the '&'
result = target.UnwrapChild(uoe.Expression);
result.Expression.AddAnnotation(inst); // add LdObj in addition to the existing ILInstruction annotation
} else {
// Dereference the existing pointer
result = new UnaryOperatorExpression(UnaryOperatorType.Dereference, target.Expression)
.WithILInstruction(inst)
.WithRR(new ResolveResult(pointerType.ElementType));
}
} else {
// reference type behind non-DirectionExpression?
// this case should be impossible, but we can use a pointer cast
// just to make sure
target = target.ConvertTo(new PointerType(inst.Type), this);
return new UnaryOperatorExpression(UnaryOperatorType.Dereference, target.Expression)
.WithILInstruction(inst)
.WithRR(new ResolveResult(inst.Type));
}
// we don't convert result to inst.Type, because the LdObj type
// might be inaccurate (it's often System.Object for all reference types),
// and our parent node should already insert casts where necessary
result.Expression.AddAnnotation(inst); // add LdObj in addition to the existing ILInstruction annotation
if (target.Type.IsSmallIntegerType() && inst.Type.IsSmallIntegerType() && target.Type.GetSign() != inst.Type.GetSign())
return result.ConvertTo(inst.Type, this);
return result;
} else {
// Cast pointer type if necessary:
// We need to cast the pointer type:
target = target.ConvertTo(new PointerType(inst.Type), this);
return new UnaryOperatorExpression(UnaryOperatorType.Dereference, target.Expression)
.WithILInstruction(inst)
@ -1270,14 +1536,30 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1270,14 +1536,30 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdFlda(LdFlda inst, TranslationContext context)
{
var expr = ConvertField(inst.Field, inst.Target);
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ResolveResult(new ByReferenceType(expr.Type)));
if (settings.FixedBuffers && inst.Field.Name == "FixedElementField"
&& inst.Target is LdFlda nestedLdFlda
&& CSharpDecompiler.IsFixedField(nestedLdFlda.Field, out var elementType, out _))
{
Expression result = ConvertField(nestedLdFlda.Field, nestedLdFlda.Target);
result.RemoveAnnotations<ResolveResult>();
return result.WithRR(new ResolveResult(new PointerType(elementType)))
.WithILInstruction(inst);
}
var expr = ConvertField(inst.Field, inst.Target).WithILInstruction(inst);
if (inst.ResultType == StackType.I) {
// ldflda producing native pointer
return new UnaryOperatorExpression(UnaryOperatorType.AddressOf, expr)
.WithoutILInstruction().WithRR(new ResolveResult(new PointerType(expr.Type)));
} else {
// ldflda producing managed pointer
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ResolveResult(new ByReferenceType(expr.Type)));
}
}
protected internal override TranslatedExpression VisitLdsFlda(LdsFlda inst, TranslationContext context)
{
var expr = ConvertField(inst.Field);
var expr = ConvertField(inst.Field).WithILInstruction(inst);
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ResolveResult(new ByReferenceType(expr.Type)));
}

29
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -16,17 +16,15 @@ @@ -16,17 +16,15 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
public class IntroduceUnsafeModifier : DepthFirstAstVisitor<bool>, IAstTransform
{
public static readonly object PointerArithmeticAnnotation = new PointerArithmetic();
sealed class PointerArithmetic {}
public void Run(AstNode compilationUnit, TransformContext context)
{
compilationUnit.AcceptVisitor(this);
@ -54,7 +52,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -54,7 +52,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
base.VisitPointerReferenceExpression(pointerReferenceExpression);
return true;
}
public override bool VisitSizeOfExpression(SizeOfExpression sizeOfExpression)
{
// C# sizeof(MyStruct) requires unsafe{}
// (not for sizeof(int), but that gets constant-folded and thus decompiled to 4)
base.VisitSizeOfExpression(sizeOfExpression);
return true;
}
public override bool VisitComposedType(ComposedType composedType)
{
if (composedType.PointerRank > 0)
@ -67,8 +73,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -67,8 +73,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
bool result = base.VisitUnaryOperatorExpression(unaryOperatorExpression);
if (unaryOperatorExpression.Operator == UnaryOperatorType.Dereference) {
BinaryOperatorExpression bop = unaryOperatorExpression.Expression as BinaryOperatorExpression;
if (bop != null && bop.Operator == BinaryOperatorType.Add && bop.Annotation<PointerArithmetic>() != null) {
var bop = unaryOperatorExpression.Expression as BinaryOperatorExpression;
if (bop != null && bop.Operator == BinaryOperatorType.Add
&& bop.GetResolveResult() is OperatorResolveResult orr
&& orr.Operands.FirstOrDefault()?.Type.Kind == TypeKind.Pointer)
{
// transform "*(ptr + int)" to "ptr[int]"
IndexerExpression indexer = new IndexerExpression();
indexer.Target = bop.Left.Detach();
@ -118,5 +127,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -118,5 +127,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
return result;
}
public override bool VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
{
base.VisitFixedVariableInitializer(fixedVariableInitializer);
return true;
}
}
}

9
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -78,7 +78,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -78,7 +78,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public FindRequiredImports(TransformContext context)
{
this.currentNamespace = context.DecompiledTypeDefinition != null ? context.DecompiledTypeDefinition.Namespace : string.Empty;
this.currentNamespace = context.DecompiledTypeDefinition?.Namespace ?? string.Empty;
}
bool IsParentOfCurrentNamespace(string ns)
@ -123,7 +123,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -123,7 +123,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public FullyQualifyAmbiguousTypeNamesVisitor(TransformContext context, UsingScope usingScope)
{
this.context = new Stack<CSharpTypeResolveContext>();
var currentContext = new CSharpTypeResolveContext(context.TypeSystem.MainAssembly, usingScope.Resolve(context.TypeSystem.Compilation));
if (!string.IsNullOrEmpty(context.DecompiledTypeDefinition?.Namespace)) {
foreach (string ns in context.DecompiledTypeDefinition.Namespace.Split('.')) {
usingScope = new UsingScope(usingScope, ns);
}
}
var currentContext = new CSharpTypeResolveContext(context.TypeSystem.MainAssembly, usingScope.Resolve(context.TypeSystem.Compilation), context.DecompiledTypeDefinition);
this.context.Push(currentContext);
this.astBuilder = CreateAstBuilder(currentContext);
}

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -103,6 +103,21 @@ namespace ICSharpCode.Decompiler @@ -103,6 +103,21 @@ namespace ICSharpCode.Decompiler
}
}
bool fixedBuffers = true;
/// <summary>
/// Decompile C# 1.0 'public unsafe fixed int arr[10];' members.
/// </summary>
public bool FixedBuffers {
get { return fixedBuffers; }
set {
if (fixedBuffers != value) {
fixedBuffers = value;
OnPropertyChanged();
}
}
}
bool liftNullables = true;
/// <summary>

2
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -337,6 +337,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -337,6 +337,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
new PointerType(((ByReferenceType)oldVar.Type).ElementType),
oldVar.Index);
newVar.Name = oldVar.Name;
newVar.HasGeneratedName = oldVar.HasGeneratedName;
oldVar.Function.Variables.Add(newVar);
ReplacePinnedVar(oldVar, newVar, pinnedRegion);
} else if (pinnedRegion.Variable.Type.IsKnownType(KnownTypeCode.String)) {
@ -383,6 +384,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -383,6 +384,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (nativeVar.Kind == VariableKind.Local) {
newVar = new ILVariable(VariableKind.PinnedLocal, nativeVar.Type, nativeVar.Index);
newVar.Name = nativeVar.Name;
newVar.HasGeneratedName = nativeVar.HasGeneratedName;
nativeVar.Function.Variables.Add(newVar);
ReplacePinnedVar(nativeVar, newVar, pinnedRegion);
} else {

2
ICSharpCode.Decompiler/IL/Instructions.cs

@ -3260,7 +3260,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3260,7 +3260,7 @@ namespace ICSharpCode.Decompiler.IL
readonly IField field;
/// <summary>Returns the field operand.</summary>
public IField Field { get { return field; } }
public override StackType ResultType { get { return StackType.Ref; } }
public override StackType ResultType { get { return target.ResultType.IsIntegerType() ? StackType.I : StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
return target.Flags | (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow);

3
ICSharpCode.Decompiler/IL/Instructions.tt

@ -192,7 +192,8 @@ @@ -192,7 +192,8 @@
SupportsVolatilePrefix, SupportsUnalignedPrefix, ResultType("Void")),
new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")),
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand,
ResultType("target.ResultType.IsIntegerType() ? StackType.I : StackType.Ref")),
new OpCode("ldsflda", "Load static field address",
CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand),

13
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.IL @@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.IL
}
/// <summary>
/// Matches either LdcI4 or LdcI8.
/// Matches ldc.i4, ldc.i8, and extending conversions.
/// </summary>
public bool MatchLdcI(out long val)
{
@ -43,6 +43,17 @@ namespace ICSharpCode.Decompiler.IL @@ -43,6 +43,17 @@ namespace ICSharpCode.Decompiler.IL
val = intVal;
return true;
}
if (this is Conv conv) {
if (conv.Kind == ConversionKind.SignExtend) {
return conv.Argument.MatchLdcI(out val);
} else if (conv.Kind == ConversionKind.ZeroExtend && conv.InputType == StackType.I4) {
if (conv.Argument.MatchLdcI(out val)) {
// clear top 32 bits
val &= uint.MaxValue;
return true;
}
}
}
return false;
}

13
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -226,14 +226,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -226,14 +226,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
switch (inst) {
case LdObj ldobj:
IField field;
if (ldobj.Target is LdFlda ldflda)
field = ldflda.Field;
else if (ldobj.Target is LdsFlda ldsflda)
field = ldsflda.Field;
else
break;
return CleanUpVariableName(field.Name);
return GetNameFromInstruction(ldobj.Target);
case LdFlda ldflda:
return CleanUpVariableName(ldflda.Field.Name);
case LdsFlda ldsflda:
return CleanUpVariableName(ldsflda.Field.Name);
case CallInstruction call:
if (call is NewObj) break;
IMethod m = call.Method;

23
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

@ -127,6 +127,28 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -127,6 +127,28 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
/// <summary>
/// Gets whether the type is a C# primitive integer type: byte, sbyte, short, ushort, int, uint, long and ulong.
///
/// Unlike the ILAst, C# does not consider bool, enums, pointers or IntPtr to be integers.
/// </summary>
public static bool IsCSharpPrimitiveIntegerType(this IType type)
{
switch (type.GetDefinition()?.KnownTypeCode) {
case KnownTypeCode.Byte:
case KnownTypeCode.SByte:
case KnownTypeCode.Int16:
case KnownTypeCode.UInt16:
case KnownTypeCode.Int32:
case KnownTypeCode.UInt32:
case KnownTypeCode.Int64:
case KnownTypeCode.UInt64:
return true;
default:
return false;
}
}
/// <summary>
/// Gets whether the type is an IL integer type.
/// Returns true for I4, I, or I8.
@ -282,6 +304,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -282,6 +304,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
case KnownTypeCode.Byte:
return PrimitiveType.U1;
case KnownTypeCode.UInt16:
case KnownTypeCode.Char:
return PrimitiveType.U2;
case KnownTypeCode.UInt32:
return PrimitiveType.U4;

Loading…
Cancel
Save