Browse Source

Improve IsCompatibleTypeForMemoryAccess

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
ec12508088
  1. 61
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

61
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -457,7 +457,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -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 @@ -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 @@ -504,6 +490,49 @@ namespace ICSharpCode.Decompiler.CSharp
return Assignment(result, value).WithILInstruction(inst);
}
/// <summary>
/// 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)
{
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);

Loading…
Cancel
Save