X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fcodegen.cs;h=79dee5e3a56b419fade9e0c1bbdc2e4ac0a2c7bf;hb=394140f5a495ff5fc718249c1406735a001edf85;hp=4041a6ae3797eb5149d53056585c30b668d2ec4b;hpb=28e91840ef6c829350b74c0fc4430e4a456a5123;p=mono.git diff --git a/mcs/mcs/codegen.cs b/mcs/mcs/codegen.cs index 4041a6ae379..79dee5e3a56 100644 --- a/mcs/mcs/codegen.cs +++ b/mcs/mcs/codegen.cs @@ -51,16 +51,6 @@ namespace Mono.CSharp /// public LocalBuilder return_value; - /// - /// The location where return has to jump to return the - /// value - /// - public Label ReturnLabel; - - /// - /// If we already defined the ReturnLabel - /// - public bool HasReturnLabel; /// /// Current loop begin and end labels. @@ -87,13 +77,17 @@ namespace Mono.CSharp DynamicSiteClass dynamic_site_container; + Label? return_label; + public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type) { this.member_context = rc; this.ig = ig; - this.return_type = return_type; + if (rc.Module.Compiler.Settings.Checked) + flags |= Options.CheckedScope; + #if STATIC ig.__CleverExceptionBlockAssistance (); #endif @@ -101,6 +95,18 @@ namespace Mono.CSharp #region Properties + internal AsyncTaskStorey AsyncTaskStorey { + get { + return CurrentAnonymousMethod.Storey as AsyncTaskStorey; + } + } + + public BuiltinTypes BuiltinTypes { + get { + return MemberContext.Module.Compiler.BuiltinTypes; + } + } + public TypeSpec CurrentType { get { return member_context.CurrentType; } } @@ -113,11 +119,17 @@ namespace Mono.CSharp get { return member_context.CurrentMemberDefinition; } } + public bool HasReturnLabel { + get { + return return_label.HasValue; + } + } + public bool IsStatic { get { return member_context.IsStatic; } } - bool IsAnonymousStoreyMutateRequired { + public bool IsAnonymousStoreyMutateRequired { get { return CurrentAnonymousMethod != null && CurrentAnonymousMethod.Storey != null && @@ -150,8 +162,27 @@ namespace Mono.CSharp return return_type; } } + + // + // The label where we have to jump before leaving the context + // + public Label ReturnLabel { + get { + return return_label.Value; + } + } + #endregion + public void AssertEmptyStack () + { +#if STATIC + if (ig.__StackHeight != 0) + throw new InternalErrorException ("Await yields with non-empty stack in `{0}", + member_context.GetSignatureForError ()); +#endif + } + /// /// This is called immediately before emitting an IL opcode to tell the symbol /// writer to which source line this opcode belongs. @@ -202,7 +233,7 @@ namespace Mono.CSharp // // Creates a nested container in this context for all dynamic compiler generated stuff // - public DynamicSiteClass CreateDynamicSite () + internal DynamicSiteClass CreateDynamicSite () { if (dynamic_site_container == null) { var mc = member_context.CurrentMemberDefinition as MemberBase; @@ -213,11 +244,23 @@ namespace Mono.CSharp dynamic_site_container.DefineType (); dynamic_site_container.ResolveTypeParameters (); dynamic_site_container.Define (); + + var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes); + var inflated = dynamic_site_container.CurrentType.InflateMember (inflator); + CurrentType.MemberCache.AddMember (inflated); } return dynamic_site_container; } + public Label CreateReturnLabel () + { + if (!return_label.HasValue) + return_label = DefineLabel (); + + return return_label.Value; + } + public LocalBuilder DeclareLocal (TypeSpec type, bool pinned) { if (IsAnonymousStoreyMutateRequired) @@ -231,6 +274,17 @@ namespace Mono.CSharp return ig.DefineLabel (); } + // + // Creates temporary field in current async storey + // + public FieldExpr GetTemporaryField (TypeSpec type) + { + var f = AsyncTaskStorey.AddCapturedLocalVariable (type); + var fexpr = new FieldExpr (f, Location.Null); + fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null); + return fexpr; + } + public void MarkLabel (Label label) { ig.MarkLabel (label); @@ -261,16 +315,6 @@ namespace Mono.CSharp ig.Emit (opcode, arg); } - public void Emit (OpCode opcode, int arg) - { - ig.Emit (opcode, arg); - } - - public void Emit (OpCode opcode, byte arg) - { - ig.Emit (opcode, arg); - } - public void Emit (OpCode opcode, Label label) { ig.Emit (opcode, label); @@ -323,7 +367,11 @@ namespace Mono.CSharp public void EmitArrayNew (ArrayContainer ac) { if (ac.Rank == 1) { - Emit (OpCodes.Newarr, ac.Element); + var type = IsAnonymousStoreyMutateRequired ? + CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) : + ac.Element; + + ig.Emit (OpCodes.Newarr, type.GetMetaInfo ()); } else { if (IsAnonymousStoreyMutateRequired) ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator); @@ -334,16 +382,17 @@ namespace Mono.CSharp public void EmitArrayAddress (ArrayContainer ac) { - if (ac.Element.IsGenericParameter) - ig.Emit (OpCodes.Readonly); - if (ac.Rank > 1) { if (IsAnonymousStoreyMutateRequired) ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator); ig.Emit (OpCodes.Call, ac.GetAddressMethod ()); } else { - Emit (OpCodes.Ldelema, ac.Element); + var type = IsAnonymousStoreyMutateRequired ? + CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) : + ac.Element; + + ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ()); } } @@ -360,55 +409,69 @@ namespace Mono.CSharp return; } + var type = ac.Element; if (type.Kind == MemberKind.Enum) type = EnumSpec.GetUnderlyingType (type); - switch (type.BuildinType) { - case BuildinTypeSpec.Type.Byte: - case BuildinTypeSpec.Type.Bool: - Emit (OpCodes.Ldelem_U1); - return; - case BuildinTypeSpec.Type.SByte: - Emit (OpCodes.Ldelem_I1); - return; - case BuildinTypeSpec.Type.Short: - Emit (OpCodes.Ldelem_I2); - return; - case BuildinTypeSpec.Type.UShort: - case BuildinTypeSpec.Type.Char: - Emit (OpCodes.Ldelem_U2); - return; - case BuildinTypeSpec.Type.Int: - Emit (OpCodes.Ldelem_I4); - return; - case BuildinTypeSpec.Type.UInt: - Emit (OpCodes.Ldelem_U4); - return; - case BuildinTypeSpec.Type.ULong: - case BuildinTypeSpec.Type.Long: - Emit (OpCodes.Ldelem_I8); - return; - case BuildinTypeSpec.Type.Float: - Emit (OpCodes.Ldelem_R4); - return; - case BuildinTypeSpec.Type.Double: - Emit (OpCodes.Ldelem_R8); - return; - case BuildinTypeSpec.Type.IntPtr: - Emit (OpCodes.Ldelem_I); - return; + switch (type.BuiltinType) { + case BuiltinTypeSpec.Type.Byte: + case BuiltinTypeSpec.Type.Bool: + ig.Emit (OpCodes.Ldelem_U1); + break; + case BuiltinTypeSpec.Type.SByte: + ig.Emit (OpCodes.Ldelem_I1); + break; + case BuiltinTypeSpec.Type.Short: + ig.Emit (OpCodes.Ldelem_I2); + break; + case BuiltinTypeSpec.Type.UShort: + case BuiltinTypeSpec.Type.Char: + ig.Emit (OpCodes.Ldelem_U2); + break; + case BuiltinTypeSpec.Type.Int: + ig.Emit (OpCodes.Ldelem_I4); + break; + case BuiltinTypeSpec.Type.UInt: + ig.Emit (OpCodes.Ldelem_U4); + break; + case BuiltinTypeSpec.Type.ULong: + case BuiltinTypeSpec.Type.Long: + ig.Emit (OpCodes.Ldelem_I8); + break; + case BuiltinTypeSpec.Type.Float: + ig.Emit (OpCodes.Ldelem_R4); + break; + case BuiltinTypeSpec.Type.Double: + ig.Emit (OpCodes.Ldelem_R8); + break; + case BuiltinTypeSpec.Type.IntPtr: + ig.Emit (OpCodes.Ldelem_I); + break; + default: + switch (type.Kind) { + case MemberKind.Struct: + if (IsAnonymousStoreyMutateRequired) + type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type); + + ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ()); + ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ()); + break; + case MemberKind.TypeParameter: + if (IsAnonymousStoreyMutateRequired) + type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type); + + ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ()); + break; + case MemberKind.PointerType: + ig.Emit (OpCodes.Ldelem_I); + break; + default: + ig.Emit (OpCodes.Ldelem_Ref); + break; + } + break; } - - if (TypeManager.IsStruct (type)) { - Emit (OpCodes.Ldelema, type); - Emit (OpCodes.Ldobj, type); - } else if (type.IsGenericParameter) { - Emit (OpCodes.Ldelem, type); - } else if (type.IsPointer) - Emit (OpCodes.Ldelem_I); - else - Emit (OpCodes.Ldelem_Ref); } // @@ -429,44 +492,55 @@ namespace Mono.CSharp if (type.Kind == MemberKind.Enum) type = EnumSpec.GetUnderlyingType (type); - switch (type.BuildinType) { - case BuildinTypeSpec.Type.Byte: - case BuildinTypeSpec.Type.SByte: - case BuildinTypeSpec.Type.Bool: + switch (type.BuiltinType) { + case BuiltinTypeSpec.Type.Byte: + case BuiltinTypeSpec.Type.SByte: + case BuiltinTypeSpec.Type.Bool: Emit (OpCodes.Stelem_I1); return; - case BuildinTypeSpec.Type.Short: - case BuildinTypeSpec.Type.UShort: - case BuildinTypeSpec.Type.Char: + case BuiltinTypeSpec.Type.Short: + case BuiltinTypeSpec.Type.UShort: + case BuiltinTypeSpec.Type.Char: Emit (OpCodes.Stelem_I2); return; - case BuildinTypeSpec.Type.Int: - case BuildinTypeSpec.Type.UInt: + case BuiltinTypeSpec.Type.Int: + case BuiltinTypeSpec.Type.UInt: Emit (OpCodes.Stelem_I4); return; - case BuildinTypeSpec.Type.Long: - case BuildinTypeSpec.Type.ULong: + case BuiltinTypeSpec.Type.Long: + case BuiltinTypeSpec.Type.ULong: Emit (OpCodes.Stelem_I8); return; - case BuildinTypeSpec.Type.Float: + case BuiltinTypeSpec.Type.Float: Emit (OpCodes.Stelem_R4); return; - case BuildinTypeSpec.Type.Double: + case BuiltinTypeSpec.Type.Double: Emit (OpCodes.Stelem_R8); return; } - if (TypeManager.IsStruct (type)) + switch (type.Kind) { + case MemberKind.Struct: Emit (OpCodes.Stobj, type); - else if (type.IsGenericParameter) + break; + case MemberKind.TypeParameter: Emit (OpCodes.Stelem, type); - else if (type.IsPointer) + break; + case MemberKind.PointerType: Emit (OpCodes.Stelem_I); - else + break; + default: Emit (OpCodes.Stelem_Ref); + break; + } } public void EmitInt (int i) + { + EmitIntConstant (i); + } + + void EmitIntConstant (int i) { switch (i) { case -1: @@ -521,18 +595,14 @@ namespace Mono.CSharp public void EmitLong (long l) { if (l >= int.MinValue && l <= int.MaxValue) { - EmitInt (unchecked ((int) l)); + EmitIntConstant (unchecked ((int) l)); ig.Emit (OpCodes.Conv_I8); - return; - } - - if (l >= 0 && l <= uint.MaxValue) { - EmitInt (unchecked ((int) l)); + } else if (l >= 0 && l <= uint.MaxValue) { + EmitIntConstant (unchecked ((int) l)); ig.Emit (OpCodes.Conv_U8); - return; + } else { + ig.Emit (OpCodes.Ldc_I8, l); } - - ig.Emit (OpCodes.Ldc_I8, l); } // @@ -543,48 +613,104 @@ namespace Mono.CSharp if (type.Kind == MemberKind.Enum) type = EnumSpec.GetUnderlyingType (type); - switch (type.BuildinType) { - case BuildinTypeSpec.Type.Int: + switch (type.BuiltinType) { + case BuiltinTypeSpec.Type.Int: ig.Emit (OpCodes.Ldind_I4); - return; - case BuildinTypeSpec.Type.UInt: + break; + case BuiltinTypeSpec.Type.UInt: ig.Emit (OpCodes.Ldind_U4); - return; - case BuildinTypeSpec.Type.Short: + break; + case BuiltinTypeSpec.Type.Short: ig.Emit (OpCodes.Ldind_I2); - return; - case BuildinTypeSpec.Type.UShort: - case BuildinTypeSpec.Type.Char: + break; + case BuiltinTypeSpec.Type.UShort: + case BuiltinTypeSpec.Type.Char: ig.Emit (OpCodes.Ldind_U2); - return; - case BuildinTypeSpec.Type.Byte: + break; + case BuiltinTypeSpec.Type.Byte: ig.Emit (OpCodes.Ldind_U1); - return; - case BuildinTypeSpec.Type.SByte: - case BuildinTypeSpec.Type.Bool: + break; + case BuiltinTypeSpec.Type.SByte: + case BuiltinTypeSpec.Type.Bool: ig.Emit (OpCodes.Ldind_I1); - return; - case BuildinTypeSpec.Type.ULong: - case BuildinTypeSpec.Type.Long: + break; + case BuiltinTypeSpec.Type.ULong: + case BuiltinTypeSpec.Type.Long: ig.Emit (OpCodes.Ldind_I8); - return; - case BuildinTypeSpec.Type.Float: + break; + case BuiltinTypeSpec.Type.Float: ig.Emit (OpCodes.Ldind_R4); - return; - case BuildinTypeSpec.Type.Double: + break; + case BuiltinTypeSpec.Type.Double: ig.Emit (OpCodes.Ldind_R8); - return; - case BuildinTypeSpec.Type.IntPtr: + break; + case BuiltinTypeSpec.Type.IntPtr: ig.Emit (OpCodes.Ldind_I); - return; + break; + default: + switch (type.Kind) { + case MemberKind.Struct: + case MemberKind.TypeParameter: + if (IsAnonymousStoreyMutateRequired) + type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type); + + ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ()); + break; + case MemberKind.PointerType: + ig.Emit (OpCodes.Ldind_I); + break; + default: + ig.Emit (OpCodes.Ldind_Ref); + break; + } + break; } + } - if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type)) - Emit (OpCodes.Ldobj, type); - else if (type.IsPointer) - ig.Emit (OpCodes.Ldind_I); + public void EmitNull () + { + ig.Emit (OpCodes.Ldnull); + } + + public void EmitArgumentAddress (int pos) + { + if (!IsStatic) + ++pos; + + if (pos > byte.MaxValue) + ig.Emit (OpCodes.Ldarga, pos); + else + ig.Emit (OpCodes.Ldarga_S, (byte) pos); + } + + public void EmitArgumentLoad (int pos) + { + if (!IsStatic) + ++pos; + + switch (pos) { + case 0: ig.Emit (OpCodes.Ldarg_0); break; + case 1: ig.Emit (OpCodes.Ldarg_1); break; + case 2: ig.Emit (OpCodes.Ldarg_2); break; + case 3: ig.Emit (OpCodes.Ldarg_3); break; + default: + if (pos > byte.MaxValue) + ig.Emit (OpCodes.Ldarg, pos); + else + ig.Emit (OpCodes.Ldarg_S, (byte) pos); + break; + } + } + + public void EmitArgumentStore (int pos) + { + if (!IsStatic) + ++pos; + + if (pos > byte.MaxValue) + ig.Emit (OpCodes.Starg, pos); else - ig.Emit (OpCodes.Ldind_Ref); + ig.Emit (OpCodes.Starg_S, (byte) pos); } // @@ -595,40 +721,53 @@ namespace Mono.CSharp if (type.IsEnum) type = EnumSpec.GetUnderlyingType (type); - switch (type.BuildinType) { - case BuildinTypeSpec.Type.Int: - case BuildinTypeSpec.Type.UInt: + switch (type.BuiltinType) { + case BuiltinTypeSpec.Type.Int: + case BuiltinTypeSpec.Type.UInt: ig.Emit (OpCodes.Stind_I4); return; - case BuildinTypeSpec.Type.Long: - case BuildinTypeSpec.Type.ULong: + case BuiltinTypeSpec.Type.Long: + case BuiltinTypeSpec.Type.ULong: ig.Emit (OpCodes.Stind_I8); return; - case BuildinTypeSpec.Type.Char: - case BuildinTypeSpec.Type.Short: - case BuildinTypeSpec.Type.UShort: + case BuiltinTypeSpec.Type.Char: + case BuiltinTypeSpec.Type.Short: + case BuiltinTypeSpec.Type.UShort: ig.Emit (OpCodes.Stind_I2); return; - case BuildinTypeSpec.Type.Float: + case BuiltinTypeSpec.Type.Float: ig.Emit (OpCodes.Stind_R4); return; - case BuildinTypeSpec.Type.Double: + case BuiltinTypeSpec.Type.Double: ig.Emit (OpCodes.Stind_R8); return; - case BuildinTypeSpec.Type.Byte: - case BuildinTypeSpec.Type.SByte: - case BuildinTypeSpec.Type.Bool: + case BuiltinTypeSpec.Type.Byte: + case BuiltinTypeSpec.Type.SByte: + case BuiltinTypeSpec.Type.Bool: ig.Emit (OpCodes.Stind_I1); return; - case BuildinTypeSpec.Type.IntPtr: + case BuiltinTypeSpec.Type.IntPtr: ig.Emit (OpCodes.Stind_I); return; } - if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type)) - Emit (OpCodes.Stobj, type); - else + switch (type.Kind) { + case MemberKind.Struct: + case MemberKind.TypeParameter: + if (IsAnonymousStoreyMutateRequired) + type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type); + + ig.Emit (OpCodes.Stobj, type.GetMetaInfo ()); + break; + default: ig.Emit (OpCodes.Stind_Ref); + break; + } + } + + public void EmitThis () + { + ig.Emit (OpCodes.Ldarg_0); } /// @@ -691,13 +830,203 @@ namespace Mono.CSharp { if (return_value == null){ return_value = DeclareLocal (return_type, false); - if (!HasReturnLabel){ - ReturnLabel = DefineLabel (); - HasReturnLabel = true; - } } return return_value; } } + + struct CallEmitter + { + public Expression InstanceExpression; + + // + // When set leaves an extra copy of all arguments on the stack + // + public bool DuplicateArguments; + + // + // Does not emit InstanceExpression load when InstanceExpressionOnStack + // is set. Used by compound assignments. + // + public bool InstanceExpressionOnStack; + + // + // Any of arguments contains await expression + // + public bool HasAwaitArguments; + + // + // When dealing with await arguments the original arguments are converted + // into a new set with hoisted stack results + // + public Arguments EmittedArguments; + + public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc) + { + // Speed up the check by not doing it on not allowed targets + if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.Module.Compiler, loc)) + return; + + EmitPredefined (ec, method, Arguments); + } + + public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments) + { + Expression instance_copy = null; + + if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) { + HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait (); + if (HasAwaitArguments && InstanceExpressionOnStack) { + throw new NotSupportedException (); + } + } + + OpCode call_op; + LocalTemporary lt = null; + + if (method.IsStatic) { + call_op = OpCodes.Call; + } else { + if (IsVirtualCallRequired (InstanceExpression, method)) { + call_op = OpCodes.Callvirt; + } else { + call_op = OpCodes.Call; + } + + if (HasAwaitArguments) { + instance_copy = InstanceExpression.EmitToField (ec); + if (Arguments == null) + EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op); + } else if (!InstanceExpressionOnStack) { + var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op); + + if (DuplicateArguments) { + ec.Emit (OpCodes.Dup); + if (Arguments != null && Arguments.Count != 0) { + lt = new LocalTemporary (instance_on_stack_type); + lt.Store (ec); + instance_copy = lt; + } + } + } + } + + if (Arguments != null && !InstanceExpressionOnStack) { + EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments); + if (EmittedArguments != null) { + if (instance_copy != null) { + EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op); + + if (lt != null) + lt.Release (ec); + } + + EmittedArguments.Emit (ec); + } + } + + if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) { + ec.Emit (OpCodes.Constrained, InstanceExpression.Type); + } + + // + // Set instance expression to actual result expression. When it contains await it can be + // picked up by caller + // + InstanceExpression = instance_copy; + + if (method.Parameters.HasArglist) { + var varargs_types = GetVarargsTypes (method, Arguments); + ec.Emit (call_op, method, varargs_types); + return; + } + + // + // If you have: + // this.DoFoo (); + // and DoFoo is not virtual, you can omit the callvirt, + // because you don't need the null checking behavior. + // + ec.Emit (call_op, method); + } + + static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode) + { + var instance_type = instance.Type; + + // + // Push the instance expression + // + if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) || + instance_type.IsGenericParameter || declaringType.IsNullableType) { + // + // If the expression implements IMemoryLocation, then + // we can optimize and use AddressOf on the + // return. + // + // If not we have to use some temporary storage for + // it. + var iml = instance as IMemoryLocation; + if (iml != null) { + iml.AddressOf (ec, AddressOp.Load); + } else { + LocalTemporary temp = new LocalTemporary (instance_type); + instance.Emit (ec); + temp.Store (ec); + temp.AddressOf (ec, AddressOp.Load); + temp.Release (ec); + } + + return ReferenceContainer.MakeType (ec.Module, instance_type); + } + + if (instance_type.IsEnum || instance_type.IsStruct) { + instance.Emit (ec); + ec.Emit (OpCodes.Box, instance_type); + return ec.BuiltinTypes.Object; + } + + instance.Emit (ec); + return instance_type; + } + + static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments) + { + AParametersCollection pd = method.Parameters; + + Argument a = arguments[pd.Count - 1]; + Arglist list = (Arglist) a.Expr; + + return list.ArgumentTypes; + } + + // + // Used to decide whether call or callvirt is needed + // + static bool IsVirtualCallRequired (Expression instance, MethodSpec method) + { + // + // There are 2 scenarious where we emit callvirt + // + // Case 1: A method is virtual and it's not used to call base + // Case 2: A method instance expression can be null. In this casen callvirt ensures + // correct NRE exception when the method is called + // + var decl_type = method.DeclaringType; + if (decl_type.IsStruct || decl_type.IsEnum) + return false; + + if (instance is BaseThis) + return false; + + // + // It's non-virtual and will never be null + // + if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation)) + return false; + + return true; + } + } }