Browse Source

Introduce IType.IsByRefLike.

pull/1213/head
Daniel Grunwald 7 years ago
parent
commit
b149238777
  1. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.cs
  2. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.il
  3. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.opt.il
  4. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.opt.roslyn.il
  5. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.roslyn.il
  6. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  7. 52
      ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs
  8. 4
      ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs
  9. 5
      ICSharpCode.Decompiler/TypeSystem/IType.cs
  10. 4
      ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs
  11. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs
  12. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs
  13. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs
  14. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs
  15. 1
      ICSharpCode.Decompiler/TypeSystem/ModifiedType.cs
  16. 5
      ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs
  17. 8
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.cs

@ -133,7 +133,14 @@ namespace CustomAttributes @@ -133,7 +133,14 @@ namespace CustomAttributes
1f,
2.0,
"text",
null
null,
typeof(int),
new object[] {
1
},
new int[] {
1
}
})]
public static void BoxedLiteralsArray()
{

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.il

@ -321,11 +321,18 @@ @@ -321,11 +321,18 @@
.method public hidebysig static void BoxedLiteralsArray() cil managed
{
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 10 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 13 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
00 00 0A 03 00 00 00 00 00 00 00 0B 04 00 00 00
00 00 00 00 06 05 00 07 06 00 05 07 04 08 03 61 // ...............a
00 03 00 00 03 FF FE 03 FF FF 0C 00 00 80 3F 0D // ..............?.
00 00 00 00 00 00 00 40 0E 04 74 65 78 74 0E FF // .......@..text..
50 59 53 79 73 74 65 6D 2E 49 6E 74 33 32 2C 20 // PYSystem.Int32,
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 1D 51 01 00 00 // c561934e089.Q...
00 08 01 00 00 00 1D 08 01 00 00 00 01 00 00 00
00 00 )
// Code size 2 (0x2)
.maxstack 8

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.opt.il

@ -306,11 +306,18 @@ @@ -306,11 +306,18 @@
.method public hidebysig static void BoxedLiteralsArray() cil managed
{
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 10 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 13 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
00 00 0A 03 00 00 00 00 00 00 00 0B 04 00 00 00
00 00 00 00 06 05 00 07 06 00 05 07 04 08 03 61 // ...............a
00 03 00 00 03 FF FE 03 FF FF 0C 00 00 80 3F 0D // ..............?.
00 00 00 00 00 00 00 40 0E 04 74 65 78 74 0E FF // .......@..text..
50 59 53 79 73 74 65 6D 2E 49 6E 74 33 32 2C 20 // PYSystem.Int32,
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 1D 51 01 00 00 // c561934e089.Q...
00 08 01 00 00 00 1D 08 01 00 00 00 01 00 00 00
00 00 )
// Code size 1 (0x1)
.maxstack 8

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.opt.roslyn.il

@ -310,11 +310,18 @@ @@ -310,11 +310,18 @@
.method public hidebysig static void BoxedLiteralsArray() cil managed
{
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 10 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 13 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
00 00 0A 03 00 00 00 00 00 00 00 0B 04 00 00 00
00 00 00 00 06 05 00 07 06 00 05 07 04 08 03 61 // ...............a
00 03 00 00 03 FF FE 03 FF FF 0C 00 00 80 3F 0D // ..............?.
00 00 00 00 00 00 00 40 0E 04 74 65 78 74 0E FF // .......@..text..
50 59 53 79 73 74 65 6D 2E 49 6E 74 33 32 2C 20 // PYSystem.Int32,
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 1D 51 01 00 00 // c561934e089.Q...
00 08 01 00 00 00 1D 08 01 00 00 00 01 00 00 00
00 00 )
// Code size 1 (0x1)
.maxstack 8

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomAttributes.roslyn.il

@ -325,11 +325,18 @@ @@ -325,11 +325,18 @@
.method public hidebysig static void BoxedLiteralsArray() cil managed
{
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 10 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
.custom instance void CustomAttributes.CustomAttributes/MyAttribute::.ctor(object) = ( 01 00 1D 51 13 00 00 00 08 01 00 00 00 09 02 00 // ...Q............
00 00 0A 03 00 00 00 00 00 00 00 0B 04 00 00 00
00 00 00 00 06 05 00 07 06 00 05 07 04 08 03 61 // ...............a
00 03 00 00 03 FF FE 03 FF FF 0C 00 00 80 3F 0D // ..............?.
00 00 00 00 00 00 00 40 0E 04 74 65 78 74 0E FF // .......@..text..
50 59 53 79 73 74 65 6D 2E 49 6E 74 33 32 2C 20 // PYSystem.Int32,
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 1D 51 01 00 00 // c561934e089.Q...
00 08 01 00 00 00 1D 08 01 00 00 00 01 00 00 00
00 00 )
// Code size 2 (0x2)
.maxstack 8

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -496,7 +496,7 @@ @@ -496,7 +496,7 @@
<Compile Include="TypeSystem\IMember.cs" />
<Compile Include="TypeSystem\IMethod.cs" />
<Compile Include="TypeSystem\Implementation\AbstractFreezable.cs" />
<Compile Include="TypeSystem\Implementation\AbstractResolvedTypeParameter.cs" />
<Compile Include="TypeSystem\Implementation\AbstractTypeParameter.cs" />
<Compile Include="TypeSystem\Implementation\AbstractType.cs" />
<Compile Include="TypeSystem\Implementation\BaseTypeCollector.cs" />
<Compile Include="TypeSystem\Implementation\DefaultAssemblyReference.cs" />

52
ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs

@ -21,6 +21,7 @@ using System.Linq; @@ -21,6 +21,7 @@ using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.Decompiler.Util;
using System.Threading;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
@ -48,7 +49,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -48,7 +49,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case VariableKind.Local:
case VariableKind.Exception:
foreach (var ldloca in v.AddressInstructions) {
if (!AddressUsedOnlyForReading(ldloca)) {
if (DetermineAddressUse(ldloca) == AddressUse.Unknown) {
// If the address isn't used immediately,
// we'd need to deal with aliases.
return false;
}
}
@ -67,29 +70,46 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -67,29 +70,46 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
static bool AddressUsedOnlyForReading(ILInstruction addressLoadingInstruction)
enum AddressUse
{
Unknown,
LocalRead,
LocalReadWrite
}
static AddressUse DetermineAddressUse(ILInstruction addressLoadingInstruction)
{
switch (addressLoadingInstruction.Parent) {
case LdObj ldobj:
return true;
return AddressUse.LocalRead;
case LdFlda ldflda:
return AddressUsedOnlyForReading(ldflda);
return DetermineAddressUse(ldflda);
case Await await:
// Not strictly true as GetAwaiter() could have side-effects,
// but we need to split awaiter variables to make async/await pretty.
return true;
// GetAwaiter() may write to the struct, but shouldn't store the address for later use
return AddressUse.LocalReadWrite;
case Call call:
if (call.Method.DeclaringTypeDefinition?.KnownTypeCode == TypeSystem.KnownTypeCode.NullableOfT) {
switch (call.Method.Name) {
case "get_HasValue":
case "get_Value":
case "GetValueOrDefault":
return true;
}
// Address is passed to method.
// We'll assume the method only uses the address locally,
// unless we can see an address being returned from the method:
if (call.Method.ReturnType.IsByRefLike) {
return AddressUse.Unknown;
}
return false;
foreach (var p in call.Method.Parameters) {
// catch "out Span<int>" and similar
if (p.Type.SkipModifiers() is ByReferenceType brt && brt.ElementType.IsByRefLike)
return AddressUse.Unknown;
}
var addrParam = call.GetParameter(addressLoadingInstruction.ChildIndex);
bool isReadOnly;
if (addrParam == null) {
isReadOnly = (call.Method.DeclaringTypeDefinition?.HasAttribute(KnownAttribute.IsReadOnly) ?? false)
|| (call.Method.DeclaringType?.IsKnownType(KnownTypeCode.NullableOfT) ?? false);
} else {
isReadOnly = false;
}
return isReadOnly ? AddressUse.LocalRead : AddressUse.Unknown; // TODO AddressUse.LocalReadWrite;
default:
return false;
return AddressUse.Unknown;
}
}

4
ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs

@ -40,7 +40,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -40,7 +40,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
public override bool? IsReferenceType {
get { return null; }
}
public override bool IsByRefLike => true;
public override int GetHashCode()
{
return elementType.GetHashCode() ^ 91725813;

5
ICSharpCode.Decompiler/TypeSystem/IType.cs

@ -64,6 +64,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -64,6 +64,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </returns>
bool? IsReferenceType { get; }
/// <summary>
/// Gets whether this type is "ref-like": a ByReferenceType or "ref struct".
/// </summary>
bool IsByRefLike { get; }
/// <summary>
/// Gets the underlying type definition.
/// Can return null for types which do not have a type definition (for example arrays, pointers, type parameters).

4
ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractType.cs

@ -52,7 +52,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -52,7 +52,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
public abstract bool? IsReferenceType { get; }
public virtual bool IsByRefLike => false;
public abstract TypeKind Kind { get; }
public virtual int TypeParameterCount {

2
ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs → ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs

@ -190,6 +190,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -190,6 +190,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return null;
}
}
bool IType.IsByRefLike => false;
IType IType.DeclaringType {
get { return null; }

2
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs

@ -44,6 +44,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -44,6 +44,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly FullTypeName fullTypeName;
readonly TypeAttributes attributes;
public TypeKind Kind { get; }
public bool IsByRefLike { get; }
public ITypeDefinition DeclaringTypeDefinition { get; }
public IReadOnlyList<ITypeParameter> TypeParameters { get; }
public KnownTypeCode KnownTypeCode { get; }
@ -99,6 +100,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -99,6 +100,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.Kind = TypeKind.Void;
} else {
this.Kind = TypeKind.Struct;
this.IsByRefLike = td.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.IsByRefLike);
}
} else if (td.IsDelegate(metadata)) {
this.Kind = TypeKind.Delegate;

2
ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs

@ -172,6 +172,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -172,6 +172,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
bool IType.IsByRefLike => false;
int IType.TypeParameterCount => KnownTypeReference.Get(typeCode).TypeParameterCount;
IReadOnlyList<ITypeParameter> IType.TypeParameters => DummyTypeParameter.GetClassTypeParameterList(KnownTypeReference.Get(typeCode).TypeParameterCount);

1
ICSharpCode.Decompiler/TypeSystem/Implementation/TypeSpecification.cs

@ -37,6 +37,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -37,6 +37,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override string NameSuffix => " pinned";
public override bool? IsReferenceType => elementType.IsReferenceType;
public override bool IsByRefLike => elementType.IsByRefLike;
public override TypeKind Kind => TypeKind.Other;

1
ICSharpCode.Decompiler/TypeSystem/ModifiedType.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override string NameSuffix => (kind == TypeKind.ModReq ? "modreq" : "modopt") + $"({modifier.FullName})";
public override bool? IsReferenceType => elementType.IsReferenceType;
public override bool IsByRefLike => elementType.IsByRefLike;
public override ITypeDefinition GetDefinition()
{

5
ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs

@ -82,9 +82,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -82,9 +82,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
get { return genericType; }
}
public bool? IsReferenceType {
get { return genericType.IsReferenceType; }
}
public bool? IsReferenceType => genericType.IsReferenceType;
public bool IsByRefLike => genericType.IsByRefLike;
public IType DeclaringType {
get {

8
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -255,6 +255,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -255,6 +255,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
#endregion
public static IType SkipModifiers(this IType ty)
{
while (ty is ModifiedType mt) {
ty = mt.ElementType;
}
return ty;
}
#region GetType/Member
/// <summary>
/// Gets all type definitions in the compilation.

Loading…
Cancel
Save