diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 1194b24c8..765a881d5 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -616,11 +616,22 @@ namespace Decompiler if (prop.GetMethod == cecilMethodDef) return target.Member(prop.Name).WithAnnotation(prop); } + } else if (cecilMethodDef.IsGetter) { // with parameters + PropertyDefinition indexer = GetIndexer(cecilMethodDef); + if (indexer != null) + return target.Indexer(methodArgs).WithAnnotation(indexer); } else if (cecilMethodDef.IsSetter && methodArgs.Count == 1) { foreach (var prop in cecilMethodDef.DeclaringType.Properties) { if (prop.SetMethod == cecilMethodDef) return new Ast.AssignmentExpression(target.Member(prop.Name).WithAnnotation(prop), methodArgs[0]); } + } else if (cecilMethodDef.IsSetter && methodArgs.Count > 1) { + PropertyDefinition indexer = GetIndexer(cecilMethodDef); + if (indexer != null) + return new AssignmentExpression( + target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)).WithAnnotation(indexer), + methodArgs[methodArgs.Count - 1] + ); } else if (cecilMethodDef.IsAddOn && methodArgs.Count == 1) { foreach (var ev in cecilMethodDef.DeclaringType.Events) { if (ev.AddMethod == cecilMethodDef) { @@ -647,6 +658,27 @@ namespace Decompiler return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod); } + static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef) + { + TypeDefinition typeDef = cecilMethodDef.DeclaringType; + string indexerName = null; + foreach (CustomAttribute ca in typeDef.CustomAttributes) { + if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") { + indexerName = ca.ConstructorArguments.Single().Value as string; + break; + } + } + if (indexerName == null) + return null; + foreach (PropertyDefinition prop in typeDef.Properties) { + if (prop.Name == indexerName) { + if (prop.GetMethod == cecilMethodDef || prop.SetMethod == cecilMethodDef) + return prop; + } + } + return null; + } + #if DEBUG static readonly ConcurrentDictionary unhandledOpcodes = new ConcurrentDictionary(); #endif @@ -699,17 +731,19 @@ namespace Decompiler if (reqType == null || actualType == reqType) { return expr; } else { - bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(typeSystem, actualType); - bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(typeSystem, reqType); + bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType); + bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType); - if (reqType == typeSystem.Boolean) { + if (TypeAnalysis.IsBoolean(reqType)) { + if (TypeAnalysis.IsBoolean(actualType)) + return expr; if (actualIsIntegerOrEnum) { return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, PrimitiveExpression(0, actualType)); } else { return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression()); } } - if (actualType == typeSystem.Boolean && requiredIsIntegerOrEnum) { + if (TypeAnalysis.IsBoolean(actualType) && requiredIsIntegerOrEnum) { return new ConditionalExpression { Condition = expr, TrueExpression = PrimitiveExpression(1, reqType), @@ -725,9 +759,9 @@ namespace Decompiler Expression PrimitiveExpression(long val, TypeReference type) { - if (type == typeSystem.Boolean && val == 0) + if (TypeAnalysis.IsBoolean(type) && val == 0) return new Ast.PrimitiveExpression(false); - else if (type == typeSystem.Boolean && val == 1) + else if (TypeAnalysis.IsBoolean(type) && val == 1) return new Ast.PrimitiveExpression(true); if (type != null) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) TypeDefinition enumDefinition = type.Resolve(); @@ -740,7 +774,7 @@ namespace Decompiler } } } - TypeCode code = TypeAnalysis.GetTypeCode(typeSystem, type); + TypeCode code = TypeAnalysis.GetTypeCode(type); if (code == TypeCode.Object) return new Ast.PrimitiveExpression((int)val); else diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs index febbb8add..6e5805435 100644 --- a/ICSharpCode.Decompiler/Ast/NameVariables.cs +++ b/ICSharpCode.Decompiler/Ast/NameVariables.cs @@ -25,6 +25,7 @@ namespace Decompiler { "System.Decimal", "num" }, { "System.String", "text" }, { "System.Object", "obj" }, + { "System.Char", "c" } }; @@ -105,10 +106,13 @@ namespace Decompiler case ILCode.Call: case ILCode.Callvirt: MethodReference mr = (MethodReference)expr.Operand; - if (mr.Name.StartsWith("get_", StringComparison.Ordinal)) + if (mr.Name.StartsWith("get_", StringComparison.Ordinal) && mr.Parameters.Count == 0) { + // use name from properties, but not from indexers return CleanUpVariableName(mr.Name.Substring(4)); - else if (mr.Name.StartsWith("Get", StringComparison.Ordinal) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3])) + } else if (mr.Name.StartsWith("Get", StringComparison.Ordinal) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3])) { + // use name from Get-methods return CleanUpVariableName(mr.Name.Substring(3)); + } break; } return null; diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index 2367bd049..a8f142969 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -495,20 +495,15 @@ namespace Decompiler bool canInline; allowInline.TryGetValue((ILVariable)arg.Operand, out canInline); - // Assigne the ranges for optimized away instrustions somewhere - currExpr.Arguments[0].ILRanges.AddRange(currExpr.ILRanges); - currExpr.Arguments[0].ILRanges.AddRange(nextExpr.Arguments[j].ILRanges); - if (canInline) { + // Assigne the ranges for optimized away instrustions somewhere + currExpr.Arguments[0].ILRanges.AddRange(currExpr.ILRanges); + currExpr.Arguments[0].ILRanges.AddRange(nextExpr.Arguments[j].ILRanges); + ast.RemoveAt(i); nextExpr.Arguments[j] = currExpr.Arguments[0]; // Inline the stloc body i -= 2; // Try the same index again break; // Found - } else { - ast.RemoveAt(i); - nextExpr.Arguments[j] = currExpr; // Inline the whole stloc - i -= 2; // Try the same index again - break; // Found } } } else { diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index d1ccc1249..028d045c7 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -106,6 +106,7 @@ namespace Decompiler TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) { switch (expr.Code) { + #region Logical operators case ILCode.LogicNot: if (forceInferChildren) { InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); @@ -118,10 +119,9 @@ namespace Decompiler InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); } return typeSystem.Boolean; - } - switch ((Code)expr.Code) { + #endregion #region Variable load/store - case Code.Stloc: + case ILCode.Stloc: { ILVariable v = (ILVariable)expr.Operand; if (forceInferChildren || v.Type == null) { @@ -131,7 +131,7 @@ namespace Decompiler } return v.Type; } - case Code.Ldloc: + case ILCode.Ldloc: { ILVariable v = (ILVariable)expr.Operand; if (v.Type == null) { @@ -143,20 +143,20 @@ namespace Decompiler } return v.Type; } - case Code.Starg: + case ILCode.Starg: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), ((ParameterReference)expr.Operand).ParameterType); return null; - case Code.Ldarg: + case ILCode.Ldarg: return ((ParameterReference)expr.Operand).ParameterType; - case Code.Ldloca: + case ILCode.Ldloca: return new ByReferenceType(((ILVariable)expr.Operand).Type); - case Code.Ldarga: + case ILCode.Ldarga: return new ByReferenceType(((ParameterReference)expr.Operand).ParameterType); #endregion #region Call / NewObj - case Code.Call: - case Code.Callvirt: + case ILCode.Call: + case ILCode.Callvirt: { MethodReference method = (MethodReference)expr.Operand; if (forceInferChildren) { @@ -174,7 +174,7 @@ namespace Decompiler } return SubstituteTypeArgs(method.ReturnType, method); } - case Code.Newobj: + case ILCode.Newobj: { MethodReference ctor = (MethodReference)expr.Operand; if (forceInferChildren) { @@ -186,139 +186,139 @@ namespace Decompiler } #endregion #region Load/Store Fields - case Code.Ldfld: + case ILCode.Ldfld: if (forceInferChildren) InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType); return GetFieldType((FieldReference)expr.Operand); - case Code.Ldsfld: + case ILCode.Ldsfld: return GetFieldType((FieldReference)expr.Operand); - case Code.Ldflda: - case Code.Ldsflda: + case ILCode.Ldflda: + case ILCode.Ldsflda: return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); - case Code.Stfld: + case ILCode.Stfld: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType); InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand)); } return null; - case Code.Stsfld: + case ILCode.Stsfld: if (forceInferChildren) InferTypeForExpression(expr.Arguments[0], GetFieldType((FieldReference)expr.Operand)); return null; #endregion #region Reference/Pointer instructions - case Code.Ldind_I: - case Code.Ldind_I1: - case Code.Ldind_I2: - case Code.Ldind_I4: - case Code.Ldind_I8: - case Code.Ldind_U1: - case Code.Ldind_U2: - case Code.Ldind_U4: - case Code.Ldind_R4: - case Code.Ldind_R8: - case Code.Ldind_Ref: + case ILCode.Ldind_I: + case ILCode.Ldind_I1: + case ILCode.Ldind_I2: + case ILCode.Ldind_I4: + case ILCode.Ldind_I8: + case ILCode.Ldind_U1: + case ILCode.Ldind_U2: + case ILCode.Ldind_U4: + case ILCode.Ldind_R4: + case ILCode.Ldind_R8: + case ILCode.Ldind_Ref: return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); - case Code.Stind_I1: - case Code.Stind_I2: - case Code.Stind_I4: - case Code.Stind_I8: - case Code.Stind_R4: - case Code.Stind_R8: - case Code.Stind_I: - case Code.Stind_Ref: + case ILCode.Stind_I1: + case ILCode.Stind_I2: + case ILCode.Stind_I4: + case ILCode.Stind_I8: + case ILCode.Stind_R4: + case ILCode.Stind_R8: + case ILCode.Stind_I: + case ILCode.Stind_Ref: if (forceInferChildren) { TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); InferTypeForExpression(expr.Arguments[1], elementType); } return null; - case Code.Ldobj: + case ILCode.Ldobj: return (TypeReference)expr.Operand; - case Code.Stobj: + case ILCode.Stobj: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand); } return null; - case Code.Initobj: + case ILCode.Initobj: return null; - case Code.Localloc: + case ILCode.Localloc: return typeSystem.IntPtr; #endregion #region Arithmetic instructions - case Code.Not: // bitwise complement - case Code.Neg: + case ILCode.Not: // bitwise complement + case ILCode.Neg: return InferTypeForExpression(expr.Arguments.Single(), expectedType); - case Code.Add: - case Code.Sub: - case Code.Mul: - case Code.Or: - case Code.And: - case Code.Xor: + case ILCode.Add: + case ILCode.Sub: + case ILCode.Mul: + case ILCode.Or: + case ILCode.And: + case ILCode.Xor: return InferArgumentsInBinaryOperator(expr, null); - case Code.Add_Ovf: - case Code.Sub_Ovf: - case Code.Mul_Ovf: - case Code.Div: - case Code.Rem: + case ILCode.Add_Ovf: + case ILCode.Sub_Ovf: + case ILCode.Mul_Ovf: + case ILCode.Div: + case ILCode.Rem: return InferArgumentsInBinaryOperator(expr, true); - case Code.Add_Ovf_Un: - case Code.Sub_Ovf_Un: - case Code.Mul_Ovf_Un: - case Code.Div_Un: - case Code.Rem_Un: + case ILCode.Add_Ovf_Un: + case ILCode.Sub_Ovf_Un: + case ILCode.Mul_Ovf_Un: + case ILCode.Div_Un: + case ILCode.Rem_Un: return InferArgumentsInBinaryOperator(expr, false); - case Code.Shl: - case Code.Shr: + case ILCode.Shl: + case ILCode.Shr: if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); return InferTypeForExpression(expr.Arguments[0], typeSystem.Int32); - case Code.Shr_Un: + case ILCode.Shr_Un: if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32); #endregion #region Constant loading instructions - case Code.Ldnull: + case ILCode.Ldnull: return typeSystem.Object; - case Code.Ldstr: + case ILCode.Ldstr: return typeSystem.String; - case Code.Ldftn: - case Code.Ldvirtftn: + case ILCode.Ldftn: + case ILCode.Ldvirtftn: return typeSystem.IntPtr; - case Code.Ldc_I4: - return (IsIntegerOrEnum(expectedType) || expectedType == typeSystem.Boolean) ? expectedType : typeSystem.Int32; - case Code.Ldc_I8: + case ILCode.Ldc_I4: + return (IsIntegerOrEnum(expectedType) || IsBoolean(expectedType)) ? expectedType : typeSystem.Int32; + case ILCode.Ldc_I8: return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64; - case Code.Ldc_R4: + case ILCode.Ldc_R4: return typeSystem.Single; - case Code.Ldc_R8: + case ILCode.Ldc_R8: return typeSystem.Double; - case Code.Ldtoken: + case ILCode.Ldtoken: if (expr.Operand is TypeReference) return new TypeReference("System", "RuntimeTypeHandle", module, module, true); else if (expr.Operand is FieldReference) return new TypeReference("System", "RuntimeFieldHandle", module, module, true); else return new TypeReference("System", "RuntimeMethodHandle", module, module, true); - case Code.Arglist: + case ILCode.Arglist: return new TypeReference("System", "RuntimeArgumentHandle", module, module, true); #endregion #region Array instructions - case Code.Newarr: + case ILCode.Newarr: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32); return new ArrayType((TypeReference)expr.Operand); - case Code.Ldlen: + case ILCode.Ldlen: return typeSystem.Int32; - case Code.Ldelem_U1: - case Code.Ldelem_U2: - case Code.Ldelem_U4: - case Code.Ldelem_I1: - case Code.Ldelem_I2: - case Code.Ldelem_I4: - case Code.Ldelem_I8: - case Code.Ldelem_I: - case Code.Ldelem_Ref: + case ILCode.Ldelem_U1: + case ILCode.Ldelem_U2: + case ILCode.Ldelem_U4: + case ILCode.Ldelem_I1: + case ILCode.Ldelem_I2: + case ILCode.Ldelem_I4: + case ILCode.Ldelem_I8: + case ILCode.Ldelem_I: + case ILCode.Ldelem_Ref: { ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; if (forceInferChildren) { @@ -327,27 +327,27 @@ namespace Decompiler } return arrayType != null ? arrayType.ElementType : null; } - case Code.Ldelem_Any: + case ILCode.Ldelem_Any: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); } return (TypeReference)expr.Operand; - case Code.Ldelema: + case ILCode.Ldelema: { ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); return arrayType != null ? new ByReferenceType(arrayType.ElementType) : null; } - case Code.Stelem_I: - case Code.Stelem_I1: - case Code.Stelem_I2: - case Code.Stelem_I4: - case Code.Stelem_I8: - case Code.Stelem_R4: - case Code.Stelem_R8: - case Code.Stelem_Ref: - case Code.Stelem_Any: + case ILCode.Stelem_I: + case ILCode.Stelem_I1: + case ILCode.Stelem_I2: + case ILCode.Stelem_I4: + case ILCode.Stelem_I8: + case ILCode.Stelem_R4: + case ILCode.Stelem_R8: + case ILCode.Stelem_Ref: + case ILCode.Stelem_Any: if (forceInferChildren) { ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); @@ -358,107 +358,107 @@ namespace Decompiler return null; #endregion #region Conversion instructions - case Code.Conv_I1: - case Code.Conv_Ovf_I1: + case ILCode.Conv_I1: + case ILCode.Conv_Ovf_I1: return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == true) ? expectedType : typeSystem.SByte; - case Code.Conv_I2: - case Code.Conv_Ovf_I2: + case ILCode.Conv_I2: + case ILCode.Conv_Ovf_I2: return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int16; - case Code.Conv_I4: - case Code.Conv_Ovf_I4: + case ILCode.Conv_I4: + case ILCode.Conv_Ovf_I4: return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int32; - case Code.Conv_I8: - case Code.Conv_Ovf_I8: + case ILCode.Conv_I8: + case ILCode.Conv_Ovf_I8: return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64; - case Code.Conv_U1: - case Code.Conv_Ovf_U1: + case ILCode.Conv_U1: + case ILCode.Conv_Ovf_U1: return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == false) ? expectedType : typeSystem.Byte; - case Code.Conv_U2: - case Code.Conv_Ovf_U2: + case ILCode.Conv_U2: + case ILCode.Conv_Ovf_U2: return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt16; - case Code.Conv_U4: - case Code.Conv_Ovf_U4: + case ILCode.Conv_U4: + case ILCode.Conv_Ovf_U4: return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt32; - case Code.Conv_U8: - case Code.Conv_Ovf_U8: + case ILCode.Conv_U8: + case ILCode.Conv_Ovf_U8: return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt64; - case Code.Conv_I: - case Code.Conv_Ovf_I: + case ILCode.Conv_I: + case ILCode.Conv_Ovf_I: return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == true) ? expectedType : typeSystem.IntPtr; - case Code.Conv_U: - case Code.Conv_Ovf_U: + case ILCode.Conv_U: + case ILCode.Conv_Ovf_U: return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == false) ? expectedType : typeSystem.UIntPtr; - case Code.Conv_R4: + case ILCode.Conv_R4: return typeSystem.Single; - case Code.Conv_R8: + case ILCode.Conv_R8: return typeSystem.Double; - case Code.Conv_R_Un: - return (expectedType == typeSystem.Single) ? typeSystem.Single : typeSystem.Double; - case Code.Castclass: - case Code.Isinst: - case Code.Unbox_Any: + case ILCode.Conv_R_Un: + return (expectedType != null && expectedType.MetadataType == MetadataType.Single) ? typeSystem.Single : typeSystem.Double; + case ILCode.Castclass: + case ILCode.Isinst: + case ILCode.Unbox_Any: return (TypeReference)expr.Operand; - case Code.Box: + case ILCode.Box: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand); return (TypeReference)expr.Operand; #endregion #region Comparison instructions - case Code.Ceq: + case ILCode.Ceq: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, null); return typeSystem.Boolean; - case Code.Clt: - case Code.Cgt: + case ILCode.Clt: + case ILCode.Cgt: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, true); return typeSystem.Boolean; - case Code.Clt_Un: - case Code.Cgt_Un: + case ILCode.Clt_Un: + case ILCode.Cgt_Un: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, false); return typeSystem.Boolean; #endregion #region Branch instructions - case Code.Beq: - case Code.Bne_Un: + case ILCode.Beq: + case ILCode.Bne_Un: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, null); return null; - case Code.Brtrue: - case Code.Brfalse: + case ILCode.Brtrue: + case ILCode.Brfalse: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); return null; - case Code.Blt: - case Code.Ble: - case Code.Bgt: - case Code.Bge: + case ILCode.Blt: + case ILCode.Ble: + case ILCode.Bgt: + case ILCode.Bge: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, true); return null; - case Code.Blt_Un: - case Code.Ble_Un: - case Code.Bgt_Un: - case Code.Bge_Un: + case ILCode.Blt_Un: + case ILCode.Ble_Un: + case ILCode.Bgt_Un: + case ILCode.Bge_Un: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, false); return null; - case Code.Br: - case Code.Leave: - case Code.Endfinally: - case Code.Switch: - case Code.Throw: - case Code.Rethrow: + case ILCode.Br: + case ILCode.Leave: + case ILCode.Endfinally: + case ILCode.Switch: + case ILCode.Throw: + case ILCode.Rethrow: return null; - case Code.Ret: + case ILCode.Ret: if (forceInferChildren && expr.Arguments.Count == 1) InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType); return null; #endregion - case Code.Pop: + case ILCode.Pop: return null; - case Code.Dup: + case ILCode.Dup: return InferTypeForExpression(expr.Arguments.Single(), expectedType); default: Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName()); @@ -568,22 +568,17 @@ namespace Decompiler TypeReference TypeWithMoreInformation(TypeReference leftPreferred, TypeReference rightPreferred) { - int left = GetInformationAmount(typeSystem, leftPreferred); - int right = GetInformationAmount(typeSystem, rightPreferred); + int left = GetInformationAmount(leftPreferred); + int right = GetInformationAmount(rightPreferred); if (left < right) return rightPreferred; else return leftPreferred; } - int GetInformationAmount(TypeReference type) - { - return GetInformationAmount(typeSystem, type); - } - const int nativeInt = 33; // treat native int as between int32 and int64 - static int GetInformationAmount(TypeSystem typeSystem, TypeReference type) + static int GetInformationAmount(TypeReference type) { if (type == null) return 0; @@ -592,40 +587,48 @@ namespace Decompiler TypeDefinition typeDef = type.Resolve() as TypeDefinition; if (typeDef != null && typeDef.IsEnum) { TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType; - return GetInformationAmount(typeDef.Module.TypeSystem, underlyingType); + return GetInformationAmount(underlyingType); } } - if (type == typeSystem.Boolean) - return 1; - else if (type == typeSystem.Byte || type == typeSystem.SByte) - return 8; - else if (type == typeSystem.Int16 || type == typeSystem.UInt16) - return 16; - else if (type == typeSystem.Int32 || type == typeSystem.UInt32) - return 32; - else if (type == typeSystem.IntPtr || type == typeSystem.UIntPtr) - return nativeInt; - else if (type == typeSystem.Int64 || type == typeSystem.UInt64) - return 64; - return 100; // we consider structs/objects to have more information than any primitives - } - - bool IsIntegerOrEnum(TypeReference type) - { - return IsIntegerOrEnum(typeSystem, type); + switch (type.MetadataType) { + case MetadataType.Void: + return 0; + case MetadataType.Boolean: + return 1; + case MetadataType.SByte: + case MetadataType.Byte: + return 8; + case MetadataType.Char: + case MetadataType.Int16: + case MetadataType.UInt16: + return 16; + case MetadataType.Int32: + case MetadataType.UInt32: + case MetadataType.Single: + return 32; + case MetadataType.Int64: + case MetadataType.UInt64: + case MetadataType.Double: + return 64; + case MetadataType.IntPtr: + case MetadataType.UIntPtr: + return nativeInt; + default: + return 100; // we consider structs/objects to have more information than any primitives + } } - public static bool IsIntegerOrEnum(TypeSystem typeSystem, TypeReference type) + public static bool IsBoolean(TypeReference type) { - return IsSigned(typeSystem, type) != null; + return type != null && type.MetadataType == MetadataType.Boolean; } - bool? IsSigned(TypeReference type) + public static bool IsIntegerOrEnum(TypeReference type) { - return IsSigned(typeSystem, type); + return IsSigned(type) != null; } - static bool? IsSigned(TypeSystem typeSystem, TypeReference type) + static bool? IsSigned(TypeReference type) { if (type == null) return null; @@ -633,47 +636,60 @@ namespace Decompiler TypeDefinition typeDef = type.Resolve() as TypeDefinition; if (typeDef != null && typeDef.IsEnum) { TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType; - return IsSigned(typeDef.Module.TypeSystem, underlyingType); + return IsSigned(underlyingType); + } + switch (type.MetadataType) { + case MetadataType.SByte: + case MetadataType.Int16: + case MetadataType.Int32: + case MetadataType.Int64: + case MetadataType.IntPtr: + return true; + case MetadataType.Byte: + case MetadataType.UInt16: + case MetadataType.UInt32: + case MetadataType.UInt64: + case MetadataType.UIntPtr: + return false; + default: + return null; } - if (type == typeSystem.Byte || type == typeSystem.UInt16 || type == typeSystem.UInt32 || type == typeSystem.UInt64 || type == typeSystem.UIntPtr) - return false; - if (type == typeSystem.SByte || type == typeSystem.Int16 || type == typeSystem.Int32 || type == typeSystem.Int64 || type == typeSystem.IntPtr) - return true; - return null; } - public static TypeCode GetTypeCode(TypeSystem typeSystem, TypeReference type) + public static TypeCode GetTypeCode(TypeReference type) { - if (type == typeSystem.Boolean) - return TypeCode.Boolean; - else if (type == typeSystem.Byte) - return TypeCode.Byte; - else if (type == typeSystem.Char) - return TypeCode.Char; - else if (type == typeSystem.Double) - return TypeCode.Double; - else if (type == typeSystem.Int16) - return TypeCode.Int16; - else if (type == typeSystem.Int32) - return TypeCode.Int32; - else if (type == typeSystem.Int64) - return TypeCode.Int64; - else if (type == typeSystem.Single) - return TypeCode.Single; - else if (type == typeSystem.Double) - return TypeCode.Double; - else if (type == typeSystem.SByte) - return TypeCode.SByte; - else if (type == typeSystem.UInt16) - return TypeCode.UInt16; - else if (type == typeSystem.UInt32) - return TypeCode.UInt32; - else if (type == typeSystem.UInt64) - return TypeCode.UInt64; - else if (type == typeSystem.String) - return TypeCode.String; - else - return TypeCode.Object; + if (type == null) + return TypeCode.Empty; + switch (type.MetadataType) { + case MetadataType.Boolean: + return TypeCode.Boolean; + case MetadataType.Char: + return TypeCode.Char; + case MetadataType.SByte: + return TypeCode.SByte; + case MetadataType.Byte: + return TypeCode.Byte; + case MetadataType.Int16: + return TypeCode.Int16; + case MetadataType.UInt16: + return TypeCode.UInt16; + case MetadataType.Int32: + return TypeCode.Int32; + case MetadataType.UInt32: + return TypeCode.UInt32; + case MetadataType.Int64: + return TypeCode.Int64; + case MetadataType.UInt64: + return TypeCode.UInt64; + case MetadataType.Single: + return TypeCode.Single; + case MetadataType.Double: + return TypeCode.Double; + case MetadataType.String: + return TypeCode.String; + default: + return TypeCode.Object; + } } } } diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 8d0896ef5..a7952b1c0 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -50,6 +50,7 @@ + diff --git a/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs b/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs new file mode 100644 index 000000000..c610bc7ae --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs @@ -0,0 +1,50 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Text; + +public class PropertiesAndEvents +{ + public int Getter(StringBuilder b) + { + return b.Length; + } + + public void Setter(StringBuilder b) + { + b.Capacity = 100; + } + + public char IndexerGetter(StringBuilder b) + { + return b[50]; + } + + public void IndexerSetter(StringBuilder b) + { + b[42] = 'b'; + } + + public int AutomaticProperty { get; set; } + + public int CustomProperty { + get { + return this.AutomaticProperty; + } + set { + this.AutomaticProperty = value; + } + } + + public event EventHandler AutomaticEvent; + + public event EventHandler CustomEvent { + add { + this.AutomaticEvent += value; + } + remove { + this.AutomaticEvent -= value; + } + } +} diff --git a/Mono.Cecil/Mono.Cecil/AssemblyDefinition.cs b/Mono.Cecil/Mono.Cecil/AssemblyDefinition.cs index bb757d38c..5ed27c431 100644 --- a/Mono.Cecil/Mono.Cecil/AssemblyDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/AssemblyDefinition.cs @@ -62,7 +62,7 @@ namespace Mono.Cecil { return modules; if (main_module.HasImage) - return modules = main_module.Read (this, (_, reader) => reader.ReadModules ()); + return main_module.Read (ref modules, this, (_, reader) => reader.ReadModules ()); return modules = new Collection { main_module }; } @@ -87,7 +87,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (main_module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, main_module)); } } public bool HasSecurityDeclarations { @@ -100,7 +100,7 @@ namespace Mono.Cecil { } public Collection SecurityDeclarations { - get { return security_declarations ?? (security_declarations = this.GetSecurityDeclarations (main_module)); } + get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, main_module)); } } internal AssemblyDefinition () diff --git a/Mono.Cecil/Mono.Cecil/AssemblyNameReference.cs b/Mono.Cecil/Mono.Cecil/AssemblyNameReference.cs index 2798082ba..ae834015d 100644 --- a/Mono.Cecil/Mono.Cecil/AssemblyNameReference.cs +++ b/Mono.Cecil/Mono.Cecil/AssemblyNameReference.cs @@ -107,9 +107,10 @@ namespace Mono.Cecil { if (public_key_token.IsNullOrEmpty () && !public_key.IsNullOrEmpty ()) { var hash = HashPublicKey (); // we need the last 8 bytes in reverse order - public_key_token = new byte [8]; - Array.Copy (hash, (hash.Length - 8), public_key_token, 0, 8); - Array.Reverse (public_key_token, 0, 8); + byte[] local_public_key_token = new byte [8]; + Array.Copy (hash, (hash.Length - 8), local_public_key_token, 0, 8); + Array.Reverse (local_public_key_token, 0, 8); + public_key_token = local_public_key_token; // publish only once finished (required for thread-safety) } return public_key_token; } diff --git a/Mono.Cecil/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/Mono.Cecil/AssemblyReader.cs index 64e330a60..ffc148678 100644 --- a/Mono.Cecil/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/Mono.Cecil/AssemblyReader.cs @@ -1558,10 +1558,11 @@ namespace Mono.Cecil { var methods = type.Methods; for (int i = 0; i < methods.Count; i++) { var method = methods [i]; - if (method.sem_attrs.HasValue) + if (method.sem_attrs_ready) continue; method.sem_attrs = ReadMethodSemantics (method); + method.sem_attrs_ready = true; } } diff --git a/Mono.Cecil/Mono.Cecil/CustomAttribute.cs b/Mono.Cecil/Mono.Cecil/CustomAttribute.cs index 40b32ebdb..51ffc52d8 100644 --- a/Mono.Cecil/Mono.Cecil/CustomAttribute.cs +++ b/Mono.Cecil/Mono.Cecil/CustomAttribute.cs @@ -191,7 +191,7 @@ namespace Mono.Cecil { if (!HasImage || signature == 0) throw new NotSupportedException (); - return blob = Module.Read (this, (attribute, reader) => reader.ReadCustomAttributeBlob (attribute.signature)); + return Module.Read (ref blob, this, (attribute, reader) => reader.ReadCustomAttributeBlob (attribute.signature)); } void Resolve () @@ -199,23 +199,22 @@ namespace Mono.Cecil { if (resolved || !HasImage) return; - try { - Module.Read (this, (attribute, reader) => { + Module.Read (this, (attribute, reader) => { + try { reader.ReadCustomAttributeSignature (attribute); - return this; - }); - - resolved = true; - } catch (ResolutionException) { - if (arguments != null) - arguments.Clear (); - if (fields != null) - fields.Clear (); - if (properties != null) - properties.Clear (); - - resolved = false; - } + resolved = true; + } catch (ResolutionException) { + if (arguments != null) + arguments.Clear (); + if (fields != null) + fields.Clear (); + if (properties != null) + properties.Clear (); + + resolved = false; + } + return this; + }); } } diff --git a/Mono.Cecil/Mono.Cecil/EventDefinition.cs b/Mono.Cecil/Mono.Cecil/EventDefinition.cs index 44ca8c092..006aa4d47 100644 --- a/Mono.Cecil/Mono.Cecil/EventDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/EventDefinition.cs @@ -113,7 +113,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } } #region EventAttributes @@ -148,16 +148,18 @@ namespace Mono.Cecil { void InitializeMethods () { - if (add_method != null - || invoke_method != null - || remove_method != null) - return; - var module = this.Module; - if (!module.HasImage ()) - return; + lock (module.SyncRoot) { + if (add_method != null + || invoke_method != null + || remove_method != null) + return; + + if (!module.HasImage ()) + return; - module.Read (this, (@event, reader) => reader.ReadMethods (@event)); + module.Read (this, (@event, reader) => reader.ReadMethods (@event)); + } } public override EventDefinition Resolve () diff --git a/Mono.Cecil/Mono.Cecil/FieldDefinition.cs b/Mono.Cecil/Mono.Cecil/FieldDefinition.cs index c60a94005..caa4898c2 100644 --- a/Mono.Cecil/Mono.Cecil/FieldDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/FieldDefinition.cs @@ -124,7 +124,7 @@ namespace Mono.Cecil { public bool HasConstant { get { - ResolveConstant (); + this.ResolveConstant (ref constant, Module); return constant != Mixin.NoValue; } @@ -136,14 +136,6 @@ namespace Mono.Cecil { set { constant = value; } } - void ResolveConstant () - { - if (constant != Mixin.NotResolved) - return; - - this.ResolveConstant (ref constant, Module); - } - public bool HasCustomAttributes { get { if (custom_attributes != null) @@ -154,7 +146,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } } public bool HasMarshalInfo { @@ -167,7 +159,7 @@ namespace Mono.Cecil { } public MarshalInfo MarshalInfo { - get { return marshal_info ?? (marshal_info = this.GetMarshalInfo (Module)); } + get { return marshal_info ?? (this.GetMarshalInfo (ref marshal_info, Module)); } set { marshal_info = value; } } diff --git a/Mono.Cecil/Mono.Cecil/GenericParameter.cs b/Mono.Cecil/Mono.Cecil/GenericParameter.cs index d3e5a15d5..133371075 100644 --- a/Mono.Cecil/Mono.Cecil/GenericParameter.cs +++ b/Mono.Cecil/Mono.Cecil/GenericParameter.cs @@ -78,7 +78,7 @@ namespace Mono.Cecil { return constraints; if (HasImage) - return constraints = Module.Read (this, (generic_parameter, reader) => reader.ReadGenericConstraints (generic_parameter)); + return Module.Read (ref constraints, this, (generic_parameter, reader) => reader.ReadGenericConstraints (generic_parameter)); return constraints = new Collection (); } @@ -94,7 +94,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } } internal new bool HasImage { diff --git a/Mono.Cecil/Mono.Cecil/IConstantProvider.cs b/Mono.Cecil/Mono.Cecil/IConstantProvider.cs index e3338cf20..a3eaacc7c 100644 --- a/Mono.Cecil/Mono.Cecil/IConstantProvider.cs +++ b/Mono.Cecil/Mono.Cecil/IConstantProvider.cs @@ -44,9 +44,14 @@ namespace Mono.Cecil { ref object constant, ModuleDefinition module) { - constant = module.HasImage () - ? module.Read (self, (provider, reader) => reader.ReadConstant (provider)) - : Mixin.NoValue; + lock (module.SyncRoot) { + if (constant != Mixin.NotResolved) + return; + if (module.HasImage ()) + constant = module.Read (self, (provider, reader) => reader.ReadConstant (provider)); + else + constant = Mixin.NoValue; + } } } } diff --git a/Mono.Cecil/Mono.Cecil/ICustomAttributeProvider.cs b/Mono.Cecil/Mono.Cecil/ICustomAttributeProvider.cs index 08e5f925a..f67f209f1 100644 --- a/Mono.Cecil/Mono.Cecil/ICustomAttributeProvider.cs +++ b/Mono.Cecil/Mono.Cecil/ICustomAttributeProvider.cs @@ -27,7 +27,6 @@ // using System; - using Mono.Collections.Generic; namespace Mono.Cecil { @@ -52,11 +51,12 @@ namespace Mono.Cecil { public static Collection GetCustomAttributes ( this ICustomAttributeProvider self, + ref Collection variable, ModuleDefinition module) { return module.HasImage () - ? module.Read (self, (provider, reader) => reader.ReadCustomAttributes (provider)) - : new Collection (); + ? module.Read (ref variable, self, (provider, reader) => reader.ReadCustomAttributes (provider)) + : variable = new Collection(); } } } diff --git a/Mono.Cecil/Mono.Cecil/IGenericParameterProvider.cs b/Mono.Cecil/Mono.Cecil/IGenericParameterProvider.cs index 27d1669fc..19ff98da8 100644 --- a/Mono.Cecil/Mono.Cecil/IGenericParameterProvider.cs +++ b/Mono.Cecil/Mono.Cecil/IGenericParameterProvider.cs @@ -65,11 +65,12 @@ namespace Mono.Cecil { public static Collection GetGenericParameters ( this IGenericParameterProvider self, + ref Collection collection, ModuleDefinition module) { return module.HasImage () - ? module.Read (self, (provider, reader) => reader.ReadGenericParameters (provider)) - : new Collection (); + ? module.Read (ref collection, self, (provider, reader) => reader.ReadGenericParameters (provider)) + : collection = new Collection (); } } } diff --git a/Mono.Cecil/Mono.Cecil/IMarshalInfoProvider.cs b/Mono.Cecil/Mono.Cecil/IMarshalInfoProvider.cs index a3bba6d0d..8e3cbce0f 100644 --- a/Mono.Cecil/Mono.Cecil/IMarshalInfoProvider.cs +++ b/Mono.Cecil/Mono.Cecil/IMarshalInfoProvider.cs @@ -47,10 +47,11 @@ namespace Mono.Cecil { public static MarshalInfo GetMarshalInfo ( this IMarshalInfoProvider self, + ref MarshalInfo variable, ModuleDefinition module) { return module.HasImage () - ? module.Read (self, (provider, reader) => reader.ReadMarshalInfo (provider)) + ? module.Read (ref variable, self, (provider, reader) => reader.ReadMarshalInfo (provider)) : null; } } diff --git a/Mono.Cecil/Mono.Cecil/MethodDefinition.cs b/Mono.Cecil/Mono.Cecil/MethodDefinition.cs index 3b74e5a7d..68a849ad7 100644 --- a/Mono.Cecil/Mono.Cecil/MethodDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/MethodDefinition.cs @@ -37,7 +37,8 @@ namespace Mono.Cecil { ushort attributes; ushort impl_attributes; - internal MethodSemanticsAttributes? sem_attrs; + internal volatile bool sem_attrs_ready; + internal MethodSemanticsAttributes sem_attrs; Collection custom_attributes; Collection security_declarations; @@ -59,23 +60,24 @@ namespace Mono.Cecil { public MethodSemanticsAttributes SemanticsAttributes { get { - if (sem_attrs.HasValue) - return sem_attrs.Value; + if (sem_attrs_ready) + return sem_attrs; if (HasImage) { ReadSemantics (); - return sem_attrs.Value; + return sem_attrs; } sem_attrs = MethodSemanticsAttributes.None; - return sem_attrs.Value; + sem_attrs_ready = true; + return sem_attrs; } set { sem_attrs = value; } } internal void ReadSemantics () { - if (sem_attrs.HasValue) + if (sem_attrs_ready) return; var module = this.Module; @@ -98,7 +100,7 @@ namespace Mono.Cecil { } public Collection SecurityDeclarations { - get { return security_declarations ?? (security_declarations = this.GetSecurityDeclarations (Module)); } + get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, Module)); } } public bool HasCustomAttributes { @@ -111,7 +113,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } } public int RVA { @@ -138,7 +140,7 @@ namespace Mono.Cecil { return null; if (HasImage && rva != 0) - return body = Module.Read (this, (method, reader) => reader.ReadMethodBody (method)); + return Module.Read (ref body, this, (method, reader) => reader.ReadMethodBody (method)); return body = new MethodBody (this); } @@ -160,7 +162,7 @@ namespace Mono.Cecil { return pinvoke; if (HasImage && IsPInvokeImpl) - return pinvoke = Module.Read (this, (method, reader) => reader.ReadPInvokeInfo (method)); + return Module.Read (ref pinvoke, this, (method, reader) => reader.ReadPInvokeInfo (method)); return null; } @@ -188,7 +190,7 @@ namespace Mono.Cecil { return overrides; if (HasImage) - return overrides = Module.Read (this, (method, reader) => reader.ReadOverrides (method)); + return Module.Read (ref overrides, this, (method, reader) => reader.ReadOverrides (method)); return overrides = new Collection (); } @@ -204,7 +206,7 @@ namespace Mono.Cecil { } public override Collection GenericParameters { - get { return generic_parameters ?? (generic_parameters = this.GetGenericParameters (Module)); } + get { return generic_parameters ?? (this.GetGenericParameters (ref generic_parameters, Module)); } } #region MethodAttributes diff --git a/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs b/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs index ea84209d7..71e56efe1 100644 --- a/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs @@ -29,8 +29,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; using SR = System.Reflection; - using Mono.Cecil.Cil; using Mono.Cecil.Metadata; using Mono.Cecil.PE; @@ -261,7 +261,11 @@ namespace Mono.Cecil { #if !READ_ONLY internal MetadataImporter MetadataImporter { - get { return importer ?? (importer = new MetadataImporter (this)); } + get { + if (importer == null) + Interlocked.CompareExchange(ref importer, new MetadataImporter(this), null); + return importer; + } } #endif @@ -270,7 +274,11 @@ namespace Mono.Cecil { } public TypeSystem TypeSystem { - get { return type_system ?? (type_system = TypeSystem.CreateTypeSystem (this)); } + get { + if (type_system == null) + Interlocked.CompareExchange(ref type_system, TypeSystem.CreateTypeSystem (this), null); + return type_system; + } } public bool HasAssemblyReferences { @@ -288,7 +296,7 @@ namespace Mono.Cecil { return references; if (HasImage) - return references = Read (this, (_, reader) => reader.ReadAssemblyReferences ()); + return Read (ref references, this, (_, reader) => reader.ReadAssemblyReferences ()); return references = new Collection (); } @@ -309,7 +317,7 @@ namespace Mono.Cecil { return modules; if (HasImage) - return modules = Read (this, (_, reader) => reader.ReadModuleReferences ()); + return Read (ref modules, this, (_, reader) => reader.ReadModuleReferences ()); return modules = new Collection (); } @@ -333,7 +341,7 @@ namespace Mono.Cecil { return resources; if (HasImage) - return resources = Read (this, (_, reader) => reader.ReadResources ()); + return Read (ref resources, this, (_, reader) => reader.ReadResources ()); return resources = new Collection (); } @@ -349,7 +357,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (this)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, this)); } } public bool HasTypes { @@ -367,7 +375,7 @@ namespace Mono.Cecil { return types; if (HasImage) - return types = Read (this, (_, reader) => reader.ReadTypes ()); + return Read (ref types, this, (_, reader) => reader.ReadTypes ()); return types = new TypeDefinitionCollection (this); } @@ -388,7 +396,7 @@ namespace Mono.Cecil { return exported_types; if (HasImage) - return exported_types = Read (this, (_, reader) => reader.ReadExportedTypes ()); + return Read (ref exported_types, this, (_, reader) => reader.ReadExportedTypes ()); return exported_types = new Collection (); } @@ -400,7 +408,7 @@ namespace Mono.Cecil { return entry_point; if (HasImage) - return entry_point = Read (this, (_, reader) => reader.ReadEntryPoint ()); + return Read (ref entry_point, this, (_, reader) => reader.ReadEntryPoint ()); return entry_point = null; } @@ -760,6 +768,10 @@ namespace Mono.Cecil { readonly object module_lock = new object(); + internal object SyncRoot { + get { return module_lock; } + } + internal TRet Read (TItem item, Func read) { lock (module_lock) { @@ -774,6 +786,24 @@ namespace Mono.Cecil { return ret; } } + + internal TRet Read (ref TRet variable, TItem item, Func read) where TRet : class + { + lock (module_lock) { + if (variable != null) + return variable; + + var position = reader.position; + var context = reader.context; + + var ret = read (item, reader); + + reader.position = position; + reader.context = context; + + return variable = ret; + } + } void ProcessDebugHeader () { diff --git a/Mono.Cecil/Mono.Cecil/ParameterDefinition.cs b/Mono.Cecil/Mono.Cecil/ParameterDefinition.cs index 059f257fc..ec916975f 100644 --- a/Mono.Cecil/Mono.Cecil/ParameterDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/ParameterDefinition.cs @@ -51,7 +51,7 @@ namespace Mono.Cecil { public bool HasConstant { get { - ResolveConstant (); + this.ResolveConstant (ref constant, parameter_type.Module); return constant != Mixin.NoValue; } @@ -63,14 +63,6 @@ namespace Mono.Cecil { set { constant = value; } } - void ResolveConstant () - { - if (constant != Mixin.NotResolved) - return; - - this.ResolveConstant (ref constant, parameter_type.Module); - } - public bool HasCustomAttributes { get { if (custom_attributes != null) @@ -81,7 +73,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (parameter_type.Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, parameter_type.Module)); } } public bool HasMarshalInfo { @@ -94,7 +86,7 @@ namespace Mono.Cecil { } public MarshalInfo MarshalInfo { - get { return marshal_info ?? (marshal_info = this.GetMarshalInfo (parameter_type.Module)); } + get { return marshal_info ?? (this.GetMarshalInfo (ref marshal_info, parameter_type.Module)); } set { marshal_info = value; } } diff --git a/Mono.Cecil/Mono.Cecil/PropertyDefinition.cs b/Mono.Cecil/Mono.Cecil/PropertyDefinition.cs index c10814f5d..43b459e63 100644 --- a/Mono.Cecil/Mono.Cecil/PropertyDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/PropertyDefinition.cs @@ -76,7 +76,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } } public MethodDefinition GetMethod { @@ -168,7 +168,7 @@ namespace Mono.Cecil { public bool HasConstant { get { - ResolveConstant (); + this.ResolveConstant (ref constant, Module); return constant != Mixin.NoValue; } @@ -180,14 +180,6 @@ namespace Mono.Cecil { set { constant = value; } } - void ResolveConstant () - { - if (constant != Mixin.NotResolved) - return; - - this.ResolveConstant (ref constant, Module); - } - #region PropertyAttributes public bool IsSpecialName { @@ -245,14 +237,16 @@ namespace Mono.Cecil { void InitializeMethods () { - if (get_method != null || set_method != null) - return; - var module = this.Module; - if (!module.HasImage ()) - return; + lock (module.SyncRoot) { + if (get_method != null || set_method != null) + return; + + if (!module.HasImage ()) + return; - module.Read (this, (property, reader) => reader.ReadMethods (property)); + module.Read (this, (property, reader) => reader.ReadMethods (property)); + } } public override PropertyDefinition Resolve () diff --git a/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs b/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs index 4e57adae3..b09e4a6e8 100644 --- a/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs +++ b/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs @@ -27,7 +27,7 @@ // using System; - +using System.Threading; using Mono.Collections.Generic; namespace Mono.Cecil { @@ -172,11 +172,12 @@ namespace Mono.Cecil { public static Collection GetSecurityDeclarations ( this ISecurityDeclarationProvider self, + ref Collection variable, ModuleDefinition module) { return module.HasImage () - ? module.Read (self, (provider, reader) => reader.ReadSecurityDeclarations (provider)) - : new Collection (); + ? module.Read (ref variable, self, (provider, reader) => reader.ReadSecurityDeclarations (provider)) + : LazyInitializer.EnsureInitialized(ref variable); } } } diff --git a/Mono.Cecil/Mono.Cecil/TypeDefinition.cs b/Mono.Cecil/Mono.Cecil/TypeDefinition.cs index c83531a05..dd0564aa1 100644 --- a/Mono.Cecil/Mono.Cecil/TypeDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/TypeDefinition.cs @@ -131,7 +131,7 @@ namespace Mono.Cecil { return interfaces; if (HasImage) - return interfaces = Module.Read (this, (type, reader) => reader.ReadInterfaces (type)); + return Module.Read (ref interfaces, this, (type, reader) => reader.ReadInterfaces (type)); return interfaces = new Collection (); } @@ -155,7 +155,7 @@ namespace Mono.Cecil { return nested_types; if (HasImage) - return nested_types = Module.Read (this, (type, reader) => reader.ReadNestedTypes (type)); + return Module.Read (ref nested_types, this, (type, reader) => reader.ReadNestedTypes (type)); return nested_types = new MemberDefinitionCollection (this); } @@ -183,7 +183,7 @@ namespace Mono.Cecil { return methods; if (HasImage) - return methods = Module.Read (this, (type, reader) => reader.ReadMethods (type)); + return Module.Read (ref methods, this, (type, reader) => reader.ReadMethods (type)); return methods = new MemberDefinitionCollection (this); } @@ -207,7 +207,7 @@ namespace Mono.Cecil { return fields; if (HasImage) - return fields = Module.Read (this, (type, reader) => reader.ReadFields (type)); + return Module.Read (ref fields, this, (type, reader) => reader.ReadFields (type)); return fields = new MemberDefinitionCollection (this); } @@ -231,7 +231,7 @@ namespace Mono.Cecil { return events; if (HasImage) - return events = Module.Read (this, (type, reader) => reader.ReadEvents (type)); + return Module.Read (ref events, this, (type, reader) => reader.ReadEvents (type)); return events = new MemberDefinitionCollection (this); } @@ -255,7 +255,7 @@ namespace Mono.Cecil { return properties; if (HasImage) - return properties = Module.Read (this, (type, reader) => reader.ReadProperties (type)); + return Module.Read (ref properties, this, (type, reader) => reader.ReadProperties (type)); return properties = new MemberDefinitionCollection (this); } @@ -271,7 +271,7 @@ namespace Mono.Cecil { } public Collection SecurityDeclarations { - get { return security_declarations ?? (security_declarations = this.GetSecurityDeclarations (Module)); } + get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, Module)); } } public bool HasCustomAttributes { @@ -284,7 +284,7 @@ namespace Mono.Cecil { } public Collection CustomAttributes { - get { return custom_attributes ?? (custom_attributes = this.GetCustomAttributes (Module)); } + get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, Module)); } } public override bool HasGenericParameters { @@ -297,7 +297,7 @@ namespace Mono.Cecil { } public override Collection GenericParameters { - get { return generic_parameters ?? (generic_parameters = this.GetGenericParameters (Module)); } + get { return generic_parameters ?? (this.GetGenericParameters (ref generic_parameters, Module)); } } #region TypeAttributes diff --git a/Mono.Cecil/Mono.Cecil/TypeSystem.cs b/Mono.Cecil/Mono.Cecil/TypeSystem.cs index 0b0ba91b9..16dfdce46 100644 --- a/Mono.Cecil/Mono.Cecil/TypeSystem.cs +++ b/Mono.Cecil/Mono.Cecil/TypeSystem.cs @@ -174,18 +174,27 @@ namespace Mono.Cecil { internal abstract TypeReference LookupType (string @namespace, string name); - TypeReference LookupSystemType (string name, ElementType element_type) + TypeReference LookupSystemType (ref TypeReference typeRef, string name, ElementType element_type) { - var type = LookupType ("System", name); - type.etype = element_type; - return type; + lock (module.SyncRoot) { + if (typeRef != null) + return typeRef; + var type = LookupType ("System", name); + type.etype = element_type; + return typeRef = type; + } } - TypeReference LookupSystemValueType (string name, ElementType element_type) + TypeReference LookupSystemValueType (ref TypeReference typeRef, string name, ElementType element_type) { - var type = LookupSystemType (name, element_type); - type.IsValueType = true; - return type; + lock (module.SyncRoot) { + if (typeRef != null) + return typeRef; + var type = LookupType ("System", name); + type.etype = element_type; + type.IsValueType = true; + return typeRef = type; + } } public IMetadataScope Corlib { @@ -199,75 +208,75 @@ namespace Mono.Cecil { } public TypeReference Object { - get { return type_object ?? (type_object = LookupSystemType ("Object", ElementType.Object)); } + get { return type_object ?? (LookupSystemType (ref type_object, "Object", ElementType.Object)); } } public TypeReference Void { - get { return type_void ?? (type_void = LookupSystemType ("Void", ElementType.Void)); } + get { return type_void ?? (LookupSystemType (ref type_void, "Void", ElementType.Void)); } } public TypeReference Boolean { - get { return type_bool ?? (type_bool = LookupSystemValueType ("Boolean", ElementType.Boolean)); } + get { return type_bool ?? (LookupSystemValueType (ref type_bool, "Boolean", ElementType.Boolean)); } } public TypeReference Char { - get { return type_char ?? (type_char = LookupSystemValueType ("Char", ElementType.Char)); } + get { return type_char ?? (LookupSystemValueType (ref type_char, "Char", ElementType.Char)); } } public TypeReference SByte { - get { return type_sbyte ?? (type_sbyte = LookupSystemValueType ("SByte", ElementType.I1)); } + get { return type_sbyte ?? (LookupSystemValueType (ref type_sbyte, "SByte", ElementType.I1)); } } public TypeReference Byte { - get { return type_byte ?? (type_byte = LookupSystemValueType ("Byte", ElementType.U1)); } + get { return type_byte ?? (LookupSystemValueType (ref type_byte, "Byte", ElementType.U1)); } } public TypeReference Int16 { - get { return type_int16 ?? (type_int16 = LookupSystemValueType ("Int16", ElementType.I2)); } + get { return type_int16 ?? (LookupSystemValueType (ref type_int16, "Int16", ElementType.I2)); } } public TypeReference UInt16 { - get { return type_uint16 ?? (type_uint16 = LookupSystemValueType ("UInt16", ElementType.U2)); } + get { return type_uint16 ?? (LookupSystemValueType (ref type_uint16, "UInt16", ElementType.U2)); } } public TypeReference Int32 { - get { return type_int32 ?? (type_int32 = LookupSystemValueType ("Int32", ElementType.I4)); } + get { return type_int32 ?? (LookupSystemValueType (ref type_int32, "Int32", ElementType.I4)); } } public TypeReference UInt32 { - get { return type_uint32 ?? (type_uint32 = LookupSystemValueType ("UInt32", ElementType.U4)); } + get { return type_uint32 ?? (LookupSystemValueType (ref type_uint32, "UInt32", ElementType.U4)); } } public TypeReference Int64 { - get { return type_int64 ?? (type_int64 = LookupSystemValueType ("Int64", ElementType.I8)); } + get { return type_int64 ?? (LookupSystemValueType (ref type_int64, "Int64", ElementType.I8)); } } public TypeReference UInt64 { - get { return type_uint64 ?? (type_uint64 = LookupSystemValueType ("UInt64", ElementType.U8)); } + get { return type_uint64 ?? (LookupSystemValueType (ref type_uint64, "UInt64", ElementType.U8)); } } public TypeReference Single { - get { return type_single ?? (type_single = LookupSystemValueType ("Single", ElementType.R4)); } + get { return type_single ?? (LookupSystemValueType (ref type_single, "Single", ElementType.R4)); } } public TypeReference Double { - get { return type_double ?? (type_double = LookupSystemValueType ("Double", ElementType.R8)); } + get { return type_double ?? (LookupSystemValueType (ref type_double, "Double", ElementType.R8)); } } public TypeReference IntPtr { - get { return type_intptr ?? (type_intptr = LookupSystemValueType ("IntPtr", ElementType.I)); } + get { return type_intptr ?? (LookupSystemValueType (ref type_intptr, "IntPtr", ElementType.I)); } } public TypeReference UIntPtr { - get { return type_uintptr ?? (type_uintptr = LookupSystemValueType ("UIntPtr", ElementType.U)); } + get { return type_uintptr ?? (LookupSystemValueType (ref type_uintptr, "UIntPtr", ElementType.U)); } } public TypeReference String { - get { return type_string ?? (type_string = LookupSystemType ("String", ElementType.String)); } + get { return type_string ?? (LookupSystemType (ref type_string, "String", ElementType.String)); } } public TypeReference TypedReference { - get { return type_typedref ?? (type_typedref = LookupSystemValueType ("TypedReference", ElementType.TypedByRef)); } + get { return type_typedref ?? (LookupSystemValueType (ref type_typedref, "TypedReference", ElementType.TypedByRef)); } } } }