@ -669,33 +669,84 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -669,33 +669,84 @@ namespace ICSharpCode.Decompiler.ILAst
} ) ;
}
static void HandlePointerArithmetic ( ILNode method )
void HandlePointerArithmetic ( ILNode method )
{
foreach ( ILExpression expr in method . GetSelfAndChildrenRecursive < ILExpression > ( ) ) {
List < ILExpression > args = expr . Arguments ;
switch ( expr . Code ) {
case ILCode . Localloc :
args [ 0 ] = DivideBySize ( args [ 0 ] , ( ( PointerType ) expr . InferredType ) . ElementType ) ;
break ;
case ILCode . Add :
{
ILExpression arg0 = args [ 0 ] ;
ILExpression expr2 = expr ;
DivideOrMultiplyBySize ( ref expr2 , ref arg0 , ( ( PointerType ) expr . InferredType ) . ElementType , true ) ;
// expr shouldn't change
if ( expr2 ! = expr )
throw new InvalidOperationException ( ) ;
args [ 0 ] = arg0 ;
break ;
}
case ILCode . Add :
case ILCode . Add_Ovf :
case ILCode . Add_Ovf_Un :
if ( expr . InferredType is PointerType ) {
if ( args [ 0 ] . ExpectedType is PointerType )
args [ 1 ] = DivideBySize ( args [ 1 ] , ( ( PointerType ) expr . InferredType ) . ElementType ) ;
else if ( args [ 1 ] . ExpectedType is PointerType )
args [ 0 ] = DivideBySize ( args [ 0 ] , ( ( PointerType ) expr . InferredType ) . ElementType ) ;
}
break ;
case ILCode . Sub :
{
ILExpression arg0 = args [ 0 ] ;
ILExpression arg1 = args [ 1 ] ;
if ( expr . InferredType is PointerType ) {
if ( arg0 . ExpectedType is PointerType ) {
DivideOrMultiplyBySize ( ref arg0 , ref arg1 , ( ( PointerType ) expr . InferredType ) . ElementType , true ) ;
} else if ( arg1 . ExpectedType is PointerType )
DivideOrMultiplyBySize ( ref arg1 , ref arg0 , ( ( PointerType ) expr . InferredType ) . ElementType , true ) ;
}
args [ 0 ] = arg0 ;
args [ 1 ] = arg1 ;
break ;
}
case ILCode . Sub :
case ILCode . Sub_Ovf :
case ILCode . Sub_Ovf_Un :
{
ILExpression arg0 = args [ 0 ] ;
ILExpression arg1 = args [ 1 ] ;
if ( expr . InferredType is PointerType ) {
if ( args [ 0 ] . ExpectedType is PointerType )
args [ 1 ] = DivideBySize ( args [ 1 ] , ( ( PointerType ) expr . InferredType ) . ElementType ) ;
if ( arg0 . ExpectedType is PointerType & & ! ( arg1 . Inferr edType is PointerType ) )
DivideOrMultiplyBySize ( ref arg0 , ref arg1 , ( ( PointerType ) expr . InferredType ) . ElementType , tru e ) ;
}
break ;
}
args [ 0 ] = arg0 ;
args [ 1 ] = arg1 ;
break ;
}
case ILCode . Conv_I8 :
{
ILExpression arg0 = args [ 0 ] ;
// conv.i8(div:intptr(p0 - p1))
if ( arg0 . Code = = ILCode . Div & & arg0 . InferredType . FullName = = "System.IntPtr" )
{
ILExpression dividend = arg0 . Arguments [ 0 ] ;
if ( dividend . InferredType . FullName = = "System.IntPtr" & &
( dividend . Code = = ILCode . Sub | | dividend . Code = = ILCode . Sub_Ovf | | dividend . Code = = ILCode . Sub_Ovf_Un ) )
{
PointerType pointerType0 = dividend . Arguments [ 0 ] . InferredType as PointerType ;
PointerType pointerType1 = dividend . Arguments [ 1 ] . InferredType as PointerType ;
if ( pointerType0 ! = null & & pointerType1 ! = null ) {
if ( pointerType0 . ElementType . FullName = = "System.Void" | |
pointerType0 . ElementType . FullName ! = pointerType1 . ElementType . FullName ) {
pointerType0 = pointerType1 = new PointerType ( typeSystem . Byte ) ;
dividend . Arguments [ 0 ] = Cast ( dividend . Arguments [ 0 ] , pointerType0 ) ;
dividend . Arguments [ 1 ] = Cast ( dividend . Arguments [ 1 ] , pointerType1 ) ;
}
DivideOrMultiplyBySize ( ref dividend , ref arg0 , pointerType0 . ElementType , false ) ;
// dividend shouldn't change
if ( args [ 0 ] . Arguments [ 0 ] ! = dividend )
throw new InvalidOperationException ( ) ;
}
}
}
args [ 0 ] = arg0 ;
break ;
}
}
}
}
@ -720,12 +771,24 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -720,12 +771,24 @@ namespace ICSharpCode.Decompiler.ILAst
return expr ;
}
static ILExpression DivideBySize ( ILExpression expr , TypeReference type )
static ILExpression Cast ( ILExpression expr , TypeReference type )
{
return new ILExpression ( ILCode . Castclass , type , expr )
{
InferredType = type ,
ExpectedType = type
} ;
}
void DivideOrMultiplyBySize ( ref ILExpression pointerExpr , ref ILExpression adjustmentExpr , TypeReference elementType , bool divide )
{
expr = UnwrapIntPtrCast ( expr ) ;
adjustm entE xpr = UnwrapIntPtrCast ( adjustm entE xpr) ;
ILExpression sizeOfExpression ;
switch ( TypeAnalysis . GetInformationAmount ( type ) ) {
switch ( TypeAnalysis . GetInformationAmount ( elementType ) ) {
case 0 : // System.Void
pointerExpr = Cast ( pointerExpr , new PointerType ( typeSystem . Byte ) ) ;
goto case 1 ;
case 1 :
case 8 :
sizeOfExpression = new ILExpression ( ILCode . Ldc_I4 , 1 ) ;
@ -740,34 +803,40 @@ namespace ICSharpCode.Decompiler.ILAst
@@ -740,34 +803,40 @@ namespace ICSharpCode.Decompiler.ILAst
sizeOfExpression = new ILExpression ( ILCode . Ldc_I4 , 8 ) ;
break ;
default :
sizeOfExpression = new ILExpression ( ILCode . Sizeof , type ) ;
sizeOfExpression = new ILExpression ( ILCode . Sizeof , elemen tT ype) ;
break ;
}
if ( expr . Code = = ILCode . Mul | | expr . Code = = ILCode . Mul_Ovf | | expr . Code = = ILCode . Mul_Ovf_Un ) {
ILExpression mulArg = expr . Arguments [ 1 ] ;
if ( mulArg . Code = = sizeOfExpression . Code & & sizeOfExpression . Operand . Equals ( mulArg . Operand ) )
return UnwrapIntPtrCast ( expr . Arguments [ 0 ] ) ;
if ( divide & & ( adjustmentExpr . Code = = ILCode . Mul | | adjustmentExpr . Code = = ILCode . Mul_Ovf | | adjustmentExpr . Code = = ILCode . Mul_Ovf_Un ) | |
! divide & & ( adjustmentExpr . Code = = ILCode . Div | | adjustmentExpr . Code = = ILCode . Div_Un ) ) {
ILExpression mulArg = adjustmentExpr . Arguments [ 1 ] ;
if ( mulArg . Code = = sizeOfExpression . Code & & sizeOfExpression . Operand . Equals ( mulArg . Operand ) ) {
adjustmentExpr = UnwrapIntPtrCast ( adjustmentExpr . Arguments [ 0 ] ) ;
return ;
}
}
if ( expr . Code = = sizeOfExpression . Code ) {
if ( sizeOfExpression . Operand . Equals ( expr . Operand ) )
return new ILExpression ( ILCode . Ldc_I4 , 1 ) ;
if ( adjustmentExpr . Code = = sizeOfExpression . Code ) {
if ( sizeOfExpression . Operand . Equals ( adjustmentExpr . Operand ) ) {
adjustmentExpr = new ILExpression ( ILCode . Ldc_I4 , 1 ) ;
return ;
}
if ( expr . Code = = ILCode . Ldc_I4 ) {
int offsetInBytes = ( int ) expr . Operand ;
if ( adjustm entE xpr. Code = = ILCode . Ldc_I4 ) {
int offsetInBytes = ( int ) adjustm entE xpr. Operand ;
int elementSize = ( int ) sizeOfExpression . Operand ;
int offsetInElements = offsetInBytes / elementSize ;
// ensure integer division
if ( offsetInElements * elementSize = = offsetInBytes ) {
expr . Operand = offsetInElements ;
return expr ;
}
}
if ( offsetInBytes % elementSize ! = 0 ) {
pointerExpr = Cast ( pointerExpr , new PointerType ( typeSystem . Byte ) ) ;
return ;
}
adjustmentExpr . Operand = offsetInBytes / elementSize ;
return ;
}
}
return new ILExpression ( ILCode . Div_Un , null , expr , sizeOfExpression ) ;
adjustmentExpr = new ILExpression ( divide ? ILCode . Div_Un : ILCode . Mul , null , adjustm entE xpr, sizeOfExpression ) ;
}
public static void ReplaceVariables ( ILNode node , Func < ILVariable , ILVariable > variableMapping )