Browse Source

properly handle char[] access and bool ref/out access

pull/728/head
Siegfried Pammer 9 years ago
parent
commit
0969abd8c9
  1. 19
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 4
      ICSharpCode.Decompiler/IL/NRTypeExtensions.cs
  3. 5
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystemUtils.cs

19
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -663,13 +663,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -663,13 +663,16 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdObj(LdObj inst)
{
var target = Translate(inst.Target);
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type, isWrite: false)) {
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can dereference the managed reference by stripping away the 'ref'
var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
// 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:
@ -685,7 +688,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -685,7 +688,7 @@ namespace ICSharpCode.Decompiler.CSharp
var target = Translate(inst.Target);
var value = Translate(inst.Value);
TranslatedExpression result;
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type, isWrite: true)) {
if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref'
result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression);
} else {
@ -702,7 +705,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -702,7 +705,7 @@ namespace ICSharpCode.Decompiler.CSharp
/// Gets whether reading/writing an element of accessType from the pointer
/// is equivalent to reading/writing an element of the pointer's element type.
/// </summary>
bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType, bool isWrite)
bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType)
{
IType memoryType;
if (pointerType is PointerType)
@ -732,19 +735,23 @@ namespace ICSharpCode.Decompiler.CSharp @@ -732,19 +735,23 @@ namespace ICSharpCode.Decompiler.CSharp
case KnownTypeCode.SByte:
// Reading small integers of different signs is not equivalent due to sign extension,
// but writes are equivalent (truncation works the same for signed and unsigned)
return isWrite && (accessType.IsKnownType(KnownTypeCode.Byte) || accessType.IsKnownType(KnownTypeCode.SByte));
return accessType.IsKnownType(KnownTypeCode.Byte) || accessType.IsKnownType(KnownTypeCode.SByte);
case KnownTypeCode.Int16:
case KnownTypeCode.UInt16:
return isWrite && (accessType.IsKnownType(KnownTypeCode.Int16) || accessType.IsKnownType(KnownTypeCode.UInt16));
return accessType.IsKnownType(KnownTypeCode.Int16) || accessType.IsKnownType(KnownTypeCode.UInt16);
case KnownTypeCode.Int32:
case KnownTypeCode.UInt32:
return isWrite && (accessType.IsKnownType(KnownTypeCode.Int32) || accessType.IsKnownType(KnownTypeCode.UInt32));
return accessType.IsKnownType(KnownTypeCode.Int32) || accessType.IsKnownType(KnownTypeCode.UInt32);
case KnownTypeCode.IntPtr:
case KnownTypeCode.UIntPtr:
return accessType.IsKnownType(KnownTypeCode.IntPtr) || accessType.IsKnownType(KnownTypeCode.UIntPtr);
case KnownTypeCode.Int64:
case KnownTypeCode.UInt64:
return accessType.IsKnownType(KnownTypeCode.Int64) || accessType.IsKnownType(KnownTypeCode.UInt64);
case KnownTypeCode.Char:
return accessType.IsKnownType(KnownTypeCode.Char) || accessType.IsKnownType(KnownTypeCode.UInt16) || accessType.IsKnownType(KnownTypeCode.Int16);
case KnownTypeCode.Boolean:
return accessType.IsKnownType(KnownTypeCode.Boolean) || accessType.IsKnownType(KnownTypeCode.Byte) || accessType.IsKnownType(KnownTypeCode.SByte);
}
}
return false;

4
ICSharpCode.Decompiler/IL/NRTypeExtensions.cs

@ -70,7 +70,8 @@ namespace ICSharpCode.Decompiler.IL @@ -70,7 +70,8 @@ namespace ICSharpCode.Decompiler.IL
public static Sign GetSign(this IType type)
{
var typeDef = type.GetDefinition();
var typeForConstant = (type.Kind == TypeKind.Enum) ? type.GetDefinition().EnumUnderlyingType : type;
var typeDef = typeForConstant.GetDefinition();
if (typeDef == null)
return Sign.None;
switch (typeDef.KnownTypeCode) {
@ -85,6 +86,7 @@ namespace ICSharpCode.Decompiler.IL @@ -85,6 +86,7 @@ namespace ICSharpCode.Decompiler.IL
return Sign.Signed;
case KnownTypeCode.UIntPtr:
case KnownTypeCode.Char:
case KnownTypeCode.Boolean:
case KnownTypeCode.Byte:
case KnownTypeCode.UInt16:
case KnownTypeCode.UInt32:

5
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystemUtils.cs

@ -60,5 +60,10 @@ namespace ICSharpCode.Decompiler @@ -60,5 +60,10 @@ namespace ICSharpCode.Decompiler
{
return GetNativeSize(type1) >= GetNativeSize(type2) ? type1 : type2;
}
public static bool IsSmallIntegerType(this IType type)
{
return GetNativeSize(type) < 4;
}
}
}

Loading…
Cancel
Save