2 // codegen.cs: The code generator
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004 Novell, Inc.
10 // Copyright 2011 Xamarin Inc
14 using System.Collections.Generic;
15 using Mono.CompilerServices.SymbolWriter;
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
30 /// An Emit Context is created for each body of code (from methods,
31 /// properties bodies, indexer bodies or constructor bodies)
33 public class EmitContext : BuilderContext
35 // TODO: Has to be private
36 public readonly ILGenerator ig;
39 /// The value that is allowed to be returned or NULL if there is no
42 readonly TypeSpec return_type;
45 /// Keeps track of the Type to LocalBuilder temporary storage created
46 /// to store structures (used to compute the address of the structure
47 /// value on structure method invocations)
49 Dictionary<TypeSpec, object> temporary_storage;
52 /// The location where we store the return value.
54 public LocalBuilder return_value;
58 /// Current loop begin and end labels.
60 public Label LoopBegin, LoopEnd;
63 /// Default target in a switch statement. Only valid if
66 public Label DefaultTarget;
69 /// If this is non-null, points to the current switch statement
74 /// Whether we are inside an anonymous method.
76 public AnonymousExpression CurrentAnonymousMethod;
78 readonly IMemberContext member_context;
80 readonly SourceMethodBuilder methodSymbols;
82 DynamicSiteClass dynamic_site_container;
86 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type, SourceMethodBuilder methodSymbols)
88 this.member_context = rc;
90 this.return_type = return_type;
92 if (rc.Module.Compiler.Settings.Checked)
93 flags |= Options.CheckedScope;
95 if (methodSymbols != null) {
96 this.methodSymbols = methodSymbols;
97 if (!rc.Module.Compiler.Settings.Optimize)
98 flags |= Options.AccurateDebugInfo;
100 flags |= Options.OmitDebugInfo;
104 ig.__CleverExceptionBlockAssistance ();
110 internal AsyncTaskStorey AsyncTaskStorey {
112 return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
116 public BuiltinTypes BuiltinTypes {
118 return MemberContext.Module.Compiler.BuiltinTypes;
122 public TypeSpec CurrentType {
123 get { return member_context.CurrentType; }
126 public TypeParameters CurrentTypeParameters {
127 get { return member_context.CurrentTypeParameters; }
130 public MemberCore CurrentTypeDefinition {
131 get { return member_context.CurrentMemberDefinition; }
134 public bool EmitAccurateDebugInfo {
136 return (flags & Options.AccurateDebugInfo) != 0;
140 public bool HasReturnLabel {
142 return return_label.HasValue;
146 public bool IsStatic {
147 get { return member_context.IsStatic; }
150 public bool IsAnonymousStoreyMutateRequired {
152 return CurrentAnonymousMethod != null &&
153 CurrentAnonymousMethod.Storey != null &&
154 CurrentAnonymousMethod.Storey.Mutator != null;
158 public IMemberContext MemberContext {
160 return member_context;
164 public ModuleContainer Module {
166 return member_context.Module;
170 // Has to be used for specific emitter errors only any
171 // possible resolver errors have to be reported during Resolve
172 public Report Report {
174 return member_context.Module.Compiler.Report;
178 public TypeSpec ReturnType {
185 // The label where we have to jump before leaving the context
187 public Label ReturnLabel {
189 return return_label.Value;
195 public void AssertEmptyStack ()
198 if (ig.__StackHeight != 0)
199 throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
200 member_context.GetSignatureForError ());
205 /// This is called immediately before emitting an IL opcode to tell the symbol
206 /// writer to which source line this opcode belongs.
208 public bool Mark (Location loc)
210 if ((flags & Options.OmitDebugInfo) != 0)
213 if (loc.IsNull || methodSymbols == null)
216 var sf = loc.SourceFile;
217 if (sf.IsHiddenLocation (loc))
221 methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
226 public void DefineLocalVariable (string name, LocalBuilder builder)
228 if ((flags & Options.OmitDebugInfo) != 0)
231 methodSymbols.AddLocal (builder.LocalIndex, name);
234 public void BeginCatchBlock (TypeSpec type)
236 ig.BeginCatchBlock (type.GetMetaInfo ());
239 public void BeginExceptionBlock ()
241 ig.BeginExceptionBlock ();
244 public void BeginFinallyBlock ()
246 ig.BeginFinallyBlock ();
249 public void BeginScope ()
251 if ((flags & Options.OmitDebugInfo) != 0)
255 methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset);
259 public void EndExceptionBlock ()
261 ig.EndExceptionBlock ();
264 public void EndScope ()
266 if ((flags & Options.OmitDebugInfo) != 0)
270 methodSymbols.EndBlock (ig.ILOffset);
275 // Creates a nested container in this context for all dynamic compiler generated stuff
277 internal DynamicSiteClass CreateDynamicSite ()
279 if (dynamic_site_container == null) {
280 var mc = member_context.CurrentMemberDefinition as MemberBase;
281 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, member_context.CurrentTypeParameters);
283 CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
284 dynamic_site_container.CreateContainer ();
285 dynamic_site_container.DefineContainer ();
286 dynamic_site_container.Define ();
288 var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
289 var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
290 CurrentType.MemberCache.AddMember (inflated);
293 return dynamic_site_container;
296 public Label CreateReturnLabel ()
298 if (!return_label.HasValue)
299 return_label = DefineLabel ();
301 return return_label.Value;
304 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
306 if (IsAnonymousStoreyMutateRequired)
307 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
309 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
312 public Label DefineLabel ()
314 return ig.DefineLabel ();
318 // Creates temporary field in current async storey
320 public FieldExpr GetTemporaryField (TypeSpec type)
322 var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
323 var fexpr = new StackFieldExpr (f);
324 fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
328 public void MarkLabel (Label label)
330 ig.MarkLabel (label);
333 public void Emit (OpCode opcode)
338 public void Emit (OpCode opcode, LocalBuilder local)
340 ig.Emit (opcode, local);
343 public void Emit (OpCode opcode, string arg)
345 ig.Emit (opcode, arg);
348 public void Emit (OpCode opcode, double arg)
350 ig.Emit (opcode, arg);
353 public void Emit (OpCode opcode, float arg)
355 ig.Emit (opcode, arg);
358 public void Emit (OpCode opcode, Label label)
360 ig.Emit (opcode, label);
363 public void Emit (OpCode opcode, Label[] labels)
365 ig.Emit (opcode, labels);
368 public void Emit (OpCode opcode, TypeSpec type)
370 if (IsAnonymousStoreyMutateRequired)
371 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
373 ig.Emit (opcode, type.GetMetaInfo ());
376 public void Emit (OpCode opcode, FieldSpec field)
378 if (IsAnonymousStoreyMutateRequired)
379 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
381 ig.Emit (opcode, field.GetMetaInfo ());
384 public void Emit (OpCode opcode, MethodSpec method)
386 if (IsAnonymousStoreyMutateRequired)
387 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
389 if (method.IsConstructor)
390 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
392 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
395 // TODO: REMOVE breaks mutator
396 public void Emit (OpCode opcode, MethodInfo method)
398 ig.Emit (opcode, method);
401 public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
403 // TODO MemberCache: This should mutate too
404 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
407 public void EmitArrayNew (ArrayContainer ac)
410 var type = IsAnonymousStoreyMutateRequired ?
411 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
414 ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
416 if (IsAnonymousStoreyMutateRequired)
417 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
419 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
423 public void EmitArrayAddress (ArrayContainer ac)
426 if (IsAnonymousStoreyMutateRequired)
427 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
429 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
431 var type = IsAnonymousStoreyMutateRequired ?
432 CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
435 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
440 // Emits the right opcode to load from an array
442 public void EmitArrayLoad (ArrayContainer ac)
445 if (IsAnonymousStoreyMutateRequired)
446 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
448 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
453 var type = ac.Element;
454 if (type.Kind == MemberKind.Enum)
455 type = EnumSpec.GetUnderlyingType (type);
457 switch (type.BuiltinType) {
458 case BuiltinTypeSpec.Type.Byte:
459 case BuiltinTypeSpec.Type.Bool:
460 ig.Emit (OpCodes.Ldelem_U1);
462 case BuiltinTypeSpec.Type.SByte:
463 ig.Emit (OpCodes.Ldelem_I1);
465 case BuiltinTypeSpec.Type.Short:
466 ig.Emit (OpCodes.Ldelem_I2);
468 case BuiltinTypeSpec.Type.UShort:
469 case BuiltinTypeSpec.Type.Char:
470 ig.Emit (OpCodes.Ldelem_U2);
472 case BuiltinTypeSpec.Type.Int:
473 ig.Emit (OpCodes.Ldelem_I4);
475 case BuiltinTypeSpec.Type.UInt:
476 ig.Emit (OpCodes.Ldelem_U4);
478 case BuiltinTypeSpec.Type.ULong:
479 case BuiltinTypeSpec.Type.Long:
480 ig.Emit (OpCodes.Ldelem_I8);
482 case BuiltinTypeSpec.Type.Float:
483 ig.Emit (OpCodes.Ldelem_R4);
485 case BuiltinTypeSpec.Type.Double:
486 ig.Emit (OpCodes.Ldelem_R8);
488 case BuiltinTypeSpec.Type.IntPtr:
489 ig.Emit (OpCodes.Ldelem_I);
493 case MemberKind.Struct:
494 if (IsAnonymousStoreyMutateRequired)
495 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
497 ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
498 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
500 case MemberKind.TypeParameter:
501 if (IsAnonymousStoreyMutateRequired)
502 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
504 ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
506 case MemberKind.PointerType:
507 ig.Emit (OpCodes.Ldelem_I);
510 ig.Emit (OpCodes.Ldelem_Ref);
518 // Emits the right opcode to store to an array
520 public void EmitArrayStore (ArrayContainer ac)
523 if (IsAnonymousStoreyMutateRequired)
524 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
526 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
530 var type = ac.Element;
532 if (type.Kind == MemberKind.Enum)
533 type = EnumSpec.GetUnderlyingType (type);
535 switch (type.BuiltinType) {
536 case BuiltinTypeSpec.Type.Byte:
537 case BuiltinTypeSpec.Type.SByte:
538 case BuiltinTypeSpec.Type.Bool:
539 Emit (OpCodes.Stelem_I1);
541 case BuiltinTypeSpec.Type.Short:
542 case BuiltinTypeSpec.Type.UShort:
543 case BuiltinTypeSpec.Type.Char:
544 Emit (OpCodes.Stelem_I2);
546 case BuiltinTypeSpec.Type.Int:
547 case BuiltinTypeSpec.Type.UInt:
548 Emit (OpCodes.Stelem_I4);
550 case BuiltinTypeSpec.Type.Long:
551 case BuiltinTypeSpec.Type.ULong:
552 Emit (OpCodes.Stelem_I8);
554 case BuiltinTypeSpec.Type.Float:
555 Emit (OpCodes.Stelem_R4);
557 case BuiltinTypeSpec.Type.Double:
558 Emit (OpCodes.Stelem_R8);
563 case MemberKind.Struct:
564 Emit (OpCodes.Stobj, type);
566 case MemberKind.TypeParameter:
567 Emit (OpCodes.Stelem, type);
569 case MemberKind.PointerType:
570 Emit (OpCodes.Stelem_I);
573 Emit (OpCodes.Stelem_Ref);
578 public void EmitInt (int i)
583 void EmitIntConstant (int i)
587 ig.Emit (OpCodes.Ldc_I4_M1);
591 ig.Emit (OpCodes.Ldc_I4_0);
595 ig.Emit (OpCodes.Ldc_I4_1);
599 ig.Emit (OpCodes.Ldc_I4_2);
603 ig.Emit (OpCodes.Ldc_I4_3);
607 ig.Emit (OpCodes.Ldc_I4_4);
611 ig.Emit (OpCodes.Ldc_I4_5);
615 ig.Emit (OpCodes.Ldc_I4_6);
619 ig.Emit (OpCodes.Ldc_I4_7);
623 ig.Emit (OpCodes.Ldc_I4_8);
627 if (i >= -128 && i <= 127) {
628 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
630 ig.Emit (OpCodes.Ldc_I4, i);
635 public void EmitLong (long l)
637 if (l >= int.MinValue && l <= int.MaxValue) {
638 EmitIntConstant (unchecked ((int) l));
639 ig.Emit (OpCodes.Conv_I8);
640 } else if (l >= 0 && l <= uint.MaxValue) {
641 EmitIntConstant (unchecked ((int) l));
642 ig.Emit (OpCodes.Conv_U8);
644 ig.Emit (OpCodes.Ldc_I8, l);
649 // Load the object from the pointer.
651 public void EmitLoadFromPtr (TypeSpec type)
653 if (type.Kind == MemberKind.Enum)
654 type = EnumSpec.GetUnderlyingType (type);
656 switch (type.BuiltinType) {
657 case BuiltinTypeSpec.Type.Int:
658 ig.Emit (OpCodes.Ldind_I4);
660 case BuiltinTypeSpec.Type.UInt:
661 ig.Emit (OpCodes.Ldind_U4);
663 case BuiltinTypeSpec.Type.Short:
664 ig.Emit (OpCodes.Ldind_I2);
666 case BuiltinTypeSpec.Type.UShort:
667 case BuiltinTypeSpec.Type.Char:
668 ig.Emit (OpCodes.Ldind_U2);
670 case BuiltinTypeSpec.Type.Byte:
671 ig.Emit (OpCodes.Ldind_U1);
673 case BuiltinTypeSpec.Type.SByte:
674 case BuiltinTypeSpec.Type.Bool:
675 ig.Emit (OpCodes.Ldind_I1);
677 case BuiltinTypeSpec.Type.ULong:
678 case BuiltinTypeSpec.Type.Long:
679 ig.Emit (OpCodes.Ldind_I8);
681 case BuiltinTypeSpec.Type.Float:
682 ig.Emit (OpCodes.Ldind_R4);
684 case BuiltinTypeSpec.Type.Double:
685 ig.Emit (OpCodes.Ldind_R8);
687 case BuiltinTypeSpec.Type.IntPtr:
688 ig.Emit (OpCodes.Ldind_I);
692 case MemberKind.Struct:
693 case MemberKind.TypeParameter:
694 if (IsAnonymousStoreyMutateRequired)
695 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
697 ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
699 case MemberKind.PointerType:
700 ig.Emit (OpCodes.Ldind_I);
703 ig.Emit (OpCodes.Ldind_Ref);
710 public void EmitNull ()
712 ig.Emit (OpCodes.Ldnull);
715 public void EmitArgumentAddress (int pos)
720 if (pos > byte.MaxValue)
721 ig.Emit (OpCodes.Ldarga, pos);
723 ig.Emit (OpCodes.Ldarga_S, (byte) pos);
726 public void EmitArgumentLoad (int pos)
732 case 0: ig.Emit (OpCodes.Ldarg_0); break;
733 case 1: ig.Emit (OpCodes.Ldarg_1); break;
734 case 2: ig.Emit (OpCodes.Ldarg_2); break;
735 case 3: ig.Emit (OpCodes.Ldarg_3); break;
737 if (pos > byte.MaxValue)
738 ig.Emit (OpCodes.Ldarg, pos);
740 ig.Emit (OpCodes.Ldarg_S, (byte) pos);
745 public void EmitArgumentStore (int pos)
750 if (pos > byte.MaxValue)
751 ig.Emit (OpCodes.Starg, pos);
753 ig.Emit (OpCodes.Starg_S, (byte) pos);
757 // The stack contains the pointer and the value of type `type'
759 public void EmitStoreFromPtr (TypeSpec type)
762 type = EnumSpec.GetUnderlyingType (type);
764 switch (type.BuiltinType) {
765 case BuiltinTypeSpec.Type.Int:
766 case BuiltinTypeSpec.Type.UInt:
767 ig.Emit (OpCodes.Stind_I4);
769 case BuiltinTypeSpec.Type.Long:
770 case BuiltinTypeSpec.Type.ULong:
771 ig.Emit (OpCodes.Stind_I8);
773 case BuiltinTypeSpec.Type.Char:
774 case BuiltinTypeSpec.Type.Short:
775 case BuiltinTypeSpec.Type.UShort:
776 ig.Emit (OpCodes.Stind_I2);
778 case BuiltinTypeSpec.Type.Float:
779 ig.Emit (OpCodes.Stind_R4);
781 case BuiltinTypeSpec.Type.Double:
782 ig.Emit (OpCodes.Stind_R8);
784 case BuiltinTypeSpec.Type.Byte:
785 case BuiltinTypeSpec.Type.SByte:
786 case BuiltinTypeSpec.Type.Bool:
787 ig.Emit (OpCodes.Stind_I1);
789 case BuiltinTypeSpec.Type.IntPtr:
790 ig.Emit (OpCodes.Stind_I);
795 case MemberKind.Struct:
796 case MemberKind.TypeParameter:
797 if (IsAnonymousStoreyMutateRequired)
798 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
800 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
803 ig.Emit (OpCodes.Stind_Ref);
808 public void EmitThis ()
810 ig.Emit (OpCodes.Ldarg_0);
814 /// Returns a temporary storage for a variable of type t as
815 /// a local variable in the current body.
817 public LocalBuilder GetTemporaryLocal (TypeSpec t)
819 if (temporary_storage != null) {
821 if (temporary_storage.TryGetValue (t, out o)) {
822 if (o is Stack<LocalBuilder>) {
823 var s = (Stack<LocalBuilder>) o;
824 o = s.Count == 0 ? null : s.Pop ();
826 temporary_storage.Remove (t);
830 return (LocalBuilder) o;
832 return DeclareLocal (t, false);
835 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
837 if (temporary_storage == null) {
838 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
839 temporary_storage.Add (t, b);
844 if (!temporary_storage.TryGetValue (t, out o)) {
845 temporary_storage.Add (t, b);
848 var s = o as Stack<LocalBuilder>;
850 s = new Stack<LocalBuilder> ();
851 s.Push ((LocalBuilder)o);
852 temporary_storage [t] = s;
858 /// ReturnValue creates on demand the LocalBuilder for the
859 /// return value from the function. By default this is not
860 /// used. This is only required when returns are found inside
861 /// Try or Catch statements.
863 /// This method is typically invoked from the Emit phase, so
864 /// we allow the creation of a return label if it was not
865 /// requested during the resolution phase. Could be cleaned
866 /// up, but it would replicate a lot of logic in the Emit phase
867 /// of the code that uses it.
869 public LocalBuilder TemporaryReturn ()
871 if (return_value == null){
872 return_value = DeclareLocal (return_type, false);
881 public Expression InstanceExpression;
884 // When set leaves an extra copy of all arguments on the stack
886 public bool DuplicateArguments;
889 // Does not emit InstanceExpression load when InstanceExpressionOnStack
890 // is set. Used by compound assignments.
892 public bool InstanceExpressionOnStack;
895 // Any of arguments contains await expression
897 public bool HasAwaitArguments;
900 // When dealing with await arguments the original arguments are converted
901 // into a new set with hoisted stack results
903 public Arguments EmittedArguments;
905 public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
907 // Speed up the check by not doing it on not allowed targets
908 if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.MemberContext, loc))
911 EmitPredefined (ec, method, Arguments);
914 public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments)
916 Expression instance_copy = null;
918 if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
919 HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
920 if (HasAwaitArguments && InstanceExpressionOnStack) {
921 throw new NotSupportedException ();
926 LocalTemporary lt = null;
928 if (method.IsStatic) {
929 call_op = OpCodes.Call;
931 if (IsVirtualCallRequired (InstanceExpression, method)) {
932 call_op = OpCodes.Callvirt;
934 call_op = OpCodes.Call;
937 if (HasAwaitArguments) {
938 instance_copy = InstanceExpression.EmitToField (ec);
939 if (Arguments == null)
940 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
941 } else if (!InstanceExpressionOnStack) {
942 var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
944 if (DuplicateArguments) {
945 ec.Emit (OpCodes.Dup);
946 if (Arguments != null && Arguments.Count != 0) {
947 lt = new LocalTemporary (instance_on_stack_type);
955 if (Arguments != null && !InstanceExpressionOnStack) {
956 EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
957 if (EmittedArguments != null) {
958 if (instance_copy != null) {
959 EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
965 EmittedArguments.Emit (ec);
969 if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
970 ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
974 // Set instance expression to actual result expression. When it contains await it can be
975 // picked up by caller
977 InstanceExpression = instance_copy;
979 if (method.Parameters.HasArglist) {
980 var varargs_types = GetVarargsTypes (method, Arguments);
981 ec.Emit (call_op, method, varargs_types);
988 // and DoFoo is not virtual, you can omit the callvirt,
989 // because you don't need the null checking behavior.
991 ec.Emit (call_op, method);
994 static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
996 var instance_type = instance.Type;
999 // Push the instance expression
1001 if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType.IsStruct))) ||
1002 instance_type.IsGenericParameter || declaringType.IsNullableType) {
1004 // If the expression implements IMemoryLocation, then
1005 // we can optimize and use AddressOf on the
1008 // If not we have to use some temporary storage for
1010 var iml = instance as IMemoryLocation;
1012 iml.AddressOf (ec, AddressOp.Load);
1014 LocalTemporary temp = new LocalTemporary (instance_type);
1017 temp.AddressOf (ec, AddressOp.Load);
1020 return ReferenceContainer.MakeType (ec.Module, instance_type);
1023 if (instance_type.IsEnum || instance_type.IsStruct) {
1025 ec.Emit (OpCodes.Box, instance_type);
1026 return ec.BuiltinTypes.Object;
1030 return instance_type;
1033 static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
1035 AParametersCollection pd = method.Parameters;
1037 Argument a = arguments[pd.Count - 1];
1038 Arglist list = (Arglist) a.Expr;
1040 return list.ArgumentTypes;
1044 // Used to decide whether call or callvirt is needed
1046 static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
1049 // There are 2 scenarious where we emit callvirt
1051 // Case 1: A method is virtual and it's not used to call base
1052 // Case 2: A method instance expression can be null. In this casen callvirt ensures
1053 // correct NRE exception when the method is called
1055 var decl_type = method.DeclaringType;
1056 if (decl_type.IsStruct || decl_type.IsEnum)
1059 if (instance is BaseThis)
1063 // It's non-virtual and will never be null
1065 if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation))