@ -34,35 +34,21 @@ namespace ICSharpCode.Decompiler.ILAst
{
{
ILVariable v , v2 , v3 ;
ILVariable v , v2 , v3 ;
ILExpression newarrExpr ;
ILExpression newarrExpr ;
TypeReference array Type;
TypeReference element Type;
ILExpression lengthExpr ;
ILExpression lengthExpr ;
int arrayLength ;
int arrayLength ;
if ( expr . Match ( ILCode . Stloc , out v , out newarrExpr ) & &
if ( expr . Match ( ILCode . Stloc , out v , out newarrExpr ) & &
newarrExpr . Match ( ILCode . Newarr , out array Type, out lengthExpr ) & &
newarrExpr . Match ( ILCode . Newarr , out element Type, out lengthExpr ) & &
lengthExpr . Match ( ILCode . Ldc_I4 , out arrayLength ) & &
lengthExpr . Match ( ILCode . Ldc_I4 , out arrayLength ) & &
arrayLength > 0 )
arrayLength > 0 ) {
{
ILExpression [ ] newArr ;
MethodReference methodRef ;
int initArrayPos ;
ILExpression methodArg1 ;
if ( ForwardScanInitializeArrayRuntimeHelper ( body , pos + 1 , v , elementType , arrayLength , out newArr , out initArrayPos ) ) {
ILExpression methodArg2 ;
var arrayType = new ArrayType ( elementType , 1 ) ;
FieldDefinition field ;
arrayType . Dimensions [ 0 ] = new ArrayDimension ( 0 , arrayLength ) ;
if ( body . ElementAtOrDefault ( pos + 1 ) . Match ( ILCode . Call , out methodRef , out methodArg1 , out methodArg2 ) & &
body [ pos ] = new ILExpression ( ILCode . Stloc , v , new ILExpression ( ILCode . InitArray , arrayType , newArr ) ) ;
methodRef . DeclaringType . FullName = = "System.Runtime.CompilerServices.RuntimeHelpers" & &
body . RemoveAt ( initArrayPos ) ;
methodRef . Name = = "InitializeArray" & &
methodArg1 . Match ( ILCode . Ldloc , out v2 ) & &
v = = v2 & &
methodArg2 . Match ( ILCode . Ldtoken , out field ) & &
field ! = null & & field . InitialValue ! = null )
{
ILExpression [ ] newArr = new ILExpression [ arrayLength ] ;
if ( DecodeArrayInitializer ( TypeAnalysis . GetTypeCode ( arrayType ) , field . InitialValue , newArr ) ) {
body [ pos ] = new ILExpression ( ILCode . Stloc , v , new ILExpression ( ILCode . InitArray , arrayType , newArr ) ) ;
body . RemoveAt ( pos + 1 ) ;
new ILInlining ( method ) . InlineIfPossible ( body , ref pos ) ;
return true ;
}
}
}
// Put in a limit so that we don't consume too much memory if the code allocates a huge array
// Put in a limit so that we don't consume too much memory if the code allocates a huge array
// and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
// and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
const int maxConsecutiveDefaultValueExpressions = 3 0 0 ;
const int maxConsecutiveDefaultValueExpressions = 3 0 0 ;
@ -77,10 +63,9 @@ namespace ICSharpCode.Decompiler.ILAst
v = = v3 & &
v = = v3 & &
nextExpr . Arguments [ 1 ] . Match ( ILCode . Ldc_I4 , out arrayPos ) & &
nextExpr . Arguments [ 1 ] . Match ( ILCode . Ldc_I4 , out arrayPos ) & &
arrayPos > = operands . Count & &
arrayPos > = operands . Count & &
arrayPos < = operands . Count + maxConsecutiveDefaultValueExpressions )
arrayPos < = operands . Count + maxConsecutiveDefaultValueExpressions ) {
{
while ( operands . Count < arrayPos )
while ( operands . Count < arrayPos )
operands . Add ( new ILExpression ( ILCode . DefaultValue , array Type) ) ;
operands . Add ( new ILExpression ( ILCode . DefaultValue , element Type) ) ;
operands . Add ( nextExpr . Arguments [ 2 ] ) ;
operands . Add ( nextExpr . Arguments [ 2 ] ) ;
numberOfInstructionsToRemove + + ;
numberOfInstructionsToRemove + + ;
} else {
} else {
@ -88,6 +73,8 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
}
}
if ( operands . Count = = arrayLength ) {
if ( operands . Count = = arrayLength ) {
var arrayType = new ArrayType ( elementType , 1 ) ;
arrayType . Dimensions [ 0 ] = new ArrayDimension ( 0 , arrayLength ) ;
expr . Arguments [ 0 ] = new ILExpression ( ILCode . InitArray , arrayType , operands ) ;
expr . Arguments [ 0 ] = new ILExpression ( ILCode . InitArray , arrayType , operands ) ;
body . RemoveRange ( pos + 1 , numberOfInstructionsToRemove ) ;
body . RemoveRange ( pos + 1 , numberOfInstructionsToRemove ) ;
@ -98,6 +85,67 @@ namespace ICSharpCode.Decompiler.ILAst
return false ;
return false ;
}
}
bool TransformMultidimensionalArrayInitializers ( List < ILNode > body , ILExpression expr , int pos )
{
ILVariable v , v2 , v3 ;
ILExpression newarrExpr ;
MethodReference ctor ;
List < ILExpression > ctorArgs ;
ArrayType arrayType ;
if ( expr . Match ( ILCode . Stloc , out v , out newarrExpr ) & &
newarrExpr . Match ( ILCode . Newobj , out ctor , out ctorArgs ) & &
( arrayType = ( ctor . DeclaringType as ArrayType ) ) ! = null & &
arrayType . Rank = = ctorArgs . Count ) {
// Clone the type, so we can muck about with the Dimensions
arrayType = new ArrayType ( arrayType . ElementType , arrayType . Rank ) ;
var arrayLengths = new int [ arrayType . Rank ] ;
for ( int i = 0 ; i < arrayType . Rank ; i + + ) {
if ( ! ctorArgs [ i ] . Match ( ILCode . Ldc_I4 , out arrayLengths [ i ] ) ) return false ;
if ( arrayLengths [ i ] < = 0 ) return false ;
arrayType . Dimensions [ i ] = new ArrayDimension ( 0 , arrayLengths [ i ] ) ;
}
var totalElements = arrayLengths . Aggregate ( 1 , ( t , l ) = > t * l ) ;
ILExpression [ ] newArr ;
int initArrayPos ;
if ( ForwardScanInitializeArrayRuntimeHelper ( body , pos + 1 , v , arrayType , totalElements , out newArr , out initArrayPos ) ) {
var mdArr = Array . CreateInstance ( typeof ( ILExpression ) , arrayLengths ) ;
body [ pos ] = new ILExpression ( ILCode . Stloc , v , new ILExpression ( ILCode . InitArray , arrayType , newArr ) ) ;
body . RemoveAt ( initArrayPos ) ;
return true ;
}
}
return false ;
}
bool ForwardScanInitializeArrayRuntimeHelper ( List < ILNode > body , int pos , ILVariable array , TypeReference arrayType , int arrayLength , out ILExpression [ ] values , out int foundPos )
{
for ( ; pos < body . Count ; pos + + ) {
ILVariable v2 ;
MethodReference methodRef ;
ILExpression methodArg1 ;
ILExpression methodArg2 ;
FieldDefinition field ;
if ( body . ElementAtOrDefault ( pos ) . Match ( ILCode . Call , out methodRef , out methodArg1 , out methodArg2 ) & &
methodRef . DeclaringType . FullName = = "System.Runtime.CompilerServices.RuntimeHelpers" & &
methodRef . Name = = "InitializeArray" & &
methodArg1 . Match ( ILCode . Ldloc , out v2 ) & &
array = = v2 & &
methodArg2 . Match ( ILCode . Ldtoken , out field ) & &
field ! = null & & field . InitialValue ! = null ) {
ILExpression [ ] newArr = new ILExpression [ arrayLength ] ;
if ( DecodeArrayInitializer ( TypeAnalysis . GetTypeCode ( arrayType . GetElementType ( ) ) , field . InitialValue , newArr ) ) {
values = newArr ;
foundPos = pos ;
return true ;
}
}
}
values = null ;
foundPos = - 1 ;
return false ;
}
static bool DecodeArrayInitializer ( TypeCode elementType , byte [ ] initialValue , ILExpression [ ] output )
static bool DecodeArrayInitializer ( TypeCode elementType , byte [ ] initialValue , ILExpression [ ] output )
{
{
switch ( elementType ) {
switch ( elementType ) {