From ec12508088423ad75741aa97fce6afd84ff2d167 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 22 Mar 2015 20:18:35 +0100 Subject: [PATCH] Improve IsCompatibleTypeForMemoryAccess --- .../CSharp/ExpressionBuilder.cs | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 795a93da5..4022e1f14 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -457,7 +457,7 @@ 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)) { + if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type, isWrite: false)) { // we can deference the managed reference by stripping away the 'ref' var result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression); result = result.ConvertTo(inst.Type, this); @@ -472,26 +472,12 @@ namespace ICSharpCode.Decompiler.CSharp } } - bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType) - { - IType memoryType; - if (pointerType is PointerType) - memoryType = ((PointerType)pointerType).ElementType; - else if (pointerType is ByReferenceType) - memoryType = ((ByReferenceType)pointerType).ElementType; - else - return false; - if (memoryType.IsReferenceType == true && accessType.IsReferenceType == true) - return true; - return memoryType.Equals(accessType); - } - protected internal override TranslatedExpression VisitStObj(StObj inst) { var target = Translate(inst.Target); var value = Translate(inst.Value); TranslatedExpression result; - if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) { + if (target.Expression is DirectionExpression && IsCompatibleTypeForMemoryAccess(target.Type, inst.Type, isWrite: true)) { // we can deference the managed reference by stripping away the 'ref' result = target.UnwrapChild(((DirectionExpression)target.Expression).Expression); } else { @@ -504,6 +490,49 @@ namespace ICSharpCode.Decompiler.CSharp return Assignment(result, value).WithILInstruction(inst); } + /// + /// Gets whether reading/writing an element of accessType from the pointer + /// is equivalent to reading/writing an element of the pointer's element type. + /// + bool IsCompatibleTypeForMemoryAccess(IType pointerType, IType accessType, bool isWrite) + { + IType memoryType; + if (pointerType is PointerType) + memoryType = ((PointerType)pointerType).ElementType; + else if (pointerType is ByReferenceType) + memoryType = ((ByReferenceType)pointerType).ElementType; + else + return false; + if (memoryType.Equals(accessType)) + return true; + // If the types are not equal, the access still might produce equal results: + if (memoryType.IsReferenceType == true && accessType.IsReferenceType == true) + return true; + ITypeDefinition memoryTypeDef = memoryType.GetDefinition(); + if (memoryTypeDef != null) { + switch (memoryTypeDef.KnownTypeCode) { + case KnownTypeCode.Byte: + 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)); + case KnownTypeCode.Int16: + case KnownTypeCode.UInt16: + return isWrite && (accessType.IsKnownType(KnownTypeCode.Int16) || accessType.IsKnownType(KnownTypeCode.UInt16)); + case KnownTypeCode.Int32: + case KnownTypeCode.UInt32: + return isWrite && (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); + } + } + return false; + } + protected internal override TranslatedExpression VisitLdFld(LdFld inst) { return ConvertField(inst.Field).WithILInstruction(inst);